From 92ed3bb49e460b11aa86c828083e36373ae039dd Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 3 Feb 2016 17:39:24 +0100 Subject: sd-boot: put hashed kernel command line in a PCR of the TPM The UEFI BIOS already hashes the contents of the loaded image, so the initrd and the command line of the binary are recorded. Because manually added LoadOptions are not taken into account, these should be recorded also. This patch logs and extends a TPM PCR register with the LoadOptions. This feature can be enabled with configure --enable-tpm The PCR register index can be specified with configure --with-tpm-pcrindex= --- src/boot/efi/boot.c | 13 +++ src/boot/efi/measure.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++++ src/boot/efi/measure.h | 21 ++++ src/boot/efi/stub.c | 13 +++ 4 files changed, 359 insertions(+) create mode 100644 src/boot/efi/measure.c create mode 100644 src/boot/efi/measure.h (limited to 'src') diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 893980071f..30c1ead1aa 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -22,6 +22,7 @@ #include "linux.h" #include "pefile.h" #include "util.h" +#include "measure.h" #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL @@ -1644,6 +1645,18 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con } loaded_image->LoadOptions = options; loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16); + +#ifdef SD_BOOT_LOG_TPM + /* Try to log any options to the TPM, escpecially to catch manually edited options */ + err = tpm_log_event(SD_TPM_PCR, + (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions, + loaded_image->LoadOptionsSize, loaded_image->LoadOptions); + if (EFI_ERROR(err)) { + Print(L"Unable to add image options measurement: %r", err); + uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); + return err; + } +#endif } efivar_set_time_usec(L"LoaderTimeExecUSec", 0); diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c new file mode 100644 index 0000000000..7c016387c1 --- /dev/null +++ b/src/boot/efi/measure.c @@ -0,0 +1,312 @@ +/* + * 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. + * + */ + +#ifdef SD_BOOT_LOG_TPM + +#include +#include +#include "measure.h" + +#define EFI_TCG_PROTOCOL_GUID { 0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd} } + +typedef struct _TCG_VERSION { + UINT8 Major; + UINT8 Minor; + UINT8 RevMajor; + UINT8 RevMinor; +} TCG_VERSION; + +typedef struct _TCG_BOOT_SERVICE_CAPABILITY { + UINT8 Size; + struct _TCG_VERSION StructureVersion; + struct _TCG_VERSION ProtocolSpecVersion; + UINT8 HashAlgorithmBitmap; + BOOLEAN TPMPresentFlag; + BOOLEAN TPMDeactivatedFlag; +} TCG_BOOT_SERVICE_CAPABILITY; + +typedef UINT32 TCG_ALGORITHM_ID; +#define TCG_ALG_SHA 0x00000004 // The SHA1 algorithm + +#define SHA1_DIGEST_SIZE 20 + +typedef struct _TCG_DIGEST { + UINT8 Digest[SHA1_DIGEST_SIZE]; +} TCG_DIGEST; + +#define EV_IPL 13 + +typedef struct _TCG_PCR_EVENT { + UINT32 PCRIndex; + UINT32 EventType; + struct _TCG_DIGEST digest; + UINT32 EventSize; + UINT8 Event[1]; +} TCG_PCR_EVENT; + +INTERFACE_DECL(_EFI_TCG); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_STATUS_CHECK) (IN struct _EFI_TCG * This, + OUT struct _TCG_BOOT_SERVICE_CAPABILITY * ProtocolCapability, + OUT UINT32 * TCGFeatureFlags, + OUT EFI_PHYSICAL_ADDRESS * EventLogLocation, + OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_ALL) (IN struct _EFI_TCG * This, + IN UINT8 * HashData, + IN UINT64 HashDataLen, + IN TCG_ALGORITHM_ID AlgorithmId, + IN OUT UINT64 * HashedDataLen, IN OUT UINT8 ** HashedDataResult); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_LOG_EVENT) (IN struct _EFI_TCG * This, + IN struct _TCG_PCR_EVENT * TCGLogData, + IN OUT UINT32 * EventNumber, IN UINT32 Flags); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_PASS_THROUGH_TO_TPM) (IN struct _EFI_TCG * This, + IN UINT32 TpmInputParameterBlockSize, + IN UINT8 * TpmInputParameterBlock, + IN UINT32 TpmOutputParameterBlockSize, + IN UINT8 * TpmOutputParameterBlock); + +typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_LOG_EXTEND_EVENT) (IN struct _EFI_TCG * This, + IN EFI_PHYSICAL_ADDRESS HashData, + IN UINT64 HashDataLen, + IN TCG_ALGORITHM_ID AlgorithmId, + IN struct _TCG_PCR_EVENT * TCGLogData, + IN OUT UINT32 * EventNumber, + OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry); + +typedef struct _EFI_TCG { + EFI_TCG_STATUS_CHECK StatusCheck; + EFI_TCG_HASH_ALL HashAll; + EFI_TCG_LOG_EVENT LogEvent; + EFI_TCG_PASS_THROUGH_TO_TPM PassThroughToTPM; + EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; +} EFI_TCG; + +#define EFI_TCG2_PROTOCOL_GUID {0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }} + +typedef struct tdEFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL; + +typedef struct tdEFI_TCG2_VERSION { + UINT8 Major; + UINT8 Minor; +} EFI_TCG2_VERSION; + +typedef UINT32 EFI_TCG2_EVENT_LOG_BITMAP; +typedef UINT32 EFI_TCG2_EVENT_LOG_FORMAT; +typedef UINT32 EFI_TCG2_EVENT_ALGORITHM_BITMAP; + +#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x00000001 +#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002 + +typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY { + UINT8 Size; + EFI_TCG2_VERSION StructureVersion; + EFI_TCG2_VERSION ProtocolVersion; + EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap; + EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs; + BOOLEAN TPMPresentFlag; + UINT16 MaxCommandSize; + UINT16 MaxResponseSize; + UINT32 ManufacturerID; + UINT32 NumberOfPCRBanks; + EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks; +} EFI_TCG2_BOOT_SERVICE_CAPABILITY; + +#define EFI_TCG2_EVENT_HEADER_VERSION 1 + +typedef struct { + UINT32 HeaderSize; + UINT16 HeaderVersion; + UINT32 PCRIndex; + UINT32 EventType; +} EFI_TCG2_EVENT_HEADER; + +typedef struct tdEFI_TCG2_EVENT { + UINT32 Size; + EFI_TCG2_EVENT_HEADER Header; + UINT8 Event[1]; +} EFI_TCG2_EVENT; + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This, + IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_EVENT_LOG) (IN EFI_TCG2_PROTOCOL * This, + IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, + OUT EFI_PHYSICAL_ADDRESS * EventLogLocation, + OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry, + OUT BOOLEAN * EventLogTruncated); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_HASH_LOG_EXTEND_EVENT) (IN EFI_TCG2_PROTOCOL * This, + IN UINT64 Flags, + IN EFI_PHYSICAL_ADDRESS DataToHash, + IN UINT64 DataToHashLen, IN EFI_TCG2_EVENT * EfiTcgEvent); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_SUBMIT_COMMAND) (IN EFI_TCG2_PROTOCOL * This, + IN UINT32 InputParameterBlockSize, + IN UINT8 * InputParameterBlock, + IN UINT32 OutputParameterBlockSize, IN UINT8 * OutputParameterBlock); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, OUT UINT32 * ActivePcrBanks); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, IN UINT32 ActivePcrBanks); + +typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, + OUT UINT32 * OperationPresent, OUT UINT32 * Response); + +typedef struct tdEFI_TCG2_PROTOCOL { + EFI_TCG2_GET_CAPABILITY GetCapability; + EFI_TCG2_GET_EVENT_LOG GetEventLog; + EFI_TCG2_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; + EFI_TCG2_SUBMIT_COMMAND SubmitCommand; + EFI_TCG2_GET_ACTIVE_PCR_BANKS GetActivePcrBanks; + EFI_TCG2_SET_ACTIVE_PCR_BANKS SetActivePcrBanks; + EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS GetResultOfSetActivePcrBanks; +} EFI_TCG2; + + +static EFI_STATUS tpm1_measure_to_pcr_and_event_log(const EFI_TCG *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, + UINTN buffer_size, const CHAR16 *description) { + EFI_STATUS status; + TCG_PCR_EVENT *tcg_event; + UINT32 event_number; + EFI_PHYSICAL_ADDRESS event_log_last; + UINTN desc_len; + + desc_len = (StrLen(description) + 1) * sizeof(CHAR16); + + tcg_event = AllocateZeroPool(desc_len + sizeof(TCG_PCR_EVENT)); + + if (tcg_event == NULL) + return EFI_OUT_OF_RESOURCES; + + tcg_event->EventSize = desc_len; + CopyMem((VOID *) & tcg_event->Event[0], (VOID *) description, desc_len); + + tcg_event->PCRIndex = pcrindex; + tcg_event->EventType = EV_IPL; + + event_number = 1; + status = uefi_call_wrapper(tcg->HashLogExtendEvent, 7, + tcg, buffer, buffer_size, TCG_ALG_SHA, tcg_event, &event_number, &event_log_last); + + if (EFI_ERROR(status)) + return status; + + uefi_call_wrapper(BS->FreePool, 1, tcg_event); + + return EFI_SUCCESS; +} + + +static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, + UINT64 buffer_size, const CHAR16 *description) { + EFI_STATUS status; + EFI_TCG2_EVENT *tcg_event; + UINTN desc_len; + + desc_len = StrLen(description) * sizeof(CHAR16); + + tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1); + + if (tcg_event == NULL) + return EFI_OUT_OF_RESOURCES; + + tcg_event->Size = sizeof(EFI_TCG2_EVENT) - sizeof(tcg_event->Event) + desc_len + 1; + tcg_event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); + tcg_event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + tcg_event->Header.PCRIndex = pcrindex; + tcg_event->Header.EventType = EV_IPL; + + CopyMem((VOID *) tcg_event->Event, (VOID *) description, desc_len); + + status = uefi_call_wrapper(tcg->HashLogExtendEvent, 5, tcg, 0, buffer, buffer_size, tcg_event); + + uefi_call_wrapper(BS->FreePool, 1, tcg_event); + + if (EFI_ERROR(status)) + return status; + + return EFI_SUCCESS; +} + +static EFI_TCG * tcg1_interface_check(void) { + EFI_GUID tpm_guid = EFI_TCG_PROTOCOL_GUID; + EFI_STATUS status; + EFI_TCG *tcg; + TCG_BOOT_SERVICE_CAPABILITY capability; + UINT32 features; + EFI_PHYSICAL_ADDRESS event_log_location; + EFI_PHYSICAL_ADDRESS event_log_last_entry; + + status = LibLocateProtocol(&tpm_guid, (void **) &tcg); + + if (EFI_ERROR(status)) + return NULL; + + capability.Size = (UINT8) sizeof(capability); + status = uefi_call_wrapper(tcg->StatusCheck, 5, tcg, &capability, &features, &event_log_location, &event_log_last_entry); + + if (EFI_ERROR(status)) + return NULL; + + if (capability.TPMDeactivatedFlag) + return NULL; + + if (!capability.TPMPresentFlag) + return NULL; + + return tcg; +} + +static EFI_TCG2 * tcg2_interface_check(void) { + EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID; + EFI_STATUS status; + EFI_TCG2 *tcg; + EFI_TCG2_BOOT_SERVICE_CAPABILITY capability; + + status = LibLocateProtocol(&tpm2_guid, (void **) &tcg); + + if (EFI_ERROR(status)) + return NULL; + + capability.Size = (UINT8) sizeof(capability); + status = uefi_call_wrapper(tcg->GetCapability, 2, tcg, &capability); + + if (EFI_ERROR(status)) + return NULL; + + if (!capability.TPMPresentFlag) + return NULL; + + return tcg; +} + +EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { + EFI_TCG *tpm1; + EFI_TCG2 *tpm2; + + tpm2 = tcg2_interface_check(); + if (tpm2) + return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description); + + tpm1 = tcg1_interface_check(); + if (tpm1) + return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description); + + /* No active TPM found, so don't return an error */ + return EFI_SUCCESS; +} + +#endif diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h new file mode 100644 index 0000000000..a2cfe817d0 --- /dev/null +++ b/src/boot/efi/measure.h @@ -0,0 +1,21 @@ +/* + * 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. + * + */ +#ifndef __SDBOOT_MEASURE_H +#define __SDBOOT_MEASURE_H + +#ifndef SD_TPM_PCR +#define SD_TPM_PCR 8 +#endif + +EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description); +#endif diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 9633bc1792..1e250f34f4 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -20,6 +20,7 @@ #include "pefile.h" #include "splash.h" #include "util.h" +#include "measure.h" /* magic string to find in the binary image */ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " VERSION " ####"; @@ -97,6 +98,18 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { for (i = 0; i < cmdline_len; i++) line[i] = options[i]; cmdline = line; + +#ifdef SD_BOOT_LOG_TPM + /* Try to log any options to the TPM, escpecially manually edited options */ + err = tpm_log_event(SD_TPM_PCR, + (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions, + loaded_image->LoadOptionsSize, loaded_image->LoadOptions); + if (EFI_ERROR(err)) { + Print(L"Unable to add image options measurement: %r", err); + uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); + return err; + } +#endif } /* export the device path this image is started from */ -- cgit v1.2.3-54-g00ecf From 9e4942ed5a82447f324fa46fbce839104d1ce0ea Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Thu, 11 Feb 2016 19:02:54 +0100 Subject: core: use correct enum from e903182e5b0daa941de47a9c08c824106cec7fe0 --- src/core/path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/path.c b/src/core/path.c index 460c1d3bf2..6ac9b8b90d 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -476,7 +476,7 @@ static void path_enter_running(Path *p) { trigger = UNIT_TRIGGER(UNIT(p)); if (!trigger) { log_unit_error(UNIT(p), "Unit to trigger vanished."); - path_enter_dead(p, TIMER_FAILURE_RESOURCES); + path_enter_dead(p, PATH_FAILURE_RESOURCES); return; } -- cgit v1.2.3-54-g00ecf From 75f32f047cc380bdb648faf3ee277f7dc3cdd007 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 1 Feb 2016 21:57:41 -0500 Subject: Add memcpy_safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISO/IEC 9899:1999 §7.21.1/2 says: Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4. In base64_append_width memcpy was called as memcpy(x, NULL, 0). GCC 4.9 started making use of this and assumes This worked fine under -O0, but does something strange under -O3. This patch fixes a bug in base64_append_width(), fixes a possible bug in journal_file_append_entry_internal(), and makes use of the new function to simplify the code in other places. --- src/basic/hexdecoct.c | 3 ++- src/basic/util.h | 10 ++++++++++ src/journal/journal-file.c | 6 +++--- src/libsystemd-network/dhcp-option.c | 7 +------ src/libsystemd-network/dhcp6-option.c | 3 +-- src/libsystemd-network/test-dhcp-option.c | 11 +++-------- src/libsystemd/sd-bus/bus-control.c | 3 +-- src/libsystemd/sd-bus/bus-message.c | 3 +-- src/libsystemd/sd-bus/bus-socket.c | 6 +++--- src/libsystemd/sd-resolve/sd-resolve.c | 5 ++--- src/nspawn/nspawn.c | 10 ++++------ src/resolve/resolved-dns-packet.c | 3 +-- 12 files changed, 32 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index f30e028f45..cbd97a1b69 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -27,6 +27,7 @@ #include "alloc-util.h" #include "hexdecoct.h" #include "macro.h" +#include "util.h" char octchar(int x) { return '0' + (x & 7); @@ -574,7 +575,7 @@ static int base64_append_width(char **prefix, int plen, if (!t) return -ENOMEM; - memcpy(t + plen, sep, slen); + memcpy_safe(t + plen, sep, slen); for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) { int act = MIN(width, avail); diff --git a/src/basic/util.h b/src/basic/util.h index 76a06822b7..b7bad76212 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -104,6 +104,16 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_ qsort(base, nmemb, size, compar); } +/** + * Normal memcpy requires src to be nonnull. We do nothing if n is 0. + */ +static inline void memcpy_safe(void *dst, const void *src, size_t n) { + if (n == 0) + return; + assert(src); + memcpy(dst, src, n); +} + int on_ac_power(void); #define memzero(x,l) (memset((x), 0, (l))) diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 2973176c8d..da8039712f 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -1110,8 +1110,8 @@ static int journal_file_append_data( } #endif - if (compression == 0 && size > 0) - memcpy(o->data.payload, data, size); + if (compression == 0) + memcpy_safe(o->data.payload, data, size); r = journal_file_link_data(f, o, p, hash); if (r < 0) @@ -1373,7 +1373,7 @@ static int journal_file_append_entry_internal( return r; o->entry.seqnum = htole64(journal_file_entry_seqnum(f, seqnum)); - memcpy(o->entry.items, items, n_items * sizeof(EntryItem)); + memcpy_safe(o->entry.items, items, n_items * sizeof(EntryItem)); o->entry.realtime = htole64(ts->realtime); o->entry.monotonic = htole64(ts->monotonic); o->entry.xor_hash = htole64(xor_hash); diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 9f0d96e57d..3ceb70f07e 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -56,12 +56,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, options[*offset] = code; options[*offset + 1] = optlen; - if (optlen) { - assert(optval); - - memcpy(&options[*offset + 2], optval, optlen); - } - + memcpy_safe(&options[*offset + 2], optval, optlen); *offset += optlen + 2; break; diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 6050851858..e858e14d97 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -73,8 +73,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, if (r < 0) return r; - if (optval) - memcpy(*buf, optval, optlen); + memcpy_safe(*buf, optval, optlen); *buf += optlen; *buflen -= optlen; diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index 7b80a5bd90..45f4e0b5f5 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -112,14 +112,9 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen, message = malloc0(len); assert_se(message); - if (options && optlen) - memcpy(&message->options, options, optlen); - - if (file && filelen <= 128) - memcpy(&message->file, file, filelen); - - if (sname && snamelen <= 64) - memcpy(&message->sname, sname, snamelen); + memcpy_safe(&message->options, options, optlen); + memcpy_safe(&message->file, file, filelen); + memcpy_safe(&message->sname, sname, snamelen); return message; } diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index ff628cfe72..00de2a95da 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1133,8 +1133,7 @@ static int add_name_change_match(sd_bus *bus, item->name_change.old_id.id = old_owner_id; item->name_change.new_id.id = new_owner_id; - if (name) - memcpy(item->name_change.name, name, l); + memcpy_safe(item->name_change.name, name, l); /* If the old name is unset or empty, then * this can match against added names */ diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index e939359338..6fd0001359 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -2633,8 +2633,7 @@ _public_ int sd_bus_message_append_array( if (r < 0) return r; - if (size > 0) - memcpy(p, ptr, size); + memcpy_safe(p, ptr, size); return 0; } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 1df571ac92..4f99719231 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -352,7 +352,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) { if (!p) return -ENOMEM; - memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); + memcpy_safe(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); memcpy(p + b->auth_iovec[0].iov_len, t, l); b->auth_iovec[0].iov_base = p; @@ -789,7 +789,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { n = m->n_iovec * sizeof(struct iovec); iov = alloca(n); - memcpy(iov, m->iovec, n); + memcpy_safe(iov, m->iovec, n); j = 0; iovec_advance(iov, &j, *idx); @@ -1000,7 +1000,7 @@ int bus_socket_read_message(sd_bus *bus) { return -ENOMEM; } - memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); bus->fds = f; bus->n_fds += n; } else diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index d6e6f396d4..c3489cb02f 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -219,9 +219,8 @@ static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *leng memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization)); memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen); - - if (ai->ai_canonname) - memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl); + memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, + ai->ai_canonname, cnl); *length += l; return (uint8_t*) p + l; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9dd4c051b2..1c010b3b84 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2580,12 +2580,10 @@ static int inner_child( /* Automatically search for the init system */ - m = 1 + strv_length(arg_parameters); - a = newa(char*, m + 1); - if (strv_isempty(arg_parameters)) - a[1] = NULL; - else - memcpy(a + 1, arg_parameters, m * sizeof(char*)); + m = strv_length(arg_parameters); + a = newa(char*, m + 2); + memcpy_safe(a + 1, arg_parameters, m * sizeof(char*)); + a[1 + m] = NULL; a[0] = (char*) "/usr/lib/systemd/systemd"; execve(a[0], a, env_use); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 5cbe20832f..abb9725b73 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -433,8 +433,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_ ((uint8_t*) d)[0] = (uint8_t) size; - if (size > 0) - memcpy(((uint8_t*) d) + 1, s, size); + memcpy_safe(((uint8_t*) d) + 1, s, size); return 0; } -- cgit v1.2.3-54-g00ecf From 91e023d896dd5ca49dd440276f2241570acffd96 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Jan 2016 18:24:27 -0500 Subject: Move initialize_libgcrypt to separate file It's annoying to have the exact same function in three places. It's stored in src/shared, but it's not added to the library to avoid the dependency on libgcrypt. --- Makefile.am | 8 ++++++-- src/journal/fsprg.c | 25 ++++++------------------ src/journal/journal-authenticate.c | 15 ++------------ src/resolve/resolved-dns-dnssec.c | 20 ++++--------------- src/shared/gcrypt-util.c | 40 ++++++++++++++++++++++++++++++++++++++ src/shared/gcrypt-util.h | 24 +++++++++++++++++++++++ 6 files changed, 82 insertions(+), 50 deletions(-) create mode 100644 src/shared/gcrypt-util.c create mode 100644 src/shared/gcrypt-util.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index db95b109ce..d2cf9360ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4274,7 +4274,9 @@ libsystemd_journal_internal_la_SOURCES += \ src/journal/journal-authenticate.c \ src/journal/journal-authenticate.h \ src/journal/fsprg.c \ - src/journal/fsprg.h + src/journal/fsprg.h \ + src/shared/gcrypt-util.c \ + src/shared/gcrypt-util.h libsystemd_journal_internal_la_LIBADD += \ $(GCRYPT_LIBS) @@ -5216,7 +5218,9 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-etc-hosts.h \ src/resolve/resolved-etc-hosts.c \ src/resolve/dns-type.c \ - src/resolve/dns-type.h + src/resolve/dns-type.h \ + src/shared/gcrypt-util.c \ + src/shared/gcrypt-util.h nodist_systemd_resolved_SOURCES = \ src/resolve/dns_type-from-name.h \ diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c index a9f564c249..12ae7449f9 100644 --- a/src/journal/fsprg.c +++ b/src/journal/fsprg.c @@ -32,6 +32,7 @@ #include #include "fsprg.h" +#include "gcrypt-util.h" #define ISVALID_SECPAR(secpar) (((secpar) % 16 == 0) && ((secpar) >= 16) && ((secpar) <= 16384)) #define VALIDATE_SECPAR(secpar) assert(ISVALID_SECPAR(secpar)); @@ -208,20 +209,6 @@ static void CRT_compose(gcry_mpi_t *x, const gcry_mpi_t xp, const gcry_mpi_t xq, gcry_mpi_release(u); } -static void initialize_libgcrypt(void) { - const char *p; - if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) - return; - - p = gcry_check_version("1.4.5"); - assert(p); - - /* Turn off "secmem". Clients which whish to make use of this - * feature should initialize the library manually */ - gcry_control(GCRYCTL_DISABLE_SECMEM); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); -} - /******************************************************************************/ size_t FSPRG_mskinbytes(unsigned _secpar) { @@ -261,7 +248,7 @@ void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigne VALIDATE_SECPAR(_secpar); secpar = _secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); if (!seed) { gcry_randomize(iseed, FSPRG_RECOMMENDED_SEEDLEN, GCRY_STRONG_RANDOM); @@ -297,7 +284,7 @@ void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seed gcry_mpi_t n, x; uint16_t secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(mpk + 0); n = mpi_import(mpk + 2, secpar / 8); @@ -316,7 +303,7 @@ void FSPRG_Evolve(void *state) { uint16_t secpar; uint64_t epoch; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(state + 0); n = mpi_import(state + 2 + 0 * secpar / 8, secpar / 8); @@ -343,7 +330,7 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, gcry_mpi_t p, q, n, x, xp, xq, kp, kq, xm; uint16_t secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(msk + 0); p = mpi_import(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8); @@ -382,7 +369,7 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx) { uint16_t secpar; - initialize_libgcrypt(); + initialize_libgcrypt(false); secpar = read_secpar(state + 0); det_randomize(key, keylen, state + 2, 2 * secpar / 8 + 8, idx); diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index aeec83da1e..45d7f4b340 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -24,6 +24,7 @@ #include "fd-util.h" #include "fsprg.h" +#include "gcrypt-util.h" #include "hexdecoct.h" #include "journal-authenticate.h" #include "journal-def.h" @@ -426,25 +427,13 @@ finish: return r; } -static void initialize_libgcrypt(void) { - const char *p; - - if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) - return; - - p = gcry_check_version("1.4.5"); - assert(p); - - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); -} - int journal_file_hmac_setup(JournalFile *f) { gcry_error_t e; if (!f->seal) return 0; - initialize_libgcrypt(); + initialize_libgcrypt(true); e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); if (e != 0) diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 21cf161494..f799379efd 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -25,6 +25,7 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "gcrypt-util.h" #include "hexdecoct.h" #include "resolved-dns-dnssec.h" #include "resolved-dns-packet.h" @@ -128,19 +129,6 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) { #ifdef HAVE_GCRYPT -static void initialize_libgcrypt(void) { - const char *p; - - if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) - return; - - p = gcry_check_version("1.4.5"); - assert(p); - - gcry_control(GCRYCTL_DISABLE_SECMEM); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); -} - static int rr_compare(const void *a, const void *b) { DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b; size_t m; @@ -739,7 +727,7 @@ int dnssec_verify_rrset( qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare); /* OK, the RRs are now in canonical order. Let's calculate the digest */ - initialize_libgcrypt(); + initialize_libgcrypt(false); hash_size = gcry_md_get_algo_dlen(md_algorithm); assert(hash_size > 0); @@ -1072,7 +1060,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag) return 0; - initialize_libgcrypt(); + initialize_libgcrypt(false); md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type); if (md_algorithm < 0) @@ -1191,7 +1179,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) { if (algorithm < 0) return algorithm; - initialize_libgcrypt(); + initialize_libgcrypt(false); hash_size = gcry_md_get_algo_dlen(algorithm); assert(hash_size > 0); diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c new file mode 100644 index 0000000000..3bbc161ef2 --- /dev/null +++ b/src/shared/gcrypt-util.c @@ -0,0 +1,40 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + 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 . +***/ + +#include + +#include "hexdecoct.h" +#include "gcrypt-util.h" + +void initialize_libgcrypt(bool secmem) { + const char *p; + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) + return; + + p = gcry_check_version("1.4.5"); + assert(p); + + /* Turn off "secmem". Clients which whish to make use of this + * feature should initialize the library manually */ + if (!secmem) + gcry_control(GCRYCTL_DISABLE_SECMEM); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h new file mode 100644 index 0000000000..42ce3fd121 --- /dev/null +++ b/src/shared/gcrypt-util.h @@ -0,0 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +void initialize_libgcrypt(bool secmem); -- cgit v1.2.3-54-g00ecf From 4ac2ca1bdb8ff0e862927c3e1162c3686449c50a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Jan 2016 18:24:27 -0500 Subject: systemd-resolve: allow easy querying of openpgp keys $ systemd-resolve --openpgp zbyszek@fedoraproject.org d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproject.org. IN OPENPGPKEY mQINBFBHPMsBEACeInGYJCb+7TurKfb6wGyTottCDtiSJB310i37/6ZYoeIay/5soJjlM yfMFQ9T2XNT/0LM6gTa0MpC1st9LnzYTMsT6tzRly1D1UbVI6xw0g0vE5y2Cjk3xUwAyn ... --- Makefile.am | 4 ++- man/systemd-resolve.xml | 19 +++++++++++++ src/resolve/resolve-tool.c | 69 ++++++++++++++++++++++++++++++++++++++++------ src/shared/gcrypt-util.c | 29 +++++++++++++++++++ src/shared/gcrypt-util.h | 1 + 5 files changed, 113 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index d2cf9360ed..e63015476c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5291,7 +5291,9 @@ systemd_resolve_SOURCES = \ src/resolve/resolved-dns-question.c \ src/resolve/resolved-dns-question.h \ src/resolve/dns-type.c \ - src/resolve/dns-type.h + src/resolve/dns-type.h \ + src/shared/gcrypt-util.c \ + src/shared/gcrypt-util.h nodist_systemd_resolve_SOURCES = \ src/resolve/dns_type-from-name.h \ diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index f1e663c5bb..0defa2d7fb 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -76,6 +76,13 @@ TYPE DOMAIN + + systemd-resolve + OPTIONS + --openpgp + USER@DOMAIN + + systemd-resolve OPTIONS @@ -114,6 +121,10 @@ is assumed to be a domain name, that is already prefixed with an SRV type, and an SRV lookup is done (no TXT). + The switch may be use to query PGP keys stored as the + OPENPGPKEY resource records. + When this option is specified one or more e-mail address must be specified. + The switch may be used to show resolver statistics, including information about the number of succesful and failed DNSSEC validations. @@ -197,6 +208,14 @@ the TXT service metadata record is resolved as well. + + + + Enables OPENPGPKEY resource record resolution (see above). Specified e-mail + addresses are converted to the corresponding DNS domain name, and any OPENPGPKEY keys are + printed. + + BOOL diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 9bee953839..6d1bc6d0f9 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -19,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include #include @@ -30,6 +31,7 @@ #include "bus-util.h" #include "escape.h" #include "in-addr-util.h" +#include "gcrypt-util.h" #include "parse-util.h" #include "resolved-def.h" #include "resolved-dns-packet.h" @@ -48,6 +50,7 @@ static enum { MODE_RESOLVE_HOST, MODE_RESOLVE_RECORD, MODE_RESOLVE_SERVICE, + MODE_RESOLVE_OPENPGP, MODE_STATISTICS, MODE_RESET_STATISTICS, } arg_mode = MODE_RESOLVE_HOST; @@ -547,15 +550,10 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) { } else n = p; - if (type == 0) - type = arg_type; - if (type == 0) - type = DNS_TYPE_A; - if (class == 0) - class = arg_class; - if (class == 0) - class = DNS_CLASS_IN; + class = arg_class ?: DNS_CLASS_IN; + if (type == 0) + type = arg_type ?: DNS_TYPE_A; return resolve_record(bus, n, class, type); @@ -765,6 +763,36 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons return 0; } +static int resolve_openpgp(sd_bus *bus, const char *address) { + const char *domain, *full; + int r; + _cleanup_free_ char *hashed = NULL; + + assert(bus); + assert(address); + + domain = strrchr(address, '@'); + if (!domain) { + log_error("Address does not contain '@': \"%s\"", address); + return -EINVAL; + } else if (domain == address || domain[1] == '\0') { + log_error("Address starts or ends with '@': \"%s\"", address); + return -EINVAL; + } + domain++; + + r = string_hashsum(address, domain - 1 - address, GCRY_MD_SHA224, &hashed); + if (r < 0) + return log_error_errno(r, "Hashing failed: %m"); + + full = strjoina(hashed, "._openpgpkey.", domain); + log_debug("Looking up \"%s\".", full); + + return resolve_record(bus, full, + arg_class ?: DNS_CLASS_IN, + arg_type ?: DNS_TYPE_OPENPGPKEY); +} + static int show_statistics(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -947,6 +975,7 @@ static void help(void) { " --service Resolve service (SRV)\n" " --service-address=BOOL Do [not] resolve address for services\n" " --service-txt=BOOL Do [not] resolve TXT records for services\n" + " --openpgp Query OpenPGP public key\n" " --cname=BOOL Do [not] follow CNAME redirects\n" " --search=BOOL Do [not] use search domains\n" " --legend=BOOL Do [not] print column headers and meta information\n" @@ -963,6 +992,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_CNAME, ARG_SERVICE_ADDRESS, ARG_SERVICE_TXT, + ARG_OPENPGP, ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, @@ -980,6 +1010,7 @@ static int parse_argv(int argc, char *argv[]) { { "service", no_argument, NULL, ARG_SERVICE }, { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, + { "openpgp", no_argument, NULL, ARG_OPENPGP }, { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, @@ -1089,6 +1120,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESOLVE_SERVICE; break; + case ARG_OPENPGP: + arg_mode = MODE_RESOLVE_OPENPGP; + break; + case ARG_CNAME: r = parse_boolean(optarg); if (r < 0) @@ -1248,6 +1283,24 @@ int main(int argc, char **argv) { break; + case MODE_RESOLVE_OPENPGP: + if (argc < optind + 1) { + log_error("E-mail address required."); + r = -EINVAL; + goto finish; + + } + + r = 0; + while (optind < argc) { + int k; + + k = resolve_openpgp(bus, argv[optind++]); + if (k < 0) + r = k; + } + break; + case MODE_STATISTICS: if (argc > optind) { log_error("Too many arguments."); diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c index 3bbc161ef2..b887243849 100644 --- a/src/shared/gcrypt-util.c +++ b/src/shared/gcrypt-util.c @@ -38,3 +38,32 @@ void initialize_libgcrypt(bool secmem) { gcry_control(GCRYCTL_DISABLE_SECMEM); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } + +int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) { + gcry_md_hd_t md = NULL; + size_t hash_size; + void *hash; + char *enc; + + initialize_libgcrypt(false); + + hash_size = gcry_md_get_algo_dlen(md_algorithm); + assert(hash_size > 0); + + gcry_md_open(&md, md_algorithm, 0); + if (!md) + return -EIO; + + gcry_md_write(md, s, len); + + hash = gcry_md_read(md, 0); + if (!hash) + return -EIO; + + enc = hexmem(hash, hash_size); + if (!enc) + return -ENOMEM; + + *out = enc; + return 0; +} diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h index 42ce3fd121..c7652c22d1 100644 --- a/src/shared/gcrypt-util.h +++ b/src/shared/gcrypt-util.h @@ -22,3 +22,4 @@ #include void initialize_libgcrypt(bool secmem); +int string_hashsum(const char *s, size_t len, int md_algorithm, char **out); -- cgit v1.2.3-54-g00ecf From e18a3c7314ddfabd3d6eabad4a32d6e571e2ec42 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Jan 2016 16:42:16 -0500 Subject: resolved: add cleanup function to rewind packets This makes the behaviour more consistent. Before we would not rewind after some errors, but this seems to have been an unintentional omission. --- src/resolve/resolved-dns-packet.c | 422 ++++++++++++++++---------------------- 1 file changed, 178 insertions(+), 244 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index abb9725b73..6a9a1f732d 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -30,6 +30,19 @@ #define EDNS0_OPT_DO (1<<15) +typedef struct DnsPacketRewinder { + DnsPacket *packet; + size_t saved_rindex; +} DnsPacketRewinder; + +static void rewind_dns_packet(DnsPacketRewinder *rewinder) { + if (rewinder->packet) + dns_packet_rewind(rewinder->packet, rewinder->saved_rindex); +} + +#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while(0) +#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while(0) + int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; size_t a; @@ -1231,80 +1244,67 @@ int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) { } int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) { - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; const void *d; char *t; uint8_t c; int r; assert(p); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_uint8(p, &c, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read(p, c, &d, NULL); if (r < 0) - goto fail; + return r; - if (memchr(d, 0, c)) { - r = -EBADMSG; - goto fail; - } + if (memchr(d, 0, c)) + return -EBADMSG; t = strndup(d, c); - if (!t) { - r = -ENOMEM; - goto fail; - } + if (!t) + return -ENOMEM; if (!utf8_is_valid(t)) { free(t); - r = -EBADMSG; - goto fail; + return -EBADMSG; } *ret = t; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; - -fail: - dns_packet_rewind(p, saved_rindex); - return r; } int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) { - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; uint8_t c; int r; assert(p); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_uint8(p, &c, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read(p, c, ret, NULL); if (r < 0) - goto fail; + return r; if (size) *size = c; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; - -fail: - dns_packet_rewind(p, saved_rindex); - return r; } int dns_packet_read_name( @@ -1313,7 +1313,8 @@ int dns_packet_read_name( bool allow_compression, size_t *start) { - size_t saved_rindex, after_rindex = 0, jump_barrier; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; + size_t after_rindex = 0, jump_barrier; _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; bool first = true; @@ -1321,19 +1322,18 @@ int dns_packet_read_name( assert(p); assert(_ret); + INIT_REWINDER(rewinder, p); + jump_barrier = p->rindex; if (p->refuse_compression) allow_compression = false; - saved_rindex = p->rindex; - jump_barrier = p->rindex; - for (;;) { uint8_t c, d; r = dns_packet_read_uint8(p, &c, NULL); if (r < 0) - goto fail; + return r; if (c == 0) /* End of name */ @@ -1344,12 +1344,10 @@ int dns_packet_read_name( /* Literal label */ r = dns_packet_read(p, c, (const void**) &label, NULL); if (r < 0) - goto fail; + return r; - if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) + return -ENOMEM; if (first) first = false; @@ -1358,7 +1356,7 @@ int dns_packet_read_name( r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); if (r < 0) - goto fail; + return r; n += r; continue; @@ -1368,13 +1366,11 @@ int dns_packet_read_name( /* Pointer */ r = dns_packet_read_uint8(p, &d, NULL); if (r < 0) - goto fail; + return r; ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; - if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) { - r = -EBADMSG; - goto fail; - } + if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) + return -EBADMSG; if (after_rindex == 0) after_rindex = p->rindex; @@ -1382,16 +1378,12 @@ int dns_packet_read_name( /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */ jump_barrier = ptr; p->rindex = ptr; - } else { - r = -EBADMSG; - goto fail; - } + } else + return -EBADMSG; } - if (!GREEDY_REALLOC(ret, allocated, n + 1)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(ret, allocated, n + 1)) + return -ENOMEM; ret[n] = 0; @@ -1402,13 +1394,10 @@ int dns_packet_read_name( ret = NULL; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; - -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) { @@ -1418,32 +1407,31 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta uint8_t bit = 0; unsigned i; bool found = false; - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; int r; assert(p); assert(types); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = bitmap_ensure_allocated(types); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &window, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &length, NULL); if (r < 0) - goto fail; + return r; if (length == 0 || length > 32) return -EBADMSG; r = dns_packet_read(p, length, (const void **)&bitmap, NULL); if (r < 0) - goto fail; + return r; for (i = 0; i < length; i++) { uint8_t bitmask = 1 << 7; @@ -1468,7 +1456,7 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta r = bitmap_set(*types, n); if (r < 0) - goto fail; + return r; } bit ++; @@ -1480,70 +1468,61 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta return -EBADMSG; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) { - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; int r; - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); - while (p->rindex < saved_rindex + size) { + while (p->rindex < rewinder.saved_rindex + size) { r = dns_packet_read_type_window(p, types, NULL); if (r < 0) - goto fail; + return r; /* don't read past end of current RR */ - if (p->rindex > saved_rindex + size) { - r = -EBADMSG; - goto fail; - } + if (p->rindex > rewinder.saved_rindex + size) + return -EBADMSG; } - if (p->rindex != saved_rindex + size) { - r = -EBADMSG; - goto fail; - } + if (p->rindex != rewinder.saved_rindex + size) + return -EBADMSG; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) { + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; _cleanup_free_ char *name = NULL; bool cache_flush = false; uint16_t class, type; DnsResourceKey *key; - size_t saved_rindex; int r; assert(p); assert(ret); - - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_name(p, &name, true, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &type, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &class, NULL); if (r < 0) - goto fail; + return r; if (p->protocol == DNS_PROTOCOL_MDNS) { /* See RFC6762, Section 10.2 */ @@ -1555,10 +1534,8 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus } key = dns_resource_key_new_consume(class, type, name); - if (!key) { - r = -ENOMEM; - goto fail; - } + if (!key) + return -ENOMEM; name = NULL; *ret = key; @@ -1566,12 +1543,10 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus if (ret_cache_flush) *ret_cache_flush = cache_flush; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static bool loc_size_ok(uint8_t size) { @@ -1583,7 +1558,8 @@ static bool loc_size_ok(uint8_t size) { int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - size_t saved_rindex, offset; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; + size_t offset; uint16_t rdlength; bool cache_flush; int r; @@ -1591,27 +1567,22 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl assert(p); assert(ret); - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) - goto fail; + return r; - if (!dns_class_is_valid_rr(key->class)|| - !dns_type_is_valid_rr(key->type)) { - r = -EBADMSG; - goto fail; - } + if (!dns_class_is_valid_rr(key->class) || !dns_type_is_valid_rr(key->type)) + return -EBADMSG; rr = dns_resource_record_new(key); - if (!rr) { - r = -ENOMEM; - goto fail; - } + if (!rr) + return -ENOMEM; r = dns_packet_read_uint32(p, &rr->ttl, NULL); if (r < 0) - goto fail; + return r; /* RFC 2181, Section 8, suggests to * treat a TTL with the MSB set as a zero TTL. */ @@ -1620,12 +1591,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_uint16(p, &rdlength, NULL); if (r < 0) - goto fail; + return r; - if (p->rindex + rdlength > p->size) { - r = -EBADMSG; - goto fail; - } + if (p->rindex + rdlength > p->size) + return -EBADMSG; offset = p->rindex; @@ -1634,13 +1603,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_SRV: r = dns_packet_read_uint16(p, &rr->srv.priority, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->srv.weight, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->srv.port, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->srv.name, true, NULL); break; @@ -1654,7 +1623,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_HINFO: r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_string(p, &rr->hinfo.os, NULL); break; @@ -1710,27 +1679,27 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_SOA: r = dns_packet_read_name(p, &rr->soa.mname, true, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->soa.rname, true, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.serial, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.retry, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.expire, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL); break; @@ -1738,7 +1707,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_MX: r = dns_packet_read_uint16(p, &rr->mx.priority, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL); break; @@ -1749,49 +1718,43 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_uint8(p, &t, &pos); if (r < 0) - goto fail; + return r; if (t == 0) { rr->loc.version = t; r = dns_packet_read_uint8(p, &rr->loc.size, NULL); if (r < 0) - goto fail; + return r; - if (!loc_size_ok(rr->loc.size)) { - r = -EBADMSG; - goto fail; - } + if (!loc_size_ok(rr->loc.size)) + return -EBADMSG; r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL); if (r < 0) - goto fail; + return r; - if (!loc_size_ok(rr->loc.horiz_pre)) { - r = -EBADMSG; - goto fail; - } + if (!loc_size_ok(rr->loc.horiz_pre)) + return -EBADMSG; r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL); if (r < 0) - goto fail; + return r; - if (!loc_size_ok(rr->loc.vert_pre)) { - r = -EBADMSG; - goto fail; - } + if (!loc_size_ok(rr->loc.vert_pre)) + return -EBADMSG; r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL); if (r < 0) - goto fail; + return r; break; } else { @@ -1804,122 +1767,114 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_DS: r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 4, &rr->ds.digest, &rr->ds.digest_size, NULL); if (r < 0) - goto fail; + return r; - if (rr->ds.digest_size <= 0) { + if (rr->ds.digest_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; case DNS_TYPE_SSHFP: r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 2, &rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size, NULL); - if (rr->sshfp.fingerprint_size <= 0) { + if (rr->sshfp.fingerprint_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; case DNS_TYPE_DNSKEY: r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 4, &rr->dnskey.key, &rr->dnskey.key_size, NULL); - if (rr->dnskey.key_size <= 0) { + if (rr->dnskey.key_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; case DNS_TYPE_RRSIG: r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, offset + rdlength - p->rindex, &rr->rrsig.signature, &rr->rrsig.signature_size, NULL); - if (rr->rrsig.signature_size <= 0) { + if (rr->rrsig.signature_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; @@ -1934,11 +1889,9 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL); - if (r < 0) - goto fail; /* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself * is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records @@ -1951,41 +1904,39 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL); if (r < 0) - goto fail; + return r; /* this may be zero */ r = dns_packet_read_uint8(p, &size, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &size, NULL); if (r < 0) - goto fail; + return r; - if (size <= 0) { - r = -EBADMSG; - goto fail; - } + if (size <= 0) + return -EBADMSG; - r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL); + r = dns_packet_read_memdup(p, size, + &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, + NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL); - if (r < 0) - goto fail; /* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */ @@ -1995,25 +1946,24 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl case DNS_TYPE_TLSA: r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL); if (r < 0) - goto fail; + return r; r = dns_packet_read_memdup(p, rdlength - 3, &rr->tlsa.data, &rr->tlsa.data_size, NULL); - if (rr->tlsa.data_size <= 0) { + + if (rr->tlsa.data_size <= 0) /* the accepted size depends on the algorithm, but for now just ensure that the value is greater than zero */ - r = -EBADMSG; - goto fail; - } + return -EBADMSG; break; @@ -2022,16 +1972,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl default: unparseable: r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL); - if (r < 0) - goto fail; + break; } if (r < 0) - goto fail; - if (p->rindex != offset + rdlength) { - r = -EBADMSG; - goto fail; - } + return r; + if (p->rindex != offset + rdlength) + return -EBADMSG; *ret = rr; rr = NULL; @@ -2039,12 +1986,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl if (ret_cache_flush) *ret_cache_flush = cache_flush; if (start) - *start = saved_rindex; + *start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; -fail: - dns_packet_rewind(p, saved_rindex); - return r; } static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) { @@ -2092,23 +2037,21 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) { int dns_packet_extract(DnsPacket *p) { _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - size_t saved_rindex; + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {}; unsigned n, i; int r; if (p->extracted) return 0; - saved_rindex = p->rindex; + INIT_REWINDER(rewinder, p); dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE); n = DNS_PACKET_QDCOUNT(p); if (n > 0) { question = dns_question_new(n); - if (!question) { - r = -ENOMEM; - goto finish; - } + if (!question) + return -ENOMEM; for (i = 0; i < n; i++) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; @@ -2116,21 +2059,17 @@ int dns_packet_extract(DnsPacket *p) { r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) - goto finish; + return r; - if (cache_flush) { - r = -EBADMSG; - goto finish; - } + if (cache_flush) + return -EBADMSG; - if (!dns_type_is_valid_query(key->type)) { - r = -EBADMSG; - goto finish; - } + if (!dns_type_is_valid_query(key->type)) + return -EBADMSG; r = dns_question_add(question, key); if (r < 0) - goto finish; + return r; } } @@ -2140,10 +2079,8 @@ int dns_packet_extract(DnsPacket *p) { bool bad_opt = false; answer = dns_answer_new(n); - if (!answer) { - r = -ENOMEM; - goto finish; - } + if (!answer) + return -ENOMEM; for (i = 0; i < n; i++) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; @@ -2151,7 +2088,7 @@ int dns_packet_extract(DnsPacket *p) { r = dns_packet_read_rr(p, &rr, &cache_flush, NULL); if (r < 0) - goto finish; + return r; /* Try to reduce memory usage a bit */ if (previous) @@ -2214,7 +2151,7 @@ int dns_packet_extract(DnsPacket *p) { (i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) | (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0)); if (r < 0) - goto finish; + return r; } /* Remember this RR, so that we potentically can merge it's ->key object with the next RR. Note @@ -2235,11 +2172,8 @@ int dns_packet_extract(DnsPacket *p) { p->extracted = true; - r = 0; - -finish: - p->rindex = saved_rindex; - return r; + /* no CANCEL, always rewind */ + return 0; } int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) { -- cgit v1.2.3-54-g00ecf From 9ca6ff50ab7af9d122521c5bb9cc8201cb38181a Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 11 Feb 2016 22:12:04 +0100 Subject: Remove kdbus custom endpoint support This feature will not be used anytime soon, so remove a bit of cruft. The BusPolicy= config directive will stay around as compat noop. --- Makefile.am | 2 - man/systemd.service.xml | 36 --------- src/basic/exit-status.c | 3 - src/basic/exit-status.h | 1 - src/core/bus-endpoint.c | 135 ---------------------------------- src/core/bus-endpoint.h | 42 ----------- src/core/busname.h | 1 + src/core/execute.c | 21 ------ src/core/execute.h | 7 -- src/core/load-fragment-gperf.gperf.m4 | 2 +- src/core/load-fragment.c | 53 ------------- src/core/load-fragment.h | 1 - src/core/mount.c | 1 - src/core/namespace.c | 85 +-------------------- src/core/namespace.h | 1 - src/core/service.c | 29 -------- src/core/service.h | 2 - src/core/socket.c | 1 - src/core/swap.c | 1 - src/libsystemd/sd-bus/bus-kernel.c | 44 ----------- src/test/test-ns.c | 1 - 21 files changed, 3 insertions(+), 466 deletions(-) delete mode 100644 src/core/bus-endpoint.c delete mode 100644 src/core/bus-endpoint.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 9f051e2954..5a8fc2fe23 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1136,8 +1136,6 @@ libcore_la_SOURCES = \ src/core/socket.h \ src/core/busname.c \ src/core/busname.h \ - src/core/bus-endpoint.c \ - src/core/bus-endpoint.h \ src/core/bus-policy.c \ src/core/bus-policy.h \ src/core/target.c \ diff --git a/man/systemd.service.xml b/man/systemd.service.xml index d7760d4f2c..be72f39268 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -272,42 +272,6 @@ - - BusPolicy= - - If specified, a custom kdbus - endpoint will be created and installed as the default bus node - for the service. Such a custom endpoint can hold an own set of - policy rules that are enforced on top of the bus-wide ones. - The custom endpoint is named after the service it was created - for, and its node will be bind-mounted over the default bus - node location, so the service can only access the bus through - its own endpoint. Note that custom bus endpoints default to a - "deny all" policy. Hence, if at least one - BusPolicy= directive is given, you have to - make sure to add explicit rules for everything the service - should be able to do. - The value of this directive is comprised - of two parts; the bus name, and a verb to - specify to granted access, which is one of - , - , or - . - implies - , and - implies both and - . - If multiple access levels are specified for the - same bus name, the most powerful one takes - effect. - - Examples: - BusPolicy=org.freedesktop.systemd1 talk - BusPolicy=org.foo.bar see - This option is only available on kdbus enabled systems. - - - ExecStart= Commands with their arguments that are diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index 5e0bc415c8..92fa5ace61 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -147,9 +147,6 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { case EXIT_MAKE_STARTER: return "MAKE_STARTER"; - case EXIT_BUS_ENDPOINT: - return "BUS_ENDPOINT"; - case EXIT_SMACK_PROCESS_LABEL: return "SMACK_PROCESS_LABEL"; } diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index 79525d30ee..1208c8feed 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -77,7 +77,6 @@ typedef enum ExitStatus { EXIT_RUNTIME_DIRECTORY, EXIT_MAKE_STARTER, EXIT_CHOWN, - EXIT_BUS_ENDPOINT, EXIT_SMACK_PROCESS_LABEL, } ExitStatus; diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c deleted file mode 100644 index d22a80c91f..0000000000 --- a/src/core/bus-endpoint.c +++ /dev/null @@ -1,135 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2014 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 . -***/ - -#include - -#include "alloc-util.h" -#include "bus-endpoint.h" -#include "bus-kernel.h" -#include "bus-policy.h" -#include "kdbus.h" - -int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) { - - struct kdbus_cmd *update; - struct kdbus_item *n; - BusEndpointPolicy *po; - Iterator i; - size_t size; - int r; - - size = ALIGN8(offsetof(struct kdbus_cmd, items)); - - HASHMAP_FOREACH(po, ep->policy_hash, i) { - size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(po->name) + 1); - size += ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access)); - } - - update = alloca0_align(size, 8); - update->size = size; - - n = update->items; - - HASHMAP_FOREACH(po, ep->policy_hash, i) { - n->type = KDBUS_ITEM_NAME; - n->size = offsetof(struct kdbus_item, str) + strlen(po->name) + 1; - strcpy(n->str, po->name); - n = KDBUS_ITEM_NEXT(n); - - n->type = KDBUS_ITEM_POLICY_ACCESS; - n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access); - - n->policy_access.type = KDBUS_POLICY_ACCESS_USER; - n->policy_access.access = bus_kernel_translate_access(po->access); - n->policy_access.id = uid; - - n = KDBUS_ITEM_NEXT(n); - } - - r = ioctl(fd, KDBUS_CMD_ENDPOINT_UPDATE, update); - if (r < 0) - return -errno; - - return 0; -} - -int bus_endpoint_new(BusEndpoint **ep) { - assert(ep); - - *ep = new0(BusEndpoint, 1); - if (!*ep) - return -ENOMEM; - - return 0; -} - -int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access) { - _cleanup_free_ BusEndpointPolicy *po = NULL; - _cleanup_free_ char *key = NULL; - int r; - - assert(ep); - assert(name); - assert(access > _BUS_POLICY_ACCESS_INVALID && access < _BUS_POLICY_ACCESS_MAX); - - /* check if we already have this name in the policy list. If we do, see if the new access level - * is higher than the exising one, and upgrade the entry in that case. Otherwise, do nothing. - */ - - if (ep->policy_hash) { - po = hashmap_get(ep->policy_hash, name); - if (po) { - if (po->access < access) - po->access = access; - - return 0; - } - } else { - ep->policy_hash = hashmap_new(&string_hash_ops); - if (!ep->policy_hash) - return -ENOMEM; - } - - po = new0(BusEndpointPolicy, 1); - if (!po) - return -ENOMEM; - - key = strdup(name); - if (!key) - return -ENOMEM; - - po->name = key; - po->access = access; - - r = hashmap_put(ep->policy_hash, key, po); - if (r < 0) - return r; - - po = NULL; - key = NULL; - return 0; -} - -void bus_endpoint_free(BusEndpoint *endpoint) { - if (!endpoint) - return; - - hashmap_free_free_free(endpoint->policy_hash); - free(endpoint); -} diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h deleted file mode 100644 index f2fbc4701c..0000000000 --- a/src/core/bus-endpoint.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 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 . -***/ - -typedef struct BusEndpoint BusEndpoint; -typedef struct BusEndpointPolicy BusEndpointPolicy; - -#include "bus-policy.h" -#include "hashmap.h" - -struct BusEndpointPolicy { - char *name; - BusPolicyAccess access; -}; - -struct BusEndpoint { - Hashmap *policy_hash; -}; - -int bus_endpoint_new(BusEndpoint **ep); -void bus_endpoint_free(BusEndpoint *endpoint); - -int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access); - -int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep); diff --git a/src/core/busname.h b/src/core/busname.h index 6b6f6c62d4..52c4055dbb 100644 --- a/src/core/busname.h +++ b/src/core/busname.h @@ -23,6 +23,7 @@ typedef struct BusName BusName; typedef struct BusNamePolicy BusNamePolicy; #include "unit.h" +#include "bus-policy.h" typedef enum BusNameResult { BUSNAME_SUCCESS, diff --git a/src/core/execute.c b/src/core/execute.c index 1e4630182d..30f7e05b90 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -57,7 +57,6 @@ #endif #include "async.h" #include "barrier.h" -#include "bus-endpoint.h" #include "cap-list.h" #include "capability-util.h" #include "def.h" @@ -1387,9 +1386,6 @@ static bool exec_needs_mount_namespace( 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) @@ -1423,9 +1419,6 @@ static int close_remaining_fds( n_dont_close += n_fds; } - if (params->bus_endpoint_fd >= 0) - dont_close[n_dont_close++] = params->bus_endpoint_fd; - if (runtime) { if (runtime->netns_storage_socket[0] >= 0) dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; @@ -1655,16 +1648,6 @@ static int exec_child( } } - if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) { - uid_t ep_uid = (uid == UID_INVALID) ? 0 : uid; - - r = bus_kernel_set_endpoint_policy(params->bus_endpoint_fd, ep_uid, context->bus_endpoint); - if (r < 0) { - *exit_status = EXIT_BUS_ENDPOINT; - return r; - } - } - /* If delegation is enabled we'll pass ownership of the cgroup * (but only in systemd's own controller hierarchy!) to the * user of the new process. */ @@ -1787,7 +1770,6 @@ static int exec_child( context->inaccessible_dirs, tmp, var, - params->bus_endpoint_path, context->private_devices, context->protect_home, context->protect_system, @@ -2214,9 +2196,6 @@ void exec_context_done(ExecContext *c) { c->address_families = set_free(c->address_families); c->runtime_directory = strv_free(c->runtime_directory); - - bus_endpoint_free(c->bus_endpoint); - c->bus_endpoint = NULL; } int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) { diff --git a/src/core/execute.h b/src/core/execute.h index 578f85b6bc..f7205701f4 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -30,7 +30,6 @@ typedef struct ExecParameters ExecParameters; #include #include -#include "bus-endpoint.h" #include "fdset.h" #include "list.h" #include "missing.h" @@ -201,9 +200,6 @@ struct ExecContext { bool ioprio_set:1; bool cpu_sched_set:1; bool no_new_privileges_set:1; - - /* custom dbus enpoint */ - BusEndpoint *bus_endpoint; }; #include "cgroup-util.h" @@ -234,9 +230,6 @@ struct ExecParameters { int *idle_pipe; - char *bus_endpoint_path; - int bus_endpoint_fd; - int stdin_fd; int stdout_fd; int stderr_fd; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5024fd19a5..fde64c9747 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -240,7 +240,7 @@ Service.BusName, config_parse_bus_name, 0, Service.FileDescriptorStoreMax, config_parse_unsigned, 0, offsetof(Service, n_fd_store_max) Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) Service.Sockets, config_parse_service_sockets, 0, 0 -Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context) +Service.BusPolicy, config_parse_warn_compat, DISABLED_LEGACY, 0 Service.USBFunctionDescriptors, config_parse_path, 0, offsetof(Service, usb_function_descriptors) Service.USBFunctionStrings, config_parse_path, 0, offsetof(Service, usb_function_strings) EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b3dec7b8cc..ba551fb41d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1902,59 +1902,6 @@ int config_parse_bus_policy( return 0; } -int config_parse_bus_endpoint_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) { - - _cleanup_free_ char *name = NULL; - BusPolicyAccess access; - ExecContext *c = data; - char *access_str; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - name = strdup(rvalue); - if (!name) - return log_oom(); - - access_str = strpbrk(name, WHITESPACE); - if (!access_str) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue); - return 0; - } - - *access_str = '\0'; - access_str++; - access_str += strspn(access_str, WHITESPACE); - - access = bus_policy_access_from_string(access_str); - if (access <= _BUS_POLICY_ACCESS_INVALID || - access >= _BUS_POLICY_ACCESS_MAX) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str); - return 0; - } - - if (!c->bus_endpoint) { - r = bus_endpoint_new(&c->bus_endpoint); - if (r < 0) - return log_error_errno(r, "Failed to create bus endpoint object: %m"); - } - - return bus_endpoint_add_policy(c->bus_endpoint, name, access); -} - int config_parse_working_directory( const char *unit, const char *filename, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 5fb5910919..372d05a61d 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -67,7 +67,6 @@ int config_parse_service_sockets(const char *unit, const char *filename, unsigne int config_parse_busname_service(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_bus_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_bus_policy_world(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_bus_endpoint_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_unit_env_file(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_ip_tos(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_unit_condition_path(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/core/mount.c b/src/core/mount.c index de1075d3a0..93d2bd595c 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -703,7 +703,6 @@ 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, .stdin_fd = -1, .stdout_fd = -1, .stderr_fd = -1, diff --git a/src/core/namespace.c b/src/core/namespace.c index 4fa381db5b..b573f008b9 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -51,7 +51,6 @@ typedef enum MountMode { PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV, - PRIVATE_BUS_ENDPOINT, READWRITE } MountMode; @@ -268,78 +267,6 @@ fail: return r; } -static int mount_kdbus(BindMount *m) { - - char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX"; - _cleanup_free_ char *basepath = NULL; - _cleanup_umask_ mode_t u; - char *busnode = NULL, *root; - struct stat st; - int r; - - assert(m); - - u = umask(0000); - - if (!mkdtemp(temporary_mount)) - return log_error_errno(errno, "Failed create temp dir: %m"); - - root = strjoina(temporary_mount, "/kdbus"); - (void) mkdir(root, 0755); - if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) { - r = -errno; - goto fail; - } - - /* create a new /dev/null dev node copy so we have some fodder to - * bind-mount the custom endpoint over. */ - if (stat("/dev/null", &st) < 0) { - r = log_error_errno(errno, "Failed to stat /dev/null: %m"); - goto fail; - } - - busnode = strjoina(root, "/bus"); - if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) { - r = log_error_errno(errno, "mknod() for %s failed: %m", - busnode); - goto fail; - } - - r = mount(m->path, busnode, NULL, MS_BIND, NULL); - if (r < 0) { - r = log_error_errno(errno, "bind mount of %s failed: %m", - m->path); - goto fail; - } - - basepath = dirname_malloc(m->path); - if (!basepath) { - r = -ENOMEM; - goto fail; - } - - if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) { - r = log_error_errno(errno, "bind mount of %s failed: %m", - basepath); - goto fail; - } - - rmdir(temporary_mount); - return 0; - -fail: - if (busnode) { - umount(busnode); - unlink(busnode); - } - - umount(root); - rmdir(root); - rmdir(temporary_mount); - - return r; -} - static int apply_mount( BindMount *m, const char *tmp_dir, @@ -379,9 +306,6 @@ static int apply_mount( case PRIVATE_DEV: return mount_dev(m); - case PRIVATE_BUS_ENDPOINT: - return mount_kdbus(m); - default: assert_not_reached("Unknown mode"); } @@ -422,7 +346,6 @@ int setup_namespace( char** inaccessible_dirs, const char* tmp_dir, const char* var_tmp_dir, - const char* bus_endpoint_path, bool private_dev, ProtectHome protect_home, ProtectSystem protect_system, @@ -438,7 +361,7 @@ int setup_namespace( if (unshare(CLONE_NEWNS) < 0) return -errno; - n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path + + n = !!tmp_dir + !!var_tmp_dir + strv_length(read_write_dirs) + strv_length(read_only_dirs) + strv_length(inaccessible_dirs) + @@ -479,12 +402,6 @@ int setup_namespace( m++; } - if (bus_endpoint_path) { - m->path = prefix_roota(root_directory, bus_endpoint_path); - m->mode = PRIVATE_BUS_ENDPOINT; - m++; - } - if (protect_home != PROTECT_HOME_NO) { const char *home_dir, *run_user_dir, *root_dir; diff --git a/src/core/namespace.h b/src/core/namespace.h index 40bee74e2c..b54b7b47d6 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -45,7 +45,6 @@ int setup_namespace(const char *chroot, char **inaccessible_dirs, const char *tmp_dir, const char *var_tmp_dir, - const char *endpoint_path, bool private_dev, ProtectHome protect_home, ProtectSystem protect_system, diff --git a/src/core/service.c b/src/core/service.c index ac7e41d777..ed24417859 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -113,7 +113,6 @@ static void service_init(Unit *u) { s->runtime_max_usec = USEC_INFINITY; s->type = _SERVICE_TYPE_INVALID; s->socket_fd = -1; - s->bus_endpoint_fd = -1; s->stdin_fd = s->stdout_fd = s->stderr_fd = -1; s->guess_main_pid = true; @@ -321,7 +320,6 @@ static void service_done(Unit *u) { s->bus_name_owner = mfree(s->bus_name_owner); - s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd); service_close_socket_fd(s); service_connection_unref(s); @@ -1157,7 +1155,6 @@ static int service_spawn( pid_t *_pid) { _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL; - _cleanup_free_ char *bus_endpoint_path = NULL; _cleanup_free_ int *fds = NULL; unsigned n_fds = 0, n_env = 0; const char *path; @@ -1167,7 +1164,6 @@ static int service_spawn( .apply_permissions = apply_permissions, .apply_chroot = apply_chroot, .apply_tty_stdin = apply_tty_stdin, - .bus_endpoint_fd = -1, .stdin_fd = -1, .stdout_fd = -1, .stderr_fd = -1, @@ -1267,18 +1263,6 @@ static int service_spawn( } else path = UNIT(s)->cgroup_path; - if (s->exec_context.bus_endpoint) { - r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user", - UNIT(s)->id, &bus_endpoint_path); - if (r < 0) - return r; - - /* Pass the fd to the exec_params so that the child process can upload the policy. - * Keep a reference to the fd in the service, so the endpoint is kept alive as long - * as the service is running. */ - exec_params.bus_endpoint_fd = s->bus_endpoint_fd = r; - } - exec_params.argv = argv; exec_params.fds = fds; exec_params.fd_names = fd_names; @@ -1290,7 +1274,6 @@ static int service_spawn( exec_params.cgroup_delegate = s->cgroup_context.delegate; exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); exec_params.watchdog_usec = s->watchdog_usec; - exec_params.bus_endpoint_path = bus_endpoint_path; exec_params.selinux_context_net = s->socket_fd_selinux_context_net; if (s->type == SERVICE_IDLE) exec_params.idle_pipe = UNIT(s)->manager->idle_pipe; @@ -2124,9 +2107,6 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { return r; r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd); - if (r < 0) - return r; - r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd); if (r < 0) return r; @@ -2263,15 +2243,6 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, asynchronous_close(s->socket_fd); s->socket_fd = fdset_remove(fds, fd); } - } else if (streq(key, "endpoint-fd")) { - int fd; - - if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - 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); - } } else if (streq(key, "fd-store-fd")) { const char *fdv; size_t pf; diff --git a/src/core/service.h b/src/core/service.h index d342e000bb..a5ced215e4 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -150,8 +150,6 @@ struct Service { int socket_fd; bool socket_fd_selinux_context_net; - int bus_endpoint_fd; - bool permissions_start_only; bool root_directory_start_only; bool remain_after_exit; diff --git a/src/core/socket.c b/src/core/socket.c index 976687af41..a1cb54d77a 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1527,7 +1527,6 @@ 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, .stdin_fd = -1, .stdout_fd = -1, .stderr_fd = -1, diff --git a/src/core/swap.c b/src/core/swap.c index 1bf0c0a808..11506d9ecb 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -609,7 +609,6 @@ 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, .stdin_fd = -1, .stdout_fd = -1, .stderr_fd = -1, diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 0896eeb177..59398b841d 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -1693,50 +1693,6 @@ int bus_kernel_open_bus_fd(const char *bus, char **path) { return fd; } -int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **ep_path) { - _cleanup_free_ char *path = NULL; - struct kdbus_cmd *make; - struct kdbus_item *n; - const char *name; - int fd; - - fd = bus_kernel_open_bus_fd(bus_name, &path); - if (fd < 0) - return fd; - - make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd, items)) + - ALIGN8(offsetof(struct kdbus_item, str) + DECIMAL_STR_MAX(uid_t) + 1 + strlen(ep_name) + 1), - 8); - make->size = ALIGN8(offsetof(struct kdbus_cmd, items)); - make->flags = KDBUS_MAKE_ACCESS_WORLD; - - n = make->items; - sprintf(n->str, UID_FMT "-%s", getuid(), ep_name); - n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; - n->type = KDBUS_ITEM_MAKE_NAME; - make->size += ALIGN8(n->size); - name = n->str; - - if (ioctl(fd, KDBUS_CMD_ENDPOINT_MAKE, make) < 0) { - safe_close(fd); - return -errno; - } - - if (ep_path) { - char *p; - - p = strjoin(dirname(path), "/", name, NULL); - if (!p) { - safe_close(fd); - return -ENOMEM; - } - - *ep_path = p; - } - - return fd; -} - int bus_kernel_try_close(sd_bus *bus) { struct kdbus_cmd byebye = { .size = sizeof(byebye) }; diff --git a/src/test/test-ns.c b/src/test/test-ns.c index cf627be6c5..9248f2987c 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -68,7 +68,6 @@ int main(int argc, char *argv[]) { (char **) inaccessible, tmp_dir, var_tmp_dir, - NULL, true, PROTECT_HOME_NO, PROTECT_SYSTEM_NO, -- cgit v1.2.3-54-g00ecf From c629ff587b19295d638710e4fa42b96da7b42123 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 12 Feb 2016 00:26:37 +0100 Subject: Typo fixes --- man/systemd.swap.xml | 2 +- src/resolve/resolved-dns-answer.h | 2 +- src/resolve/resolved-dns-dnssec.c | 6 +++--- src/resolve/resolved-dns-transaction.c | 2 +- src/shared/dns-domain.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml index c600405c87..69d4be4769 100644 --- a/man/systemd.swap.xml +++ b/man/systemd.swap.xml @@ -72,7 +72,7 @@ project='man-pages'>swapon8 binary is executed in, in systemd.kill5, - which define the way the these processes are + which define the way these processes are terminated, and in systemd.resource-control5, which configure resource control settings for these processes of the diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 8f9c15eab4..0679c610f5 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -30,7 +30,7 @@ typedef struct DnsAnswerItem DnsAnswerItem; * can qualify A and AAAA RRs referring to a local link with the * right ifindex. * - * Note that we usually encode the the empty DnsAnswer object as a simple NULL. */ + * Note that we usually encode the empty DnsAnswer object as a simple NULL. */ typedef enum DnsAnswerFlags { DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */ diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 7123d2d3a8..7aea9cb653 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -635,9 +635,9 @@ int dnssec_verify_rrset( assert(rrsig->key->type == DNS_TYPE_RRSIG); assert(dnskey->key->type == DNS_TYPE_DNSKEY); - /* Verifies the the RRSet matching the specified "key" in "a", + /* Verifies that the RRSet matches the specified "key" in "a", * using the signature "rrsig" and the key "dnskey". It's - * assumed the RRSIG and DNSKEY match. */ + * assumed that RRSIG and DNSKEY match. */ md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm); if (md_algorithm == -EOPNOTSUPP) { @@ -1989,7 +1989,7 @@ static int dnssec_test_positive_wildcard_nsec3( /* Run a positive NSEC3 wildcard proof. Specifically: * - * A proof that the the "next closer" of the generating wildcard does not exist. + * A proof that the "next closer" of the generating wildcard does not exist. * * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index d48fdd1281..060c430f3a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1678,7 +1678,7 @@ static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const assert(t); - /* Check whether the specified name is in the the NTA + /* Check whether the specified name is in the NTA * database, either in the global one, or the link-local * one. */ diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 45d24c0079..0fc2a31f04 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -331,7 +331,7 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded l = strlen(buffer); - /* Verify that the the result is not longer than one DNS label. */ + /* Verify that the result is not longer than one DNS label. */ if (l <= 0 || l > DNS_LABEL_MAX) return -EINVAL; if (l > decoded_max) -- cgit v1.2.3-54-g00ecf From ee7dca21f70e4a82c56180e9f9a4dbe0f8c6a4c6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 11 Feb 2016 21:52:02 -0500 Subject: Typo --- src/systemd/sd-login.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index 3c10ff032f..e3ecbd8378 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -108,7 +108,7 @@ int sd_peer_get_slice(int fd, char **slice); int sd_peer_get_user_slice(int fd, char **slice); /* Similar to sd_pid_get_machine_name(), but retrieves data about the - * peer of a a connected AF_UNIX socket */ + * peer of a connected AF_UNIX socket */ int sd_peer_get_machine_name(int fd, char **machine); /* Similar to sd_pid_get_cgroup(), but retrieves data about the peer -- cgit v1.2.3-54-g00ecf From 798c486fbcdce3346cd862c52e1a200bb8a2cb23 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 12 Feb 2016 15:25:27 +0100 Subject: remove bus-proxyd As kdbus won't land in the anticipated way, the bus-proxy is not needed in its current form. It can be resurrected at any time thanks to the history, but for now, let's remove it from the sources. If we'll have a similar tool in the future, it will look quite differently anyway. Note that stdio-bridge is still available. It was restored from a version prior to f252ff17, and refactored to make use of the current APIs. --- .gitignore | 2 - Makefile-man.am | 9 - Makefile.am | 70 +- README | 3 - TODO | 4 - man/busctl.xml | 1 - man/systemd-bus-proxyd.service.xml | 80 -- man/systemd-bus-proxyd.xml | 108 --- src/bus-proxyd/Makefile | 1 - src/bus-proxyd/bus-proxyd.c | 328 -------- src/bus-proxyd/bus-xml-policy.c | 1327 ------------------------------ src/bus-proxyd/bus-xml-policy.h | 147 ---- src/bus-proxyd/driver.c | 745 ----------------- src/bus-proxyd/driver.h | 27 - src/bus-proxyd/proxy.c | 953 --------------------- src/bus-proxyd/proxy.h | 66 -- src/bus-proxyd/stdio-bridge.c | 244 ------ src/bus-proxyd/synthesize.c | 225 ----- src/bus-proxyd/synthesize.h | 36 - src/bus-proxyd/test-bus-xml-policy.c | 170 ---- src/libsystemd/sd-bus/test-bus-proxy.c | 117 --- src/stdio-bridge/stdio-bridge.c | 301 +++++++ src/test/test-tables.c | 3 - sysusers.d/systemd.conf.m4 | 1 - units/.gitignore | 2 - units/systemd-bus-proxyd.service.m4.in | 25 - units/systemd-bus-proxyd.socket | 12 - units/user/.gitignore | 1 - units/user/systemd-bus-proxyd.service.in | 14 - units/user/systemd-bus-proxyd.socket | 12 - 30 files changed, 303 insertions(+), 4731 deletions(-) delete mode 100644 man/systemd-bus-proxyd.service.xml delete mode 100644 man/systemd-bus-proxyd.xml delete mode 120000 src/bus-proxyd/Makefile delete mode 100644 src/bus-proxyd/bus-proxyd.c delete mode 100644 src/bus-proxyd/bus-xml-policy.c delete mode 100644 src/bus-proxyd/bus-xml-policy.h delete mode 100644 src/bus-proxyd/driver.c delete mode 100644 src/bus-proxyd/driver.h delete mode 100644 src/bus-proxyd/proxy.c delete mode 100644 src/bus-proxyd/proxy.h delete mode 100644 src/bus-proxyd/stdio-bridge.c delete mode 100644 src/bus-proxyd/synthesize.c delete mode 100644 src/bus-proxyd/synthesize.h delete mode 100644 src/bus-proxyd/test-bus-xml-policy.c delete mode 100644 src/libsystemd/sd-bus/test-bus-proxy.c create mode 100644 src/stdio-bridge/stdio-bridge.c delete mode 100644 units/systemd-bus-proxyd.service.m4.in delete mode 100644 units/systemd-bus-proxyd.socket delete mode 100644 units/user/systemd-bus-proxyd.service.in delete mode 100644 units/user/systemd-bus-proxyd.socket (limited to 'src') diff --git a/.gitignore b/.gitignore index 586b3796b1..47fdb2b7d7 100644 --- a/.gitignore +++ b/.gitignore @@ -59,7 +59,6 @@ /systemd-binfmt /systemd-bootchart /systemd-bootx64.efi -/systemd-bus-proxyd /systemd-cat /systemd-cgls /systemd-cgroups-agent @@ -157,7 +156,6 @@ /test-bus-match /test-bus-objects /test-bus-policy -/test-bus-proxy /test-bus-server /test-bus-signature /test-bus-zero-copy diff --git a/Makefile-man.am b/Makefile-man.am index 28b5fb6adb..92bc13e449 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -98,8 +98,6 @@ MANPAGES += \ man/systemd-analyze.1 \ man/systemd-ask-password-console.service.8 \ man/systemd-ask-password.1 \ - man/systemd-bus-proxyd.8 \ - man/systemd-bus-proxyd.service.8 \ man/systemd-cat.1 \ man/systemd-cgls.1 \ man/systemd-cgtop.1 \ @@ -421,7 +419,6 @@ MANPAGES_ALIAS += \ man/systemd-ask-password-console.path.8 \ man/systemd-ask-password-wall.path.8 \ man/systemd-ask-password-wall.service.8 \ - man/systemd-bus-proxyd.socket.8 \ man/systemd-fsck-root.service.8 \ man/systemd-fsck.8 \ man/systemd-hibernate-resume.8 \ @@ -751,7 +748,6 @@ man/system.conf.d.5: man/systemd-system.conf.5 man/systemd-ask-password-console.path.8: man/systemd-ask-password-console.service.8 man/systemd-ask-password-wall.path.8: man/systemd-ask-password-console.service.8 man/systemd-ask-password-wall.service.8: man/systemd-ask-password-console.service.8 -man/systemd-bus-proxyd.socket.8: man/systemd-bus-proxyd.service.8 man/systemd-fsck-root.service.8: man/systemd-fsck@.service.8 man/systemd-fsck.8: man/systemd-fsck@.service.8 man/systemd-hibernate-resume.8: man/systemd-hibernate-resume@.service.8 @@ -1571,9 +1567,6 @@ man/systemd-ask-password-wall.path.html: man/systemd-ask-password-console.servic man/systemd-ask-password-wall.service.html: man/systemd-ask-password-console.service.html $(html-alias) -man/systemd-bus-proxyd.socket.html: man/systemd-bus-proxyd.service.html - $(html-alias) - man/systemd-fsck-root.service.html: man/systemd-fsck@.service.html $(html-alias) @@ -2581,8 +2574,6 @@ EXTRA_DIST += \ man/systemd-backlight@.service.xml \ man/systemd-binfmt.service.xml \ man/systemd-bootchart.xml \ - man/systemd-bus-proxyd.service.xml \ - man/systemd-bus-proxyd.xml \ man/systemd-cat.xml \ man/systemd-cgls.xml \ man/systemd-cgtop.xml \ diff --git a/Makefile.am b/Makefile.am index 5a8fc2fe23..32ac66275a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -411,7 +411,6 @@ rootlibexec_PROGRAMS = \ systemd-ac-power \ systemd-sysctl \ systemd-sleep \ - systemd-bus-proxyd \ systemd-socket-proxyd \ systemd-update-done @@ -1488,7 +1487,6 @@ tests += \ test-ratelimit \ test-condition \ test-uid-range \ - test-bus-policy \ test-locale-util \ test-execute \ test-copy \ @@ -1961,14 +1959,11 @@ test_unaligned_SOURCES = \ test_tables_SOURCES = \ src/test/test-tables.c \ src/shared/test-tables.h \ - src/bus-proxyd/bus-xml-policy.c \ - src/bus-proxyd/bus-xml-policy.h \ src/journal/journald-server.c \ src/journal/journald-server.h test_tables_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -I$(top_srcdir)/src/bus-proxyd + $(AM_CPPFLAGS) test_tables_CFLAGS = \ $(AM_CFLAGS) \ @@ -2209,13 +2204,6 @@ test_conf_parser_SOURCES = \ test_conf_parser_LDADD = \ libshared.la -test_bus_policy_SOURCES = \ - src/bus-proxyd/test-bus-xml-policy.c - -test_bus_policy_LDADD = \ - libbus-proxy-core.la \ - libshared.la - test_af_list_SOURCES = \ src/test/test-af-list.c @@ -2980,59 +2968,12 @@ systemd_run_LDADD = \ libshared.la # ------------------------------------------------------------------------------ -noinst_LTLIBRARIES += \ - libbus-proxy-core.la - -libbus_proxy_core_la_SOURCES = \ - src/bus-proxyd/bus-xml-policy.c \ - src/bus-proxyd/bus-xml-policy.h \ - src/bus-proxyd/driver.c \ - src/bus-proxyd/driver.h \ - src/bus-proxyd/proxy.c \ - src/bus-proxyd/proxy.h \ - src/bus-proxyd/synthesize.c \ - src/bus-proxyd/synthesize.h - -libbus_proxy_core_la_LIBADD = \ - libshared.la - -systemd_bus_proxyd_SOURCES = \ - src/bus-proxyd/bus-proxyd.c - -systemd_bus_proxyd_LDADD = \ - libbus-proxy-core.la \ - libshared.la - systemd_stdio_bridge_SOURCES = \ - src/bus-proxyd/stdio-bridge.c + src/stdio-bridge/stdio-bridge.c systemd_stdio_bridge_LDADD = \ - libbus-proxy-core.la \ libshared.la -nodist_systemunit_DATA += \ - units/systemd-bus-proxyd.service - -dist_systemunit_DATA += \ - units/systemd-bus-proxyd.socket - -nodist_userunit_DATA += \ - units/user/systemd-bus-proxyd.service - -dist_userunit_DATA += \ - units/user/systemd-bus-proxyd.socket - -EXTRA_DIST += \ - units/systemd-bus-proxyd.service.m4.in \ - units/user/systemd-bus-proxyd.service.in - -if HAVE_SMACK -bus-proxyd-set-cap-hook: - -$(SETCAP) cap_mac_admin+ei $(DESTDIR)$(rootlibexecdir)/systemd-bus-proxyd - -INSTALL_EXEC_HOOKS += bus-proxyd-set-cap-hook -endif - # ------------------------------------------------------------------------------ systemd_tty_ask_password_agent_SOURCES = \ src/tty-ask-password-agent/tty-ask-password-agent.c @@ -3195,7 +3136,6 @@ tests += \ test-bus-cleanup \ test-bus-server \ test-bus-match \ - test-bus-proxy \ test-bus-kernel \ test-bus-kernel-bloom \ test-bus-zero-copy \ @@ -3288,12 +3228,6 @@ test_bus_match_SOURCES = \ test_bus_match_LDADD = \ libshared.la -test_bus_proxy_SOURCES = \ - src/libsystemd/sd-bus/test-bus-proxy.c - -test_bus_proxy_LDADD = \ - libshared.la - test_bus_kernel_SOURCES = \ src/libsystemd/sd-bus/test-bus-kernel.c diff --git a/README b/README index 0a2c0df47d..41fb07a298 100644 --- a/README +++ b/README @@ -200,9 +200,6 @@ USERS AND GROUPS: Similarly, the name resolution daemon requires the "systemd-resolve" system user and group to exist. - Similarly, the kdbus dbus1 proxy daemon requires the - "systemd-bus-proxy" system user and group to exist. - Similarly, the coredump support requires the "systemd-coredump" system user and group to exist. diff --git a/TODO b/TODO index 7437938bf0..e42bf27dae 100644 --- a/TODO +++ b/TODO @@ -321,10 +321,6 @@ Features: - path escaping - update systemd.special(7) to mention that dbus.socket is only about the compatibility socket now - test bloom filter generation indexes - - bus-proxy: when passing messages from kdbus, make sure we properly - handle the case where a large number of fds is appended that we - cannot pass into sendmsg() of the AF_UNIX sokcet (which only accepts - 253 messages) - kdbus: introduce a concept of "send-only" connections - kdbus: add counter for refused unicast messages that is passed out via the RECV ioctl. SImilar to the counter for dropped multicast messages we already have. diff --git a/man/busctl.xml b/man/busctl.xml index 26d778d4dd..b71a174634 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -473,7 +473,6 @@ o "/org/freedesktop/systemd1/job/42684" D-Bus, sd-bus3, systemd1, - systemd-bus-proxyd8, machinectl1, wireshark1 diff --git a/man/systemd-bus-proxyd.service.xml b/man/systemd-bus-proxyd.service.xml deleted file mode 100644 index 02189eea7c..0000000000 --- a/man/systemd-bus-proxyd.service.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - systemd-bus-proxyd.service - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemd-bus-proxyd.service - 8 - - - - systemd-bus-proxyd.service - systemd-bus-proxyd.socket - Proxy classic D-Bus clients to kdbus - - - - systemd-bus-proxyd.service - systemd-bus-proxyd.socket - - - - Description - - systemd-bus-proxyd.socket will launch - systemd-bus-proxyd.service for connections - to the classic D-Bus socket in - /var/run/dbus/system_bus_socket. - - systemd-bus-proxyd.service is launched - for an existing D-Bus connection and will use - systemd-bus-proxyd to proxy messages from this - connection to the system bus (either kdbus or classic D-Bus). - - - - - See Also - - - systemd-bus-proxyd8, - dbus-daemon1, - D-Bus - - - diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml deleted file mode 100644 index 0923396151..0000000000 --- a/man/systemd-bus-proxyd.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - systemd-bus-proxyd - systemd - - - - Developer - Lennart - Poettering - lennart@poettering.net - - - - - - systemd-bus-proxyd - 8 - - - - systemd-bus-proxyd - Connect STDIO or a socket to a given bus address - - - - - /usr/lib/systemd/systemd-bus-proxyd - OPTIONS - PLACEHOLDER - - - - - Description - - systemd-bus-proxyd will proxy D-Bus - messages to and from a bus. The will be either the system bus or - the bus specified with when that option - is given. Messages will be proxied to/from standard input and - output, or the socket received through socket activation. - - This program can be used to connect a program using classic - D-Bus to kdbus. - - - - Options and Arguments - - The following options are understood: - - - - - - - Connect to the bus specified by - ADDRESS. Multiple colon-separated - addresses can be specified, in which case - systemd-bus-proxyd will attempt to - connect to them in turn. - - - - - - - - PLACEHOLDER, if given, must be a string - of x and will be used to display information about - the process that systemd-bus-proxyd is forwarding - messages for. - - - - See Also - - - dbus-daemon1, - D-Bus - - - diff --git a/src/bus-proxyd/Makefile b/src/bus-proxyd/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/bus-proxyd/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile \ No newline at end of file diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c deleted file mode 100644 index b6bd6eb390..0000000000 --- a/src/bus-proxyd/bus-proxyd.c +++ /dev/null @@ -1,328 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 Kay Sievers - Copyright 2015 David Herrmann - - 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 . -***/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sd-daemon.h" - -#include "alloc-util.h" -#include "bus-internal.h" -#include "bus-xml-policy.h" -#include "capability-util.h" -#include "def.h" -#include "fd-util.h" -#include "formats-util.h" -#include "log.h" -#include "proxy.h" -#include "string-util.h" -#include "strv.h" -#include "user-util.h" -#include "util.h" - -static char *arg_address = NULL; -static char **arg_configuration = NULL; - -typedef struct { - int fd; - SharedPolicy *policy; - uid_t bus_uid; -} ClientContext; - -static ClientContext *client_context_free(ClientContext *c) { - if (!c) - return NULL; - - safe_close(c->fd); - free(c); - - return NULL; -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free); - -static int client_context_new(ClientContext **out) { - _cleanup_(client_context_freep) ClientContext *c = NULL; - - c = new0(ClientContext, 1); - if (!c) - return -ENOMEM; - - c->fd = -1; - - *out = c; - c = NULL; - return 0; -} - -static void *run_client(void *userdata) { - _cleanup_(client_context_freep) ClientContext *c = userdata; - _cleanup_(proxy_freep) Proxy *p = NULL; - char comm[16]; - int r; - - r = proxy_new(&p, c->fd, c->fd, arg_address); - c->fd = -1; - - if (r < 0) - goto exit; - - /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */ - r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid); - if (r >= (ssize_t)sizeof(comm)) - comm[sizeof(comm) - 2] = '*'; - (void) prctl(PR_SET_NAME, comm); - - r = proxy_set_policy(p, c->policy, arg_configuration); - if (r < 0) - goto exit; - - r = proxy_hello_policy(p, c->bus_uid); - if (r < 0) - goto exit; - - r = proxy_run(p); - -exit: - return NULL; -} - -static int loop_clients(int accept_fd, uid_t bus_uid) { - _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL; - pthread_attr_t attr; - int r; - - r = pthread_attr_init(&attr); - if (r != 0) - return log_error_errno(r, "Cannot initialize pthread attributes: %m"); - - r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (r != 0) { - r = log_error_errno(r, "Cannot mark pthread attributes as detached: %m"); - goto finish; - } - - r = shared_policy_new(&sp); - if (r < 0) - goto finish; - - for (;;) { - ClientContext *c; - pthread_t tid; - int fd; - - fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC); - if (fd < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - - r = log_error_errno(errno, "accept4() failed: %m"); - goto finish; - } - - r = client_context_new(&c); - if (r < 0) { - log_oom(); - close(fd); - continue; - } - - c->fd = fd; - c->policy = sp; - c->bus_uid = bus_uid; - - r = pthread_create(&tid, &attr, run_client, c); - if (r != 0) { - log_warning_errno(r, "Cannot spawn thread, ignoring: %m"); - client_context_free(c); - continue; - } - } - -finish: - pthread_attr_destroy(&attr); - return r; -} - -static int help(void) { - - printf("%s [OPTIONS...]\n\n" - "DBus proxy server.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --configuration=PATH Configuration file or directory\n" - " --machine=MACHINE Connect to specified machine\n" - " --address=ADDRESS Connect to the bus specified by ADDRESS\n" - " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_ADDRESS, - ARG_CONFIGURATION, - ARG_MACHINE, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "address", required_argument, NULL, ARG_ADDRESS }, - { "configuration", required_argument, NULL, ARG_CONFIGURATION }, - { "machine", required_argument, NULL, ARG_MACHINE }, - {}, - }; - - int c, r; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - return version(); - - case ARG_ADDRESS: - r = free_and_strdup(&arg_address, optarg); - if (r < 0) - return log_oom(); - break; - - case ARG_CONFIGURATION: - r = strv_extend(&arg_configuration, optarg); - if (r < 0) - return log_oom(); - break; - - case ARG_MACHINE: { - _cleanup_free_ char *e = NULL; - char *a; - - e = bus_address_escape(optarg); - if (!e) - return log_oom(); - - a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); - if (!a) - return log_oom(); - - free(arg_address); - arg_address = a; - - break; - } - - case '?': - return -EINVAL; - - default: - assert_not_reached("Unhandled option"); - } - - if (argc > optind) { - log_error("Too many arguments"); - return -EINVAL; - } - - if (!arg_address) { - arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); - if (!arg_address) - return log_oom(); - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r, accept_fd; - uid_t uid, bus_uid; - gid_t gid; - - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); - log_parse_environment(); - log_open(); - - bus_uid = getuid(); - - if (geteuid() == 0) { - const char *user = "systemd-bus-proxy"; - - r = get_user_creds(&user, &uid, &gid, NULL, NULL); - if (r < 0) { - log_error_errno(r, "Cannot resolve user name %s: %m", user); - goto finish; - } - - r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER); - if (r < 0) { - log_error_errno(r, "Cannot drop privileges: %m"); - goto finish; - } - } - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - r = sd_listen_fds(0); - if (r != 1) { - log_error("Illegal number of file descriptors passed"); - goto finish; - } - - accept_fd = SD_LISTEN_FDS_START; - - r = fd_nonblock(accept_fd, false); - if (r < 0) { - log_error_errno(r, "Cannot mark accept-fd non-blocking: %m"); - goto finish; - } - - r = loop_clients(accept_fd, bus_uid); - -finish: - sd_notify(false, - "STOPPING=1\n" - "STATUS=Shutting down."); - - strv_free(arg_configuration); - free(arg_address); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c deleted file mode 100644 index 8943e0dc12..0000000000 --- a/src/bus-proxyd/bus-xml-policy.c +++ /dev/null @@ -1,1327 +0,0 @@ -/*** - This file is part of systemd. - - 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 - 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 . -***/ - -#include "sd-login.h" - -#include "alloc-util.h" -#include "bus-internal.h" -#include "bus-xml-policy.h" -#include "conf-files.h" -#include "fileio.h" -#include "formats-util.h" -#include "locale-util.h" -#include "set.h" -#include "string-table.h" -#include "string-util.h" -#include "strv.h" -#include "user-util.h" -#include "xml.h" - -static void policy_item_free(PolicyItem *i) { - assert(i); - - free(i->interface); - free(i->member); - free(i->error); - free(i->name); - free(i->path); - free(i); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free); - -static void item_append(PolicyItem *i, PolicyItem **list) { - - PolicyItem *tail; - - LIST_FIND_TAIL(items, *list, tail); - LIST_INSERT_AFTER(items, *list, tail, i); -} - -static int file_load(Policy *p, const char *path) { - - _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL; - _cleanup_(policy_item_freep) PolicyItem *i = NULL; - void *xml_state = NULL; - unsigned n_other = 0; - const char *q; - int r; - - enum { - STATE_OUTSIDE, - STATE_BUSCONFIG, - STATE_POLICY, - STATE_POLICY_CONTEXT, - STATE_POLICY_CONSOLE, - STATE_POLICY_USER, - STATE_POLICY_GROUP, - STATE_POLICY_OTHER_ATTRIBUTE, - STATE_ALLOW_DENY, - STATE_ALLOW_DENY_INTERFACE, - STATE_ALLOW_DENY_MEMBER, - STATE_ALLOW_DENY_ERROR, - STATE_ALLOW_DENY_PATH, - STATE_ALLOW_DENY_MESSAGE_TYPE, - STATE_ALLOW_DENY_NAME, - STATE_ALLOW_DENY_OTHER_ATTRIBUTE, - STATE_OTHER, - } state = STATE_OUTSIDE; - - enum { - POLICY_CATEGORY_NONE, - POLICY_CATEGORY_DEFAULT, - POLICY_CATEGORY_MANDATORY, - POLICY_CATEGORY_ON_CONSOLE, - POLICY_CATEGORY_NO_CONSOLE, - POLICY_CATEGORY_USER, - POLICY_CATEGORY_GROUP - } policy_category = POLICY_CATEGORY_NONE; - - unsigned line = 0; - - assert(p); - - r = read_full_file(path, &c, NULL); - if (r < 0) { - if (r == -ENOENT) - return 0; - if (r == -EISDIR) - return r; - - return log_error_errno(r, "Failed to load %s: %m", path); - } - - q = c; - for (;;) { - _cleanup_free_ char *name = NULL; - int t; - - t = xml_tokenize(&q, &name, &xml_state, &line); - if (t < 0) - return log_error_errno(t, "XML parse failure in %s: %m", path); - - switch (state) { - - case STATE_OUTSIDE: - - if (t == XML_TAG_OPEN) { - if (streq(name, "busconfig")) - state = STATE_BUSCONFIG; - else { - log_error("Unexpected tag %s at %s:%u.", name, path, line); - return -EINVAL; - } - - } else if (t == XML_END) - return 0; - else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (1) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_BUSCONFIG: - - if (t == XML_TAG_OPEN) { - if (streq(name, "policy")) { - state = STATE_POLICY; - policy_category = POLICY_CATEGORY_NONE; - free(policy_user); - free(policy_group); - policy_user = policy_group = NULL; - } else { - state = STATE_OTHER; - n_other = 0; - } - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, "busconfig"))) - state = STATE_OUTSIDE; - else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (2) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY: - - if (t == XML_ATTRIBUTE_NAME) { - if (streq(name, "context")) - state = STATE_POLICY_CONTEXT; - else if (streq(name, "at_console")) - state = STATE_POLICY_CONSOLE; - else if (streq(name, "user")) - state = STATE_POLICY_USER; - else if (streq(name, "group")) - state = STATE_POLICY_GROUP; - else { - log_warning("Attribute %s of tag unknown at %s:%u, ignoring.", name, path, line); - state = STATE_POLICY_OTHER_ATTRIBUTE; - } - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, "policy"))) - state = STATE_BUSCONFIG; - else if (t == XML_TAG_OPEN) { - PolicyItemType it; - - if (streq(name, "allow")) - it = POLICY_ITEM_ALLOW; - else if (streq(name, "deny")) - it = POLICY_ITEM_DENY; - else { - log_warning("Unknown tag %s in %s:%u.", name, path, line); - return -EINVAL; - } - - assert(!i); - i = new0(PolicyItem, 1); - if (!i) - return log_oom(); - - i->type = it; - state = STATE_ALLOW_DENY; - - } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (3) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_CONTEXT: - - if (t == XML_ATTRIBUTE_VALUE) { - if (streq(name, "default")) { - policy_category = POLICY_CATEGORY_DEFAULT; - state = STATE_POLICY; - } else if (streq(name, "mandatory")) { - policy_category = POLICY_CATEGORY_MANDATORY; - state = STATE_POLICY; - } else { - log_error("context= parameter %s unknown for at %s:%u.", name, path, line); - return -EINVAL; - } - } else { - log_error("Unexpected token (4) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_CONSOLE: - - if (t == XML_ATTRIBUTE_VALUE) { - if (streq(name, "true")) { - policy_category = POLICY_CATEGORY_ON_CONSOLE; - state = STATE_POLICY; - } else if (streq(name, "false")) { - policy_category = POLICY_CATEGORY_NO_CONSOLE; - state = STATE_POLICY; - } else { - log_error("at_console= parameter %s unknown for at %s:%u.", name, path, line); - return -EINVAL; - } - } else { - log_error("Unexpected token (4.1) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_USER: - - if (t == XML_ATTRIBUTE_VALUE) { - free(policy_user); - policy_user = name; - name = NULL; - policy_category = POLICY_CATEGORY_USER; - state = STATE_POLICY; - } else { - log_error("Unexpected token (5) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_GROUP: - - if (t == XML_ATTRIBUTE_VALUE) { - free(policy_group); - policy_group = name; - name = NULL; - policy_category = POLICY_CATEGORY_GROUP; - state = STATE_POLICY; - } else { - log_error("Unexpected token (6) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_POLICY_OTHER_ATTRIBUTE: - - if (t == XML_ATTRIBUTE_VALUE) - state = STATE_POLICY; - else { - log_error("Unexpected token (7) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY: - - assert(i); - - if (t == XML_ATTRIBUTE_NAME) { - PolicyItemClass ic; - - if (startswith(name, "send_")) - ic = POLICY_ITEM_SEND; - else if (startswith(name, "receive_")) - ic = POLICY_ITEM_RECV; - else if (streq(name, "own")) - ic = POLICY_ITEM_OWN; - else if (streq(name, "own_prefix")) - ic = POLICY_ITEM_OWN_PREFIX; - else if (streq(name, "user")) - ic = POLICY_ITEM_USER; - else if (streq(name, "group")) - ic = POLICY_ITEM_GROUP; - else if (STR_IN_SET(name, "eavesdrop", "log")) { - log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } else { - log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } - - if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) { - log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line); - return -EINVAL; - } - - i->class = ic; - - if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) { - const char *u; - - u = strchr(name, '_'); - assert(u); - - u++; - - if (streq(u, "interface")) - state = STATE_ALLOW_DENY_INTERFACE; - else if (streq(u, "member")) - state = STATE_ALLOW_DENY_MEMBER; - else if (streq(u, "error")) - state = STATE_ALLOW_DENY_ERROR; - else if (streq(u, "path")) - state = STATE_ALLOW_DENY_PATH; - else if (streq(u, "type")) - state = STATE_ALLOW_DENY_MESSAGE_TYPE; - else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) || - (streq(u, "sender") && ic == POLICY_ITEM_RECV)) - state = STATE_ALLOW_DENY_NAME; - else { - if (streq(u, "requested_reply")) - log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line); - else - log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line); - state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE; - break; - } - } else - state = STATE_ALLOW_DENY_NAME; - - } else if (t == XML_TAG_CLOSE_EMPTY || - (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) { - - /* If the tag is fully empty so far, we consider it a recv */ - if (i->class == _POLICY_ITEM_CLASS_UNSET) - i->class = POLICY_ITEM_RECV; - - if (policy_category == POLICY_CATEGORY_DEFAULT) - item_append(i, &p->default_items); - else if (policy_category == POLICY_CATEGORY_MANDATORY) - item_append(i, &p->mandatory_items); - else if (policy_category == POLICY_CATEGORY_ON_CONSOLE) - item_append(i, &p->on_console_items); - else if (policy_category == POLICY_CATEGORY_NO_CONSOLE) - item_append(i, &p->no_console_items); - else if (policy_category == POLICY_CATEGORY_USER) { - const char *u = policy_user; - - assert_cc(sizeof(uid_t) == sizeof(uint32_t)); - - r = hashmap_ensure_allocated(&p->user_items, NULL); - if (r < 0) - return log_oom(); - - if (!u) { - log_error("User policy without name"); - return -EINVAL; - } - - r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); - if (r < 0) { - log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u); - free(i); - } else { - PolicyItem *first; - - first = hashmap_get(p->user_items, UID_TO_PTR(i->uid)); - item_append(i, &first); - i->uid_valid = true; - - r = hashmap_replace(p->user_items, UID_TO_PTR(i->uid), first); - if (r < 0) { - LIST_REMOVE(items, first, i); - return log_oom(); - } - } - - } else if (policy_category == POLICY_CATEGORY_GROUP) { - const char *g = policy_group; - - assert_cc(sizeof(gid_t) == sizeof(uint32_t)); - - r = hashmap_ensure_allocated(&p->group_items, NULL); - if (r < 0) - return log_oom(); - - if (!g) { - log_error("Group policy without name"); - return -EINVAL; - } - - r = get_group_creds(&g, &i->gid); - if (r < 0) { - log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g); - free(i); - } else { - PolicyItem *first; - - first = hashmap_get(p->group_items, GID_TO_PTR(i->gid)); - item_append(i, &first); - i->gid_valid = true; - - r = hashmap_replace(p->group_items, GID_TO_PTR(i->gid), first); - if (r < 0) { - LIST_REMOVE(items, first, i); - return log_oom(); - } - } - } - - state = STATE_POLICY; - i = NULL; - - } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) { - log_error("Unexpected token (8) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_INTERFACE: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->interface) { - log_error("Duplicate interface at %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->interface = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (9) at %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_MEMBER: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->member) { - log_error("Duplicate member in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->member = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (10) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_ERROR: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->error) { - log_error("Duplicate error in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->error = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (11) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_PATH: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->path) { - log_error("Duplicate path in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - i->path = name; - name = NULL; - } - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (12) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_MESSAGE_TYPE: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - - if (i->message_type != 0) { - log_error("Duplicate message type in %s:%u.", path, line); - return -EINVAL; - } - - if (!streq(name, "*")) { - r = bus_message_type_from_string(name, &i->message_type); - if (r < 0) { - log_error("Invalid message type in %s:%u.", path, line); - return -EINVAL; - } - } - - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (13) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_NAME: - - if (t == XML_ATTRIBUTE_VALUE) { - assert(i); - if (i->name) { - log_error("Duplicate name in %s:%u.", path, line); - return -EINVAL; - } - - switch (i->class) { - case POLICY_ITEM_USER: - if (!streq(name, "*")) { - const char *u = name; - - r = get_user_creds(&u, &i->uid, NULL, NULL, NULL); - if (r < 0) - log_error_errno(r, "Failed to resolve user %s: %m", name); - else - i->uid_valid = true; - } - break; - case POLICY_ITEM_GROUP: - if (!streq(name, "*")) { - const char *g = name; - - r = get_group_creds(&g, &i->gid); - if (r < 0) - log_error_errno(r, "Failed to resolve group %s: %m", name); - else - i->gid_valid = true; - } - break; - - case POLICY_ITEM_SEND: - case POLICY_ITEM_RECV: - - if (streq(name, "*")) - name = mfree(name); - break; - - - default: - break; - } - - i->name = name; - name = NULL; - - state = STATE_ALLOW_DENY; - } else { - log_error("Unexpected token (14) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_ALLOW_DENY_OTHER_ATTRIBUTE: - - if (t == XML_ATTRIBUTE_VALUE) - state = STATE_ALLOW_DENY; - else { - log_error("Unexpected token (15) in %s:%u.", path, line); - return -EINVAL; - } - - break; - - case STATE_OTHER: - - if (t == XML_TAG_OPEN) - n_other++; - else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) { - - if (n_other == 0) - state = STATE_BUSCONFIG; - else - n_other--; - } - - break; - } - } -} - -enum { - DENY, - ALLOW, - DUNNO, -}; - -static const char *verdict_to_string(int v) { - switch (v) { - - case DENY: - return "DENY"; - case ALLOW: - return "ALLOW"; - case DUNNO: - return "DUNNO"; - } - - return NULL; -} - -struct policy_check_filter { - PolicyItemClass class; - uid_t uid; - gid_t gid; - int message_type; - const char *name; - const char *interface; - const char *path; - const char *member; -}; - -static int is_permissive(PolicyItem *i) { - - assert(i); - - return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY; -} - -static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) { - - assert(i); - assert(filter); - - switch (i->class) { - case POLICY_ITEM_SEND: - case POLICY_ITEM_RECV: - - if (i->name && !streq_ptr(i->name, filter->name)) - break; - - if ((i->message_type != 0) && (i->message_type != filter->message_type)) - break; - - if (i->path && !streq_ptr(i->path, filter->path)) - break; - - if (i->member && !streq_ptr(i->member, filter->member)) - break; - - if (i->interface && !streq_ptr(i->interface, filter->interface)) - break; - - return is_permissive(i); - - case POLICY_ITEM_OWN: - assert(filter->name); - - if (streq(i->name, "*") || streq(i->name, filter->name)) - return is_permissive(i); - break; - - case POLICY_ITEM_OWN_PREFIX: - assert(filter->name); - - if (streq(i->name, "*") || service_name_startswith(filter->name, i->name)) - return is_permissive(i); - break; - - case POLICY_ITEM_USER: - if (filter->uid != UID_INVALID) - if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid))) - return is_permissive(i); - break; - - case POLICY_ITEM_GROUP: - if (filter->gid != GID_INVALID) - if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid))) - return is_permissive(i); - break; - - case POLICY_ITEM_IGNORE: - default: - break; - } - - return DUNNO; -} - -static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) { - - PolicyItem *i; - int verdict = DUNNO; - - assert(filter); - - /* Check all policies in a set - a broader one might be followed by a more specific one, - * and the order of rules in policy definitions matters */ - LIST_FOREACH(items, i, items) { - int v; - - if (i->class != filter->class && - !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN)) - continue; - - v = check_policy_item(i, filter); - if (v != DUNNO) - verdict = v; - } - - return verdict; -} - -static int policy_check(Policy *p, const struct policy_check_filter *filter) { - - PolicyItem *items; - int verdict, v; - - assert(p); - assert(filter); - - assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP)); - - /* - * The policy check is implemented by the following logic: - * - * 1. Check default items - * 2. Check group items - * 3. Check user items - * 4. Check on/no_console items - * 5. Check mandatory items - * - * Later rules override earlier rules. - */ - - verdict = check_policy_items(p->default_items, filter); - - if (filter->gid != GID_INVALID) { - items = hashmap_get(p->group_items, GID_TO_PTR(filter->gid)); - if (items) { - v = check_policy_items(items, filter); - if (v != DUNNO) - verdict = v; - } - } - - if (filter->uid != UID_INVALID) { - items = hashmap_get(p->user_items, UID_TO_PTR(filter->uid)); - if (items) { - v = check_policy_items(items, filter); - if (v != DUNNO) - verdict = v; - } - } - - if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0) - v = check_policy_items(p->on_console_items, filter); - else - v = check_policy_items(p->no_console_items, filter); - if (v != DUNNO) - verdict = v; - - v = check_policy_items(p->mandatory_items, filter); - if (v != DUNNO) - verdict = v; - - return verdict; -} - -bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_OWN, - .uid = uid, - .gid = gid, - .name = name, - }; - - int verdict; - - assert(p); - assert(name); - - verdict = policy_check(p, &filter); - - log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), - "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s", - uid, gid, strna(name), strna(verdict_to_string(verdict))); - - return verdict == ALLOW; -} - -bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) { - - struct policy_check_filter filter = { - .uid = uid, - .gid = gid, - }; - int verdict; - - assert(p); - - filter.class = POLICY_ITEM_USER; - verdict = policy_check(p, &filter); - - if (verdict != DENY) { - int v; - - filter.class = POLICY_ITEM_GROUP; - v = policy_check(p, &filter); - if (v != DUNNO) - verdict = v; - } - - log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG), - "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s", - uid, gid, strna(verdict_to_string(verdict))); - - return verdict == ALLOW; -} - -bool policy_check_one_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_RECV, - .uid = uid, - .gid = gid, - .message_type = message_type, - .name = name, - .interface = interface, - .path = path, - .member = member, - }; - - assert(p); - - return policy_check(p, &filter) == ALLOW; -} - -bool policy_check_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel) { - - char *n, **nv, *last = NULL; - bool allow = false; - Iterator i; - - assert(p); - - if (set_isempty(names) && strv_isempty(namesv)) { - allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member); - } else { - SET_FOREACH(n, names, i) { - last = n; - allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member); - if (allow) - break; - } - if (!allow) { - STRV_FOREACH(nv, namesv) { - last = *nv; - allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member); - if (allow) - break; - } - } - } - - log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), - "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", - dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), - strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); - - return allow; -} - -bool policy_check_one_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member) { - - struct policy_check_filter filter = { - .class = POLICY_ITEM_SEND, - .uid = uid, - .gid = gid, - .message_type = message_type, - .name = name, - .interface = interface, - .path = path, - .member = member, - }; - - assert(p); - - return policy_check(p, &filter) == ALLOW; -} - -bool policy_check_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel, - char **out_used_name) { - - char *n, **nv, *last = NULL; - bool allow = false; - Iterator i; - - assert(p); - - if (set_isempty(names) && strv_isempty(namesv)) { - allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member); - } else { - SET_FOREACH(n, names, i) { - last = n; - allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member); - if (allow) - break; - } - if (!allow) { - STRV_FOREACH(nv, namesv) { - last = *nv; - allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member); - if (allow) - break; - } - } - } - - if (out_used_name) - *out_used_name = last; - - log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG), - "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s", - dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last), - strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY"); - - return allow; -} - -int policy_load(Policy *p, char **files) { - char **i; - int r; - - assert(p); - - STRV_FOREACH(i, files) { - - r = file_load(p, *i); - if (r == -EISDIR) { - _cleanup_strv_free_ char **l = NULL; - char **j; - - r = conf_files_list(&l, ".conf", NULL, *i, NULL); - if (r < 0) - return log_error_errno(r, "Failed to get configuration file list: %m"); - - STRV_FOREACH(j, l) - file_load(p, *j); - } - - /* We ignore all errors but EISDIR, and just proceed. */ - } - - return 0; -} - -void policy_free(Policy *p) { - PolicyItem *i, *first; - - if (!p) - return; - - while ((i = p->default_items)) { - LIST_REMOVE(items, p->default_items, i); - policy_item_free(i); - } - - while ((i = p->mandatory_items)) { - LIST_REMOVE(items, p->mandatory_items, i); - policy_item_free(i); - } - - while ((i = p->on_console_items)) { - LIST_REMOVE(items, p->on_console_items, i); - policy_item_free(i); - } - - while ((i = p->no_console_items)) { - LIST_REMOVE(items, p->no_console_items, i); - policy_item_free(i); - } - - while ((first = hashmap_steal_first(p->user_items))) { - - while ((i = first)) { - LIST_REMOVE(items, first, i); - policy_item_free(i); - } - } - - while ((first = hashmap_steal_first(p->group_items))) { - - while ((i = first)) { - LIST_REMOVE(items, first, i); - policy_item_free(i); - } - } - - hashmap_free(p->user_items); - hashmap_free(p->group_items); - - p->user_items = p->group_items = NULL; -} - -static void dump_items(PolicyItem *items, const char *prefix) { - - PolicyItem *i; - - if (!items) - return; - - if (!prefix) - prefix = ""; - - LIST_FOREACH(items, i, items) { - - printf("%sType: %s\n" - "%sClass: %s\n", - prefix, policy_item_type_to_string(i->type), - prefix, policy_item_class_to_string(i->class)); - - if (i->interface) - printf("%sInterface: %s\n", - prefix, i->interface); - - if (i->member) - printf("%sMember: %s\n", - prefix, i->member); - - if (i->error) - printf("%sError: %s\n", - prefix, i->error); - - if (i->path) - printf("%sPath: %s\n", - prefix, i->path); - - if (i->name) - printf("%sName: %s\n", - prefix, i->name); - - if (i->message_type != 0) - printf("%sMessage Type: %s\n", - prefix, bus_message_type_to_string(i->message_type)); - - if (i->uid_valid) { - _cleanup_free_ char *user; - - user = uid_to_name(i->uid); - - printf("%sUser: %s ("UID_FMT")\n", - prefix, strna(user), i->uid); - } - - if (i->gid_valid) { - _cleanup_free_ char *group; - - group = gid_to_name(i->gid); - - printf("%sGroup: %s ("GID_FMT")\n", - prefix, strna(group), i->gid); - } - printf("%s-\n", prefix); - } -} - -static void dump_hashmap_items(Hashmap *h) { - PolicyItem *i; - Iterator j; - void *k; - - HASHMAP_FOREACH_KEY(i, k, h, j) { - printf("\t%s Item for " UID_FMT ":\n", draw_special_char(DRAW_ARROW), PTR_TO_UID(k)); - dump_items(i, "\t\t"); - } -} - -void policy_dump(Policy *p) { - - printf("%s Default Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->default_items, "\t"); - - printf("%s Group Items:\n", draw_special_char(DRAW_ARROW)); - dump_hashmap_items(p->group_items); - - printf("%s User Items:\n", draw_special_char(DRAW_ARROW)); - dump_hashmap_items(p->user_items); - - printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->on_console_items, "\t"); - - printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->no_console_items, "\t"); - - printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW)); - dump_items(p->mandatory_items, "\t"); - - fflush(stdout); -} - -int shared_policy_new(SharedPolicy **out) { - SharedPolicy *sp; - int r; - - sp = new0(SharedPolicy, 1); - if (!sp) - return log_oom(); - - r = pthread_mutex_init(&sp->lock, NULL); - if (r != 0) { - r = log_error_errno(r, "Cannot initialize shared policy mutex: %m"); - goto exit_free; - } - - r = pthread_rwlock_init(&sp->rwlock, NULL); - if (r != 0) { - r = log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); - goto exit_mutex; - } - - *out = sp; - sp = NULL; - return 0; - - /* pthread lock destruction is not fail-safe... meh! */ -exit_mutex: - pthread_mutex_destroy(&sp->lock); -exit_free: - free(sp); - return r; -} - -SharedPolicy *shared_policy_free(SharedPolicy *sp) { - if (!sp) - return NULL; - - policy_free(sp->policy); - pthread_rwlock_destroy(&sp->rwlock); - pthread_mutex_destroy(&sp->lock); - strv_free(sp->configuration); - free(sp); - - return NULL; -} - -static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) { - Policy old, buffer = {}; - bool free_old; - int r; - - assert(sp); - - r = policy_load(&buffer, configuration); - if (r < 0) - return log_error_errno(r, "Failed to load policy: %m"); - - log_debug("Reloading configuration"); - /* policy_dump(&buffer); */ - - pthread_rwlock_wrlock(&sp->rwlock); - memcpy(&old, &sp->buffer, sizeof(old)); - memcpy(&sp->buffer, &buffer, sizeof(buffer)); - free_old = !!sp->policy; - sp->policy = &sp->buffer; - pthread_rwlock_unlock(&sp->rwlock); - - if (free_old) - policy_free(&old); - - return 0; -} - -int shared_policy_reload(SharedPolicy *sp) { - int r; - - assert(sp); - - pthread_mutex_lock(&sp->lock); - r = shared_policy_reload_unlocked(sp, sp->configuration); - pthread_mutex_unlock(&sp->lock); - - return r; -} - -int shared_policy_preload(SharedPolicy *sp, char **configuration) { - _cleanup_strv_free_ char **conf = NULL; - int r = 0; - - assert(sp); - - conf = strv_copy(configuration); - if (!conf) - return log_oom(); - - pthread_mutex_lock(&sp->lock); - if (!sp->policy) { - r = shared_policy_reload_unlocked(sp, conf); - if (r >= 0) { - sp->configuration = conf; - conf = NULL; - } - } - pthread_mutex_unlock(&sp->lock); - - return r; -} - -Policy *shared_policy_acquire(SharedPolicy *sp) { - assert(sp); - - pthread_rwlock_rdlock(&sp->rwlock); - if (sp->policy) - return sp->policy; - pthread_rwlock_unlock(&sp->rwlock); - - return NULL; -} - -void shared_policy_release(SharedPolicy *sp, Policy *p) { - assert(sp); - assert(!p || sp->policy == p); - - if (p) - pthread_rwlock_unlock(&sp->rwlock); -} - -static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = { - [_POLICY_ITEM_TYPE_UNSET] = "unset", - [POLICY_ITEM_ALLOW] = "allow", - [POLICY_ITEM_DENY] = "deny", -}; -DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType); - -static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = { - [_POLICY_ITEM_CLASS_UNSET] = "unset", - [POLICY_ITEM_SEND] = "send", - [POLICY_ITEM_RECV] = "recv", - [POLICY_ITEM_OWN] = "own", - [POLICY_ITEM_OWN_PREFIX] = "own-prefix", - [POLICY_ITEM_USER] = "user", - [POLICY_ITEM_GROUP] = "group", - [POLICY_ITEM_IGNORE] = "ignore", -}; -DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass); diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h deleted file mode 100644 index 3dcddaa048..0000000000 --- a/src/bus-proxyd/bus-xml-policy.h +++ /dev/null @@ -1,147 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - 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 - 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 . -***/ - -#include - -#include "hashmap.h" -#include "list.h" - -typedef enum PolicyItemType { - _POLICY_ITEM_TYPE_UNSET = 0, - POLICY_ITEM_ALLOW, - POLICY_ITEM_DENY, - _POLICY_ITEM_TYPE_MAX, - _POLICY_ITEM_TYPE_INVALID = -1, -} PolicyItemType; - -typedef enum PolicyItemClass { - _POLICY_ITEM_CLASS_UNSET = 0, - POLICY_ITEM_SEND, - POLICY_ITEM_RECV, - POLICY_ITEM_OWN, - POLICY_ITEM_OWN_PREFIX, - POLICY_ITEM_USER, - POLICY_ITEM_GROUP, - POLICY_ITEM_IGNORE, - _POLICY_ITEM_CLASS_MAX, - _POLICY_ITEM_CLASS_INVALID = -1, -} PolicyItemClass; - -typedef struct PolicyItem PolicyItem; - -struct PolicyItem { - PolicyItemType type; - PolicyItemClass class; - char *interface; - char *member; - char *error; - char *path; - char *name; - uint8_t message_type; - uid_t uid; - gid_t gid; - - bool uid_valid, gid_valid; - - LIST_FIELDS(PolicyItem, items); -}; - -typedef struct Policy { - LIST_HEAD(PolicyItem, default_items); - LIST_HEAD(PolicyItem, mandatory_items); - LIST_HEAD(PolicyItem, on_console_items); - LIST_HEAD(PolicyItem, no_console_items); - Hashmap *user_items; - Hashmap *group_items; -} Policy; - -typedef struct SharedPolicy { - char **configuration; - pthread_mutex_t lock; - pthread_rwlock_t rwlock; - Policy buffer; - Policy *policy; -} SharedPolicy; - -/* policy */ - -int policy_load(Policy *p, char **files); -void policy_free(Policy *p); - -bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name); -bool policy_check_hello(Policy *p, uid_t uid, gid_t gid); -bool policy_check_one_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member); -bool policy_check_recv(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel); -bool policy_check_one_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - const char *name, - const char *path, - const char *interface, - const char *member); -bool policy_check_send(Policy *p, - uid_t uid, - gid_t gid, - int message_type, - Set *names, - char **namesv, - const char *path, - const char *interface, - const char *member, - bool dbus_to_kernel, - char **out_used_name); - -void policy_dump(Policy *p); - -const char* policy_item_type_to_string(PolicyItemType t) _const_; -PolicyItemType policy_item_type_from_string(const char *s) _pure_; - -const char* policy_item_class_to_string(PolicyItemClass t) _const_; -PolicyItemClass policy_item_class_from_string(const char *s) _pure_; - -/* shared policy */ - -int shared_policy_new(SharedPolicy **out); -SharedPolicy *shared_policy_free(SharedPolicy *sp); - -int shared_policy_reload(SharedPolicy *sp); -int shared_policy_preload(SharedPolicy *sp, char **configuration); -Policy *shared_policy_acquire(SharedPolicy *sp); -void shared_policy_release(SharedPolicy *sp, Policy *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(SharedPolicy*, shared_policy_free); diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c deleted file mode 100644 index 1af5c310ea..0000000000 --- a/src/bus-proxyd/driver.c +++ /dev/null @@ -1,745 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 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 . -***/ - -#include -#include -#include - -#include "sd-bus.h" - -#include "alloc-util.h" -#include "bus-internal.h" -#include "bus-message.h" -#include "bus-util.h" -#include "driver.h" -#include "env-util.h" -#include "proxy.h" -#include "set.h" -#include "strv.h" -#include "synthesize.h" -#include "util.h" - -static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; - int r; - - assert(bus); - assert(name); - assert(_creds); - - r = sd_bus_get_name_creds(bus, name, mask, &c); - if (r == -ESRCH || r == -ENXIO) - return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name); - if (r < 0) - return r; - - *_creds = c; - c = NULL; - - return 0; -} - -static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { - const char *name; - int r; - - assert(bus); - assert(m); - assert(_creds); - - r = sd_bus_message_read(m, "s", &name); - if (r < 0) - return r; - - return get_creds_by_name(bus, name, mask, _creds, error); -} - -static int driver_activation(sd_bus_message *reply, void *userdata, sd_bus_error *error) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - ProxyActivation *activation = userdata; - - /* - * The org.freedesktop.DBus.Peer.Ping() call returned. We don't care - * whether this succeeded, failed, was not implemented or timed out. We - * cannot assume that the target reacts to this properly. Hence, just - * send the reply to the activation request and be done. - */ - - m = activation->request; /* claim reference */ - - --activation->proxy->n_activations; - LIST_REMOVE(activations_by_proxy, activation->proxy->activations, activation); - sd_bus_slot_unref(activation->slot); - free(activation); - - return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS); -} - -int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) { - int r; - - assert(a); - assert(b); - assert(m); - - if (!a->is_kernel) - return 0; - - if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus")) - return 0; - - /* The "Hello()" call is is handled in process_hello() */ - - if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - return synthetic_reply_method_return(m, "s", - "\n" - "\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) { - const char *match; - - 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 = sd_bus_message_read(m, "s", &match); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_add_match(a, NULL, match, proxy_match, p); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, NULL); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) { - const char *match; - - 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 = sd_bus_message_read(m, "s", &match); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = bus_remove_match_by_string(a, match, NULL, NULL); - if (r == 0) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found")); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, NULL); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionCredentials")) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_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_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - _cleanup_(sd_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_SELINUX_CONTEXT, &creds, &error); - if (r < 0) - return synthetic_reply_method_errno(m, r, &error); - - 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_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - _cleanup_(sd_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, &creds, &error); - 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")) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - _cleanup_(sd_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_EUID, &creds, &error); - 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")) { - sd_id128_t server_id; - char buf[SD_ID128_STRING_MAX]; - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_get_bus_id(a, &server_id); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf)); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) { - const char *name; - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - _cleanup_(sd_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 = sd_bus_message_read(m, "s", &name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (streq(name, "org.freedesktop.DBus")) - return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus"); - - r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error); - 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")) { - _cleanup_strv_free_ char **names = NULL; - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_list_names(a, NULL, &names); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - /* Let's sort the names list to make it stable */ - strv_sort(names); - - return synthetic_reply_method_return_strv(m, names); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) { - _cleanup_strv_free_ char **names = NULL; - - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_list_names(a, &names, NULL); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = strv_extend(&names, "org.freedesktop.DBus"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - /* Let's sort the names list to make it stable */ - strv_sort(names); - - return synthetic_reply_method_return_strv(m, names); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) { - struct kdbus_cmd_list cmd = { - .flags = KDBUS_LIST_QUEUED, - .size = sizeof(cmd), - }; - struct kdbus_info *name_list, *name; - _cleanup_strv_free_ char **owners = NULL; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - char *arg0; - int err = 0; - - 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 = sd_bus_message_read(m, "s", &arg0); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_get_name_creds(a, arg0, 0, NULL); - if (r == -ESRCH || r == -ENXIO) { - sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0); - return synthetic_reply_method_errno(m, r, &error); - } - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd); - if (r < 0) - return synthetic_reply_method_errno(m, -errno, NULL); - - name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset); - - KDBUS_FOREACH(name, name_list, cmd.list_size) { - struct kdbus_item *item; - char *n; - - KDBUS_ITEM_FOREACH(item, name, items) { - if (item->type == KDBUS_ITEM_OWNED_NAME) { - if (!streq_ptr(item->name.name, arg0)) - continue; - - if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) { - err = -ENOMEM; - break; - } - - r = strv_consume(&owners, n); - if (r < 0) { - err = r; - break; - } - } - } - - if (err < 0) - break; - } - - r = bus_kernel_cmd_free(a, cmd.offset); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (err < 0) - return synthetic_reply_method_errno(m, err, NULL); - - return synthetic_reply_method_return_strv(m, owners); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) { - const char *name; - - 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 = sd_bus_message_read(m, "s", &name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (streq(name, "org.freedesktop.DBus")) - return synthetic_reply_method_return(m, "b", true); - - r = sd_bus_get_name_creds(a, name, 0, NULL); - if (r < 0 && r != -ESRCH && r != -ENXIO) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, "b", r >= 0); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) { - const char *name; - - 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 = sd_bus_message_read(m, "s", &name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_release_name(a, name); - if (r < 0) { - if (r == -ESRCH) - return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT); - if (r == -EADDRINUSE) - return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER); - - return synthetic_reply_method_errno(m, r, NULL); - } - - set_remove(owned_names, (char*) name); - - return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) { - if (!sd_bus_message_has_signature(m, "")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = shared_policy_reload(sp); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, NULL); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) { - const char *name; - uint32_t flags, param; - bool in_queue; - - if (!sd_bus_message_has_signature(m, "su")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "su", &name, &flags); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (sp) { - Policy *policy; - bool denied; - - policy = shared_policy_acquire(sp); - denied = !policy_check_own(policy, ucred->uid, ucred->gid, name); - shared_policy_release(sp, policy); - if (denied) - return synthetic_reply_method_errno(m, -EPERM, NULL); - } - - if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0) - return synthetic_reply_method_errno(m, -EINVAL, NULL); - - param = 0; - if (flags & BUS_NAME_ALLOW_REPLACEMENT) - param |= SD_BUS_NAME_ALLOW_REPLACEMENT; - if (flags & BUS_NAME_REPLACE_EXISTING) - param |= SD_BUS_NAME_REPLACE_EXISTING; - if (!(flags & BUS_NAME_DO_NOT_QUEUE)) - param |= SD_BUS_NAME_QUEUE; - - r = set_put_strdup(owned_names, name); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_request_name(a, name, param); - if (r < 0) { - if (r == -EALREADY) - return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER); - - set_remove(owned_names, (char*) name); - - if (r == -EEXIST) - return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS); - return synthetic_reply_method_errno(m, r, NULL); - } - - in_queue = (r == 0); - - if (in_queue) - return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE); - - return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER); - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL; - ProxyActivation *activation; - const char *name; - uint64_t cookie; - uint32_t flags; - - if (!sd_bus_message_has_signature(m, "su")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_read(m, "su", &name, &flags); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (flags != 0) - return synthetic_reply_method_errno(m, -EINVAL, NULL); - - r = sd_bus_get_name_creds(a, name, 0, NULL); - if (r >= 0 || streq(name, "org.freedesktop.DBus")) - return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING); - if (r != -ESRCH) - return synthetic_reply_method_errno(m, r, NULL); - - if (p->n_activations >= PROXY_ACTIVATIONS_MAX) - return synthetic_reply_method_errno(m, -EMFILE, NULL); - - r = sd_bus_message_get_cookie(m, &cookie); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_new_method_call(a, - &msg, - name, - "/", - "org.freedesktop.DBus.Peer", - "Ping"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = bus_message_seal(msg, cookie, BUS_DEFAULT_TIMEOUT); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - activation = new0(ProxyActivation, 1); - if (!activation) - return synthetic_reply_method_errno(m, -ENOMEM, NULL); - - r = sd_bus_call_async(a, - &activation->slot, - msg, - driver_activation, - activation, - 0); - if (r < 0) { - free(activation); - return synthetic_reply_method_errno(m, r, NULL); - } - - activation->proxy = p; - activation->request = sd_bus_message_ref(m); - LIST_PREPEND(activations_by_proxy, p->activations, activation); - ++p->n_activations; - return 1; - - } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL; - _cleanup_strv_free_ char **args = NULL; - - if (!sd_bus_message_has_signature(m, "a{ss}")) - return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); - - r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) { - _cleanup_free_ char *s = NULL; - const char *key; - const char *value; - - r = sd_bus_message_read(m, "ss", &key, &value); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - s = strjoin(key, "=", value, NULL); - if (!s) - return synthetic_reply_method_errno(m, -ENOMEM, NULL); - - if (!env_assignment_is_valid(s)) { - log_warning("UpdateActivationEnvironment() called with invalid assignment, discarding: %s", s); - } else { - r = strv_extend(&args, s); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - } - - r = sd_bus_message_exit_container(m); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - if (strv_isempty(args)) /* nothing to do? */ - return synthetic_reply_method_return(m, NULL); - - r = sd_bus_message_new_method_call( - a, - &msg, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "SetEnvironment"); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_message_append_strv(msg, args); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - r = sd_bus_call(a, msg, 0, NULL, NULL); - if (r < 0) - return synthetic_reply_method_errno(m, r, NULL); - - return synthetic_reply_method_return(m, NULL); - - } else { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - - r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member); - - return synthetic_reply_method_errno(m, r, &error); - } -} diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h deleted file mode 100644 index 1630cdc7b9..0000000000 --- a/src/bus-proxyd/driver.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -/*** - 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 . -***/ - -#include "sd-bus.h" - -#include "bus-xml-policy.h" -#include "proxy.h" - -int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names); diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c deleted file mode 100644 index 907d93d4c7..0000000000 --- a/src/bus-proxyd/proxy.c +++ /dev/null @@ -1,953 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 Kay Sievers - Copyright 2014 David Herrmann - - 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 . -***/ - -#include -#include -#include -#include -#include - -#include "sd-bus.h" -#include "sd-daemon.h" - -#include "alloc-util.h" -#include "bus-control.h" -#include "bus-internal.h" -#include "bus-message.h" -#include "bus-util.h" -#include "bus-xml-policy.h" -#include "driver.h" -#include "fd-util.h" -#include "formats-util.h" -#include "log.h" -#include "proxy.h" -#include "set.h" -#include "strv.h" -#include "synthesize.h" -#include "user-util.h" -#include "util.h" - -static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *b = NULL; - int r; - - r = sd_bus_new(&b); - if (r < 0) - return log_error_errno(r, "Failed to allocate bus: %m"); - - r = sd_bus_set_description(b, "sd-proxy"); - if (r < 0) - return log_error_errno(r, "Failed to set bus name: %m"); - - r = sd_bus_set_address(b, destination); - if (r < 0) - return log_error_errno(r, "Failed to set address to connect to: %m"); - - r = sd_bus_negotiate_fds(b, negotiate_fds); - if (r < 0) - return log_error_errno(r, "Failed to set FD negotiation: %m"); - - r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT); - if (r < 0) - return log_error_errno(r, "Failed to set credential negotiation: %m"); - - if (p->local_creds.pid > 0) { - b->fake_pids.pid = p->local_creds.pid; - b->fake_pids_valid = true; - - b->fake_creds.uid = UID_INVALID; - b->fake_creds.euid = p->local_creds.uid; - b->fake_creds.suid = UID_INVALID; - b->fake_creds.fsuid = UID_INVALID; - b->fake_creds.gid = GID_INVALID; - b->fake_creds.egid = p->local_creds.gid; - b->fake_creds.sgid = GID_INVALID; - b->fake_creds.fsgid = GID_INVALID; - b->fake_creds_valid = true; - } - - if (local_sec) { - b->fake_label = strdup(local_sec); - if (!b->fake_label) - return log_oom(); - } - - b->manual_peer_interface = true; - - r = sd_bus_start(b); - if (r < 0) - return log_error_errno(r, "Failed to start bus client: %m"); - - p->destination_bus = b; - b = NULL; - return 0; -} - -static int proxy_create_local(Proxy *p, bool negotiate_fds) { - sd_id128_t server_id; - sd_bus *b; - int r; - - r = sd_bus_new(&b); - if (r < 0) - return log_error_errno(r, "Failed to allocate bus: %m"); - - r = sd_bus_set_fd(b, p->local_in, p->local_out); - if (r < 0) { - sd_bus_unref(b); - return log_error_errno(r, "Failed to set fds: %m"); - } - - /* The fds are now owned by the bus, and we indicate that by - * storing the bus object in the proxy object. */ - p->local_bus = b; - - r = sd_bus_get_bus_id(p->destination_bus, &server_id); - if (r < 0) - return log_error_errno(r, "Failed to get server ID: %m"); - - r = sd_bus_set_server(b, 1, server_id); - if (r < 0) - return log_error_errno(r, "Failed to set server mode: %m"); - - r = sd_bus_negotiate_fds(b, negotiate_fds); - if (r < 0) - return log_error_errno(r, "Failed to set FD negotiation: %m"); - - r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT); - if (r < 0) - return log_error_errno(r, "Failed to set credential negotiation: %m"); - - r = sd_bus_set_anonymous(b, true); - if (r < 0) - return log_error_errno(r, "Failed to set anonymous authentication: %m"); - - b->manual_peer_interface = true; - - r = sd_bus_start(b); - if (r < 0) - return log_error_errno(r, "Failed to start bus client: %m"); - - return 0; -} - -static int proxy_match_synthetic(sd_bus_message *m, void *userdata, sd_bus_error *error) { - Proxy *p = userdata; - - p->synthetic_matched = true; - return 0; /* make sure to continue processing it in further handlers */ -} - -/* - * We always need NameOwnerChanged so we can synthesize NameLost and - * NameAcquired. Furthermore, dbus-1 always passes unicast-signals through, so - * subscribe unconditionally. - */ -static int proxy_prepare_matches(Proxy *p) { - _cleanup_free_ char *match = NULL; - const char *unique; - int r; - - if (!p->destination_bus->is_kernel) - return 0; - - r = sd_bus_get_unique_name(p->destination_bus, &unique); - if (r < 0) - return log_error_errno(r, "Failed to get unique name: %m"); - - match = strjoin("type='signal'," - "sender='org.freedesktop.DBus'," - "path='/org/freedesktop/DBus'," - "interface='org.freedesktop.DBus'," - "member='NameOwnerChanged'," - "arg1='", - unique, - "'", - NULL); - if (!match) - return log_oom(); - - r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p); - if (r < 0) - return log_error_errno(r, "Failed to add match for NameLost: %m"); - - free(match); - match = strjoin("type='signal'," - "sender='org.freedesktop.DBus'," - "path='/org/freedesktop/DBus'," - "interface='org.freedesktop.DBus'," - "member='NameOwnerChanged'," - "arg2='", - unique, - "'", - NULL); - if (!match) - return log_oom(); - - r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p); - if (r < 0) - return log_error_errno(r, "Failed to add match for NameAcquired: %m"); - - free(match); - match = strjoin("type='signal'," - "destination='", - unique, - "'", - NULL); - if (!match) - return log_oom(); - - r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p); - if (r < 0) - log_error_errno(r, "Failed to add match for directed signals: %m"); - /* FIXME: temporarily ignore error to support older kdbus versions */ - - return 0; -} - -int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { - _cleanup_(proxy_freep) Proxy *p = NULL; - _cleanup_free_ char *local_sec = NULL; - bool is_unix; - int r; - - /* This takes possession/destroys the file descriptors passed - * in even on failure. The caller should hence forget about - * the fds in all cases after calling this function and not - * close them. */ - - p = new0(Proxy, 1); - if (!p) { - safe_close(in_fd); - safe_close(out_fd); - return log_oom(); - } - - p->local_in = in_fd; - p->local_out = out_fd; - - p->owned_names = set_new(&string_hash_ops); - if (!p->owned_names) - return log_oom(); - - is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && - sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; - - if (is_unix) { - (void) getpeercred(in_fd, &p->local_creds); - (void) getpeersec(in_fd, &local_sec); - } - - r = proxy_create_destination(p, destination, local_sec, is_unix); - if (r < 0) - return r; - - r = proxy_create_local(p, is_unix); - if (r < 0) - return r; - - r = proxy_prepare_matches(p); - if (r < 0) - return r; - - *out = p; - p = NULL; - - return 0; -} - -Proxy *proxy_free(Proxy *p) { - ProxyActivation *activation; - - if (!p) - return NULL; - - while ((activation = p->activations)) { - LIST_REMOVE(activations_by_proxy, p->activations, activation); - sd_bus_message_unref(activation->request); - sd_bus_slot_unref(activation->slot); - free(activation); - } - - if (p->local_bus) - sd_bus_flush_close_unref(p->local_bus); - else { - safe_close(p->local_in); - if (p->local_out != p->local_in) - safe_close(p->local_out); - } - - sd_bus_flush_close_unref(p->destination_bus); - set_free_free(p->owned_names); - free(p); - - return NULL; -} - -int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) { - _cleanup_strv_free_ char **strv = NULL; - Policy *policy; - int r; - - assert(p); - assert(sp); - - /* no need to load legacy policy if destination is not kdbus */ - if (!p->destination_bus->is_kernel) - return 0; - - p->policy = sp; - - policy = shared_policy_acquire(sp); - if (policy) { - /* policy already pre-loaded */ - shared_policy_release(sp, policy); - return 0; - } - - if (!configuration) { - const char *scope; - - r = sd_bus_get_scope(p->destination_bus, &scope); - if (r < 0) - return log_error_errno(r, "Couldn't determine bus scope: %m"); - - if (streq(scope, "system")) - strv = strv_new("/usr/share/dbus-1/system.conf", - "/etc/dbus-1/system.conf", - "/usr/share/dbus-1/system.d/", - "/etc/dbus-1/system.d/", - "/etc/dbus-1/system-local.conf", - NULL); - else if (streq(scope, "user")) - strv = strv_new("/usr/share/dbus-1/session.conf", - "/etc/dbus-1/session.conf", - "/usr/share/dbus-1/session.d/", - "/etc/dbus-1/session.d/", - "/etc/dbus-1/session-local.conf", - NULL); - else - return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope); - - if (!strv) - return log_oom(); - - configuration = strv; - } - - return shared_policy_preload(sp, configuration); -} - -int proxy_hello_policy(Proxy *p, uid_t original_uid) { - Policy *policy; - int r = 0; - - assert(p); - - if (!p->policy) - return 0; - - policy = shared_policy_acquire(p->policy); - - if (p->local_creds.uid == original_uid) - log_debug("Permitting access, since bus owner matches bus client."); - else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid)) - log_debug("Permitting access due to XML policy."); - else - r = log_error_errno(EPERM, "Policy denied connection."); - - shared_policy_release(p->policy, policy); - - return r; -} - -static int proxy_wait(Proxy *p) { - uint64_t timeout_destination, timeout_local, t; - int events_destination, events_local, fd; - struct timespec _ts, *ts; - struct pollfd *pollfd; - int r; - - assert(p); - - fd = sd_bus_get_fd(p->destination_bus); - if (fd < 0) - return log_error_errno(fd, "Failed to get fd: %m"); - - events_destination = sd_bus_get_events(p->destination_bus); - if (events_destination < 0) - return log_error_errno(events_destination, "Failed to get events mask: %m"); - - r = sd_bus_get_timeout(p->destination_bus, &timeout_destination); - if (r < 0) - return log_error_errno(r, "Failed to get timeout: %m"); - - events_local = sd_bus_get_events(p->local_bus); - if (events_local < 0) - return log_error_errno(events_local, "Failed to get events mask: %m"); - - r = sd_bus_get_timeout(p->local_bus, &timeout_local); - if (r < 0) - return log_error_errno(r, "Failed to get timeout: %m"); - - t = timeout_destination; - if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination)) - t = timeout_local; - - if (t == (uint64_t) -1) - ts = NULL; - else { - usec_t nw; - - nw = now(CLOCK_MONOTONIC); - if (t > nw) - t -= nw; - else - t = 0; - - ts = timespec_store(&_ts, t); - } - - pollfd = (struct pollfd[3]) { - { .fd = fd, .events = events_destination, }, - { .fd = p->local_in, .events = events_local & POLLIN, }, - { .fd = p->local_out, .events = events_local & POLLOUT, }, - }; - - r = ppoll(pollfd, 3, ts, NULL); - if (r < 0) - return log_error_errno(errno, "ppoll() failed: %m"); - - return 0; -} - -static int handle_policy_error(sd_bus_message *m, int r) { - if (r == -ESRCH || r == -ENXIO) - return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination); - - return r; -} - -static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) { - int r; - - assert(from); - assert(to); - assert(m); - - if (!policy) - return 0; - - /* - * dbus-1 distinguishes expected and non-expected replies by tracking - * method-calls and timeouts. By default, DENY rules are *NEVER* applied - * on expected replies, unless explicitly specified. But we dont track - * method-calls, thus, we cannot know whether a reply is expected. - * Fortunately, the kdbus forbids non-expected replies, so we can safely - * ignore any policy on those and let the kernel deal with it. - * - * TODO: To be correct, we should only ignore policy-tags that are - * applied on non-expected replies. However, so far we don't parse those - * tags so we let everything pass. I haven't seen a DENY policy tag on - * expected-replies, ever, so don't bother.. - */ - if (m->reply_cookie > 0) - return 0; - - if (from->is_kernel) { - uid_t sender_uid = UID_INVALID; - gid_t sender_gid = GID_INVALID; - char **sender_names = NULL; - - /* Driver messages are always OK */ - if (streq_ptr(m->sender, "org.freedesktop.DBus")) - return 0; - - /* The message came from the kernel, and is sent to our legacy client. */ - (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names); - - (void) sd_bus_creds_get_euid(&m->creds, &sender_uid); - (void) sd_bus_creds_get_egid(&m->creds, &sender_gid); - - if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *sender_creds = NULL; - - /* If the message came from another legacy - * client, then the message creds will be - * missing, simply because on legacy clients - * per-message creds were unknown. In this - * case, query the creds of the peer - * instead. */ - - r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds); - if (r < 0) - return handle_policy_error(m, r); - - (void) sd_bus_creds_get_euid(sender_creds, &sender_uid); - (void) sd_bus_creds_get_egid(sender_creds, &sender_gid); - } - - /* First check whether the sender can send the message to our name */ - if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) && - policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false)) - return 0; - - /* Return an error back to the caller */ - if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) - return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy."); - - /* Return 1, indicating that the message shall not be processed any further */ - return 1; - } - - if (to->is_kernel) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *destination_creds = NULL; - uid_t destination_uid = UID_INVALID; - gid_t destination_gid = GID_INVALID; - const char *destination_unique = NULL; - char **destination_names = NULL; - char *n; - - /* Driver messages are always OK */ - if (streq_ptr(m->destination, "org.freedesktop.DBus")) - return 0; - - /* The message came from the legacy client, and is sent to kdbus. */ - if (m->destination) { - r = bus_get_name_creds_kdbus(to, m->destination, - SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME| - SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID, - true, &destination_creds); - if (r < 0) - return handle_policy_error(m, r); - - r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique); - if (r < 0) - return handle_policy_error(m, r); - - (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names); - - (void) sd_bus_creds_get_euid(destination_creds, &destination_uid); - (void) sd_bus_creds_get_egid(destination_creds, &destination_gid); - } - - /* First check if we (the sender) can send to this name */ - if (sd_bus_message_is_signal(m, NULL, NULL)) { - /* If we forward a signal from dbus-1 to kdbus, we have - * no idea who the recipient is. Therefore, we cannot - * apply any dbus-1 policies that match on receiver - * credentials. We know sd-bus always sets - * KDBUS_MSG_SIGNAL, so the kernel applies policies to - * the message. Therefore, skip policy checks in this - * case. */ - return 0; - } else if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) { - if (n) { - /* If we made a receiver decision, then remember which - * name's policy we used, and to which unique ID it - * mapped when we made the decision. Then, let's pass - * this to the kernel when sending the message, so that - * it refuses the operation should the name and unique - * ID not map to each other anymore. */ - - r = free_and_strdup(&m->destination_ptr, n); - if (r < 0) - return r; - - r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id); - if (r < 0) - return r; - } - - if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) - return 0; - } - - /* Return an error back to the caller */ - if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) - return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy."); - - /* Return 1, indicating that the message shall not be processed any further */ - return 1; - } - - return 0; -} - -static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) { - Policy *policy; - int r; - - assert(sp); - - policy = shared_policy_acquire(sp); - r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names); - shared_policy_release(sp, policy); - - return r; -} - -static int process_hello(Proxy *p, sd_bus_message *m) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL; - bool is_hello; - int r; - - assert(p); - assert(m); - - /* As reaction to hello we need to respond with two messages: - * the callback reply and the NameAcquired for the unique - * name, since hello is otherwise obsolete on kdbus. */ - - is_hello = - sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") && - streq_ptr(m->destination, "org.freedesktop.DBus"); - - if (!is_hello) { - if (p->got_hello) - return 0; - - return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member); - } - - if (p->got_hello) - return log_error_errno(EIO, "Got duplicate hello, aborting."); - - p->got_hello = true; - - if (!p->destination_bus->is_kernel) - return 0; - - r = sd_bus_message_new_method_return(m, &n); - if (r < 0) - return log_error_errno(r, "Failed to generate HELLO reply: %m"); - - r = sd_bus_message_append(n, "s", p->destination_bus->unique_name); - if (r < 0) - return log_error_errno(r, "Failed to append unique name to HELLO reply: %m"); - - r = bus_message_append_sender(n, "org.freedesktop.DBus"); - if (r < 0) - return log_error_errno(r, "Failed to append sender to HELLO reply: %m"); - - r = bus_seal_synthetic_message(p->local_bus, n); - if (r < 0) - return log_error_errno(r, "Failed to seal HELLO reply: %m"); - - r = sd_bus_send(p->local_bus, n, NULL); - if (r < 0) - return log_error_errno(r, "Failed to send HELLO reply: %m"); - - n = sd_bus_message_unref(n); - r = sd_bus_message_new_signal( - p->local_bus, - &n, - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "NameAcquired"); - if (r < 0) - return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m"); - - r = sd_bus_message_append(n, "s", p->destination_bus->unique_name); - if (r < 0) - return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m"); - - r = bus_message_append_sender(n, "org.freedesktop.DBus"); - if (r < 0) - return log_error_errno(r, "Failed to append sender to NameAcquired message: %m"); - - r = sd_bus_message_set_destination(n, p->destination_bus->unique_name); - if (r < 0) - return log_error_errno(r, "Failed to set destination for NameAcquired message: %m"); - - r = bus_seal_synthetic_message(p->local_bus, n); - if (r < 0) - return log_error_errno(r, "Failed to seal NameAcquired message: %m"); - - r = sd_bus_send(p->local_bus, n, NULL); - if (r < 0) - return log_error_errno(r, "Failed to send NameAcquired message: %m"); - - return 1; -} - -static int patch_sender(sd_bus *a, sd_bus_message *m) { - char **well_known = NULL; - sd_bus_creds *c; - int r; - - assert(a); - assert(m); - - if (!a->is_kernel) - return 0; - - /* We will change the sender of messages from the bus driver - * so that they originate from the bus driver. This is a - * speciality originating from dbus1, where the bus driver did - * not have a unique id, but only the well-known name. */ - - c = sd_bus_message_get_creds(m); - if (!c) - return 0; - - r = sd_bus_creds_get_well_known_names(c, &well_known); - if (r < 0) - return r; - - if (strv_contains(well_known, "org.freedesktop.DBus")) - m->sender = "org.freedesktop.DBus"; - - return 0; -} - -static int proxy_process_destination_to_local(Proxy *p) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - bool matched, matched_synthetic; - int r; - - assert(p); - - /* - * Usually, we would just take any message that the bus passes to us - * and forward it to the local connection. However, there are actually - * applications that fail if they receive broadcasts that they didn't - * subscribe to. Therefore, we actually emulate a real broadcast - * matching here, and discard any broadcasts that weren't matched. Our - * match-handlers remembers whether a message was matched by any rule, - * by marking it in @p->message_matched. - */ - - r = sd_bus_process(p->destination_bus, &m); - - matched = p->message_matched; - matched_synthetic = p->synthetic_matched; - p->message_matched = false; - p->synthetic_matched = false; - - if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */ - return r; - if (r < 0) { - log_error_errno(r, "Failed to process destination bus: %m"); - return r; - } - if (r == 0) - return 0; - if (!m) - return 1; - - /* We officially got EOF, let's quit */ - if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) - return -ECONNRESET; - - r = synthesize_name_acquired(p, p->destination_bus, p->local_bus, m); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to synthesize message: %m"); - - /* discard broadcasts that were not matched by any MATCH rule */ - if (!matched && !sd_bus_message_get_destination(m)) { - if (!matched_synthetic) - log_debug("Dropped unmatched broadcast: uid=" UID_FMT " gid=" GID_FMT " pid=" PID_FMT " message=%s path=%s interface=%s member=%s sender=%s destination=%s", - p->local_creds.uid, p->local_creds.gid, p->local_creds.pid, bus_message_type_to_string(m->header->type), - strna(m->path), strna(m->interface), strna(m->member), strna(m->sender), strna(m->destination)); - return 1; - } - - patch_sender(p->destination_bus, m); - - if (p->policy) { - r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process policy: %m"); - if (r > 0) - return 1; - } - - r = sd_bus_send(p->local_bus, m, NULL); - if (r < 0) { - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - - /* If the peer tries to send a reply and it is - * rejected with EBADSLT by the kernel, we ignore the - * error. This catches cases where the original - * method-call didn't had EXPECT_REPLY set, but the - * proxy-peer still sends a reply. This is allowed in - * dbus1, but not in kdbus. We don't want to track - * reply-windows in the proxy, so we simply ignore - * EBADSLT for all replies. The only downside is, that - * callers are no longer notified if their replies are - * dropped. However, this is equivalent to the - * caller's timeout to expire, so this should be - * acceptable. Nobody sane sends replies without a - * matching method-call, so nobody should care. */ - - /* FIXME: remove -EPERM when kdbus is updated */ - if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0) - return 1; - - /* Return the error to the client, if we can */ - synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m"); - 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; -} - -static int proxy_process_local_to_destination(Proxy *p) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - int r; - - assert(p); - - r = sd_bus_process(p->local_bus, &m); - if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */ - return r; - if (r < 0) { - log_error_errno(r, "Failed to process local bus: %m"); - return r; - } - if (r == 0) - return 0; - if (!m) - return 1; - - /* We officially got EOF, let's quit */ - if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) - return -ECONNRESET; - - r = process_hello(p, m); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process HELLO: %m"); - if (r > 0) - return 1; - - r = bus_proxy_process_driver(p, p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process driver calls: %m"); - if (r > 0) - return 1; - - for (;;) { - if (p->policy) { - r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names); - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - if (r < 0) - return log_error_errno(r, "Failed to process policy: %m"); - if (r > 0) - return 1; - } - - r = sd_bus_send(p->destination_bus, m, NULL); - if (r < 0) { - if (r == -ECONNRESET || r == -ENOTCONN) - return r; - - /* The name database changed since the policy check, hence let's check again */ - if (r == -EREMCHG) - continue; - - /* see above why EBADSLT is ignored for replies */ - if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0) - return 1; - - synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m"); - log_error_errno(r, - "Failed to forward message we got from local: 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; - } - - break; - } - - return 1; -} - -int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error) { - Proxy *p = userdata; - - p->message_matched = true; - return 0; /* make sure to continue processing it in further handlers */ -} - -int proxy_run(Proxy *p) { - int r; - - assert(p); - - for (;;) { - bool busy = false; - - if (p->got_hello) { - /* Read messages from bus, to pass them on to our client */ - r = proxy_process_destination_to_local(p); - if (r == -ECONNRESET || r == -ENOTCONN) - return 0; - if (r < 0) - return r; - if (r > 0) - busy = true; - } - - /* Read messages from our client, to pass them on to the bus */ - r = proxy_process_local_to_destination(p); - if (r == -ECONNRESET || r == -ENOTCONN) - return 0; - if (r < 0) - return r; - if (r > 0) - busy = true; - - if (!busy) { - r = proxy_wait(p); - if (r == -ECONNRESET || r == -ENOTCONN) - return 0; - if (r < 0) - return r; - } - } - - return 0; -} diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h deleted file mode 100644 index d9e75cf73b..0000000000 --- a/src/bus-proxyd/proxy.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann - - 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 . -***/ - -#include "sd-bus.h" - -#include "bus-xml-policy.h" - -typedef struct Proxy Proxy; -typedef struct ProxyActivation ProxyActivation; - -#define PROXY_ACTIVATIONS_MAX (16) /* max parallel activation requests */ - -struct Proxy { - sd_bus *local_bus; - struct ucred local_creds; - int local_in; - int local_out; - - sd_bus *destination_bus; - - Set *owned_names; - SharedPolicy *policy; - - LIST_HEAD(ProxyActivation, activations); - size_t n_activations; - - bool got_hello : 1; - bool queue_overflow : 1; - bool message_matched : 1; - bool synthetic_matched : 1; -}; - -struct ProxyActivation { - LIST_FIELDS(ProxyActivation, activations_by_proxy); - Proxy *proxy; - sd_bus_message *request; - sd_bus_slot *slot; -}; - -int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest); -Proxy *proxy_free(Proxy *p); - -int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration); -int proxy_hello_policy(Proxy *p, uid_t original_uid); -int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error); -int proxy_run(Proxy *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free); diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c deleted file mode 100644 index 291c1b09e3..0000000000 --- a/src/bus-proxyd/stdio-bridge.c +++ /dev/null @@ -1,244 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 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 . -***/ - -#include -#include -#include -#include -#include - -#include "sd-bus.h" -#include "sd-daemon.h" - -#include "alloc-util.h" -#include "bus-internal.h" -#include "bus-util.h" -#include "def.h" -#include "formats-util.h" -#include "log.h" -#include "proxy.h" -#include "strv.h" -#include "user-util.h" -#include "util.h" - -static char *arg_address = NULL; -static char *arg_command_line_buffer = NULL; - -static int help(void) { - - printf("%s [OPTIONS...]\n\n" - "Connect STDIO to a given bus address.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --machine=MACHINE Connect to specified machine\n" - " --address=ADDRESS Connect to the bus specified by ADDRESS\n" - " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n", - program_invocation_short_name); - - return 0; -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_ADDRESS, - ARG_MACHINE, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "address", required_argument, NULL, ARG_ADDRESS }, - { "machine", required_argument, NULL, ARG_MACHINE }, - {}, - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) - - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - return version(); - - case ARG_ADDRESS: { - char *a; - - a = strdup(optarg); - if (!a) - return log_oom(); - - free(arg_address); - arg_address = a; - break; - } - - case ARG_MACHINE: { - _cleanup_free_ char *e = NULL; - char *a; - - e = bus_address_escape(optarg); - if (!e) - return log_oom(); - - a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL); - if (!a) - return log_oom(); - - free(arg_address); - arg_address = a; - - break; - } - - case '?': - return -EINVAL; - - default: - assert_not_reached("Unhandled option"); - } - - /* If the first command line argument is only "x" characters - * we'll write who we are talking to into it, so that "ps" is - * explanatory */ - arg_command_line_buffer = argv[optind]; - if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) { - log_error("Too many arguments"); - return -EINVAL; - } - - if (!arg_address) { - arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS); - if (!arg_address) - return log_oom(); - } - - return 1; -} - -static int rename_service(sd_bus *a, sd_bus *b) { - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - _cleanup_free_ char *p = NULL, *name = NULL; - const char *comm; - char **cmdline; - uid_t uid; - pid_t pid; - int r; - - assert(a); - assert(b); - - r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds); - if (r < 0) - return r; - - r = sd_bus_creds_get_euid(creds, &uid); - if (r < 0) - return r; - - r = sd_bus_creds_get_pid(creds, &pid); - if (r < 0) - return r; - - r = sd_bus_creds_get_cmdline(creds, &cmdline); - if (r < 0) - return r; - - r = sd_bus_creds_get_comm(creds, &comm); - if (r < 0) - return r; - - name = uid_to_name(uid); - if (!name) - return -ENOMEM; - - p = strv_join(cmdline, " "); - if (!p) - return -ENOMEM; - - /* The status string gets the full command line ... */ - sd_notifyf(false, - "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)", - pid, p, - uid, name); - - /* ... and the argv line only the short comm */ - if (arg_command_line_buffer) { - size_t m, w; - - m = strlen(arg_command_line_buffer); - w = snprintf(arg_command_line_buffer, m, - "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]", - pid, comm, - uid, name); - - if (m > w) - memzero(arg_command_line_buffer + w, m - w); - } - - log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s", - pid, p, - uid, name, - a->unique_name); - - return 0; -} - -int main(int argc, char *argv[]) { - _cleanup_(proxy_freep) Proxy *p = NULL; - int r; - - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); - log_parse_environment(); - log_open(); - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address); - if (r < 0) - goto finish; - - r = rename_service(p->destination_bus, p->local_bus); - if (r < 0) - log_debug_errno(r, "Failed to rename process: %m"); - - r = proxy_run(p); - -finish: - sd_notify(false, - "STOPPING=1\n" - "STATUS=Shutting down."); - - free(arg_address); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c deleted file mode 100644 index 8eea7dc5b9..0000000000 --- a/src/bus-proxyd/synthesize.c +++ /dev/null @@ -1,225 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - Copyright 2013 Daniel Mack - Copyright 2014 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 . -***/ - -#include - -#include "sd-bus.h" - -#include "bus-internal.h" -#include "bus-match.h" -#include "bus-message.h" -#include "bus-util.h" -#include "synthesize.h" -#include "util.h" - -int synthetic_driver_send(sd_bus *b, sd_bus_message *m) { - int r; - - assert(b); - assert(m); - - r = bus_message_append_sender(m, "org.freedesktop.DBus"); - if (r < 0) - return r; - - r = bus_seal_synthetic_message(b, m); - if (r < 0) - return r; - - return sd_bus_send(b, m, NULL); -} - -int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - int r; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - r = sd_bus_message_new_method_error(call, &m, e); - if (r < 0) - return r; - - return synthetic_driver_send(call->bus, m); -} - -int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - va_list ap; - - va_start(ap, format); - bus_error_setfv(&error, name, format, ap); - va_end(ap); - - return synthetic_reply_method_error(call, &error); -} - -int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) { - _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - if (sd_bus_error_is_set(p)) - return synthetic_reply_method_error(call, p); - - sd_bus_error_set_errno(&berror, error); - - return synthetic_reply_method_error(call, &berror); -} - -int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) { - _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; - va_list ap; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - va_start(ap, format); - sd_bus_error_set_errnofv(&berror, error, format, ap); - va_end(ap); - - return synthetic_reply_method_error(call, &berror); -} - -int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - int r; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - r = sd_bus_message_new_method_return(call, &m); - if (r < 0) - return r; - - if (!isempty(types)) { - va_list ap; - - va_start(ap, types); - r = bus_message_append_ap(m, types, ap); - va_end(ap); - if (r < 0) - return r; - } - - return synthetic_driver_send(call->bus, m); -} - -int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; - int r; - - assert(call); - - if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) - return 0; - - r = sd_bus_message_new_method_return(call, &m); - if (r < 0) - return synthetic_reply_method_errno(call, r, NULL); - - r = sd_bus_message_append_strv(m, l); - if (r < 0) - return synthetic_reply_method_errno(call, r, NULL); - - return synthetic_driver_send(call->bus, m); -} - -int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL; - const char *name, *old_owner, *new_owner; - int r; - - assert(p); - assert(a); - assert(b); - assert(m); - - /* If we get NameOwnerChanged for our own name, we need to - * synthesize NameLost/NameAcquired, since socket clients need - * that, even though it is obsoleted on kdbus */ - - if (!a->is_kernel) - return 0; - - if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") || - !streq_ptr(m->path, "/org/freedesktop/DBus") || - !streq_ptr(m->sender, "org.freedesktop.DBus")) - return 0; - - r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner); - if (r < 0) - return r; - - r = sd_bus_message_rewind(m, true); - if (r < 0) - return r; - - if (streq(old_owner, a->unique_name)) { - - r = sd_bus_message_new_signal( - b, - &n, - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "NameLost"); - - } else if (streq(new_owner, a->unique_name)) { - - r = sd_bus_message_new_signal( - b, - &n, - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "NameAcquired"); - } else - return 0; - - if (r < 0) - return r; - - r = sd_bus_message_append(n, "s", name); - if (r < 0) - return r; - - r = bus_message_append_sender(n, "org.freedesktop.DBus"); - if (r < 0) - return r; - - r = sd_bus_message_set_destination(n, a->unique_name); - if (r < 0) - return r; - - r = bus_seal_synthetic_message(b, n); - if (r < 0) - return r; - - return sd_bus_send(b, n, NULL); -} diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h deleted file mode 100644 index 1b7197f8ec..0000000000 --- a/src/bus-proxyd/synthesize.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -/*** - 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 . -***/ - -#include "sd-bus.h" - -#include "proxy.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); - -int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e); -int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4); -int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p); -int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4); - -int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m); diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c deleted file mode 100644 index af7c9128a2..0000000000 --- a/src/bus-proxyd/test-bus-xml-policy.c +++ /dev/null @@ -1,170 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2014 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 . -***/ - -#include -#include -#include - -#include "sd-bus.h" - -#include "alloc-util.h" -#include "bus-xml-policy.h" -#include "log.h" -#include "string-util.h" -#include "strv.h" -#include "util.h" - -static int test_policy_load(Policy *p, const char *name) { - _cleanup_free_ char *path = NULL; - int r = 0; - - path = strjoin(TEST_DIR, "/bus-policy/", name, NULL); - assert_se(path); - - if (access(path, R_OK) == 0) - r = policy_load(p, STRV_MAKE(path)); - else - r = -ENOENT; - - return r; -} - -static int show_policy(const char *fn) { - Policy p = {}; - int r; - - r = policy_load(&p, STRV_MAKE(fn)); - if (r < 0) { - log_error_errno(r, "Failed to load policy %s: %m", fn); - return r; - } - - policy_dump(&p); - policy_free(&p); - - return 0; -} - -int main(int argc, char *argv[]) { - - Policy p = {}; - - printf("Showing session policy BEGIN\n"); - show_policy("/etc/dbus-1/session.conf"); - printf("Showing session policy END\n"); - - printf("Showing system policy BEGIN\n"); - show_policy("/etc/dbus-1/system.conf"); - printf("Showing system policy END\n"); - - /* Ownership tests */ - assert_se(test_policy_load(&p, "ownerships.conf") == 0); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test1") == true); - assert_se(policy_check_own(&p, 1, 0, "org.test.test1") == true); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test2") == true); - assert_se(policy_check_own(&p, 1, 0, "org.test.test2") == false); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test3") == false); - assert_se(policy_check_own(&p, 1, 0, "org.test.test3") == false); - - assert_se(policy_check_own(&p, 0, 0, "org.test.test4") == false); - assert_se(policy_check_own(&p, 1, 0, "org.test.test4") == true); - - policy_free(&p); - - /* Signaltest */ - assert_se(test_policy_load(&p, "signals.conf") == 0); - - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true); - assert_se(policy_check_one_send(&p, 1, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false); - - policy_free(&p); - - /* Method calls */ - assert_se(test_policy_load(&p, "methods.conf") == 0); - policy_dump(&p); - - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true); - - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true); - - policy_free(&p); - - /* User and groups */ - assert_se(test_policy_load(&p, "hello.conf") == 0); - policy_dump(&p); - - assert_se(policy_check_hello(&p, 0, 0) == true); - assert_se(policy_check_hello(&p, 1, 0) == false); - assert_se(policy_check_hello(&p, 0, 1) == false); - - policy_free(&p); - - /* dbus1 test file: ownership */ - - assert_se(test_policy_load(&p, "check-own-rules.conf") >= 0); - policy_dump(&p); - - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystem") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems") == true); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo") == true); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo.bar") == true); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo") == false); - assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo.bar") == false); - - policy_free(&p); - - /* dbus1 test file: many rules */ - - assert_se(test_policy_load(&p, "many-rules.conf") >= 0); - policy_dump(&p); - policy_free(&p); - - /* dbus1 test file: generic test */ - - assert_se(test_policy_load(&p, "test.conf") >= 0); - policy_dump(&p); - - assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService") == true); - assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService2") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false); - assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false); - assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); - - assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService") == false); - assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService2") == false); - assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false); - assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); - assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true); - assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false); - assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false); - - policy_free(&p); - - return EXIT_SUCCESS; -} diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c deleted file mode 100644 index 45d0a5ffce..0000000000 --- a/src/libsystemd/sd-bus/test-bus-proxy.c +++ /dev/null @@ -1,117 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2015 David Herrmann - - 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 . -***/ - -#include -#include -#include - -#include "sd-bus.h" - -#include "alloc-util.h" -#include "bus-dump.h" -#include "bus-kernel.h" -#include "bus-util.h" -#include "log.h" -#include "util.h" - -typedef struct { - const char *sender; - int matched_acquired; -} TestProxyMatch; - -static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error *error) { - TestProxyMatch *match = userdata; - const char *name; - int r; - - r = sd_bus_message_read(m, "s", &name); - assert_se(r >= 0); - - if (!streq_ptr(match->sender, name)) - return 0; - - ++match->matched_acquired; - return 1; -} - -static void test_proxy_matched(void) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *a = NULL; - _cleanup_free_ char *matchstr = NULL; - TestProxyMatch match = {}; - const char *me; - int r; - - /* open bus 'a' */ - - r = sd_bus_new(&a); - assert_se(r >= 0); - - r = sd_bus_set_address(a, "unix:path=/var/run/dbus/system_bus_socket"); - assert_se(r >= 0); - - r = sd_bus_set_bus_client(a, true); - assert_se(r >= 0); - - r = sd_bus_start(a); - assert_se(r >= 0); - - r = sd_bus_get_unique_name(a, &me); - assert_se(r >= 0); - - matchstr = strjoin("type='signal'," - "member='NameAcquired'," - "destination='", - me, - "'", - NULL); - assert_se(matchstr); - r = sd_bus_add_match(a, NULL, matchstr, test_proxy_acquired, &match); - assert_se(r >= 0); - - r = sd_bus_get_unique_name(a, &match.sender); - assert_se(r >= 0); - - /* barrier to guarantee proxy/dbus-daemon handled the previous data */ - r = sd_bus_call_method(a, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "GetId", - NULL, NULL, NULL); - assert_se(r >= 0); - - /* now we can be sure the Name* signals were sent */ - do { - r = sd_bus_process(a, NULL); - } while (r > 0); - assert_se(r == 0); - - assert_se(match.matched_acquired == 1); -} - -int main(int argc, char **argv) { - if (access("/var/run/dbus/system_bus_socket", F_OK) < 0) - return EXIT_TEST_SKIP; - - log_parse_environment(); - - test_proxy_matched(); - - return EXIT_SUCCESS; -} diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c new file mode 100644 index 0000000000..91eace90e2 --- /dev/null +++ b/src/stdio-bridge/stdio-bridge.c @@ -0,0 +1,301 @@ +/*** + 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 . +***/ + +#include +#include +#include +#include +#include +#include + +#include "sd-bus.h" +#include "sd-daemon.h" + +#include "bus-internal.h" +#include "bus-util.h" +#include "build.h" +#include "log.h" +#include "util.h" + +#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket" + +const char *arg_bus_path = DEFAULT_BUS_PATH; + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --bus-path=PATH Path to the kernel bus (default: %s)\n", + program_invocation_short_name, DEFAULT_BUS_PATH); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "bus-path", required_argument, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + help(); + return 0; + + case ARG_VERSION: + return version(); + + case '?': + return -EINVAL; + + case 'p': + arg_bus_path = optarg; + break; + + default: + log_error("Unknown option code %c", c); + return -EINVAL; + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL; + sd_id128_t server_id; + bool is_unix; + int r, in_fd, out_fd; + + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = sd_listen_fds(0); + if (r == 0) { + in_fd = STDIN_FILENO; + out_fd = STDOUT_FILENO; + } else if (r == 1) { + in_fd = SD_LISTEN_FDS_START; + out_fd = SD_LISTEN_FDS_START; + } else { + log_error("Illegal number of file descriptors passed\n"); + goto finish; + } + + is_unix = + sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && + sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; + + r = sd_bus_new(&a); + if (r < 0) { + log_error_errno(r, "Failed to allocate bus: %m"); + goto finish; + } + + r = sd_bus_set_address(a, arg_bus_path); + if (r < 0) { + log_error_errno(r, "Failed to set address to connect to: %m"); + goto finish; + } + + r = sd_bus_negotiate_fds(a, is_unix); + if (r < 0) { + log_error_errno(r, "Failed to set FD negotiation: %m"); + goto finish; + } + + r = sd_bus_start(a); + if (r < 0) { + log_error_errno(r, "Failed to start bus client: %m"); + goto finish; + } + + r = sd_bus_get_bus_id(a, &server_id); + if (r < 0) { + log_error_errno(r, "Failed to get server ID: %m"); + goto finish; + } + + r = sd_bus_new(&b); + if (r < 0) { + log_error_errno(r, "Failed to allocate bus: %m"); + goto finish; + } + + r = sd_bus_set_fd(b, in_fd, out_fd); + if (r < 0) { + log_error_errno(r, "Failed to set fds: %m"); + goto finish; + } + + r = sd_bus_set_server(b, 1, server_id); + if (r < 0) { + log_error_errno(r, "Failed to set server mode: %m"); + goto finish; + } + + r = sd_bus_negotiate_fds(b, is_unix); + if (r < 0) { + log_error_errno(r, "Failed to set FD negotiation: %m"); + goto finish; + } + + r = sd_bus_set_anonymous(b, true); + if (r < 0) { + log_error_errno(r, "Failed to set anonymous authentication: %m"); + goto finish; + } + + r = sd_bus_start(b); + if (r < 0) { + log_error_errno(r, "Failed to start bus client: %m"); + goto finish; + } + + for (;;) { + _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; + int events_a, events_b, fd; + uint64_t timeout_a, timeout_b, t; + struct timespec _ts, *ts; + + r = sd_bus_process(a, &m); + if (r < 0) { + log_error_errno(r, "Failed to process bus a: %m"); + goto finish; + } + + if (m) { + r = sd_bus_send(b, m, NULL); + if (r < 0) { + log_error_errno(r, "Failed to send message: %m"); + goto finish; + } + } + + if (r > 0) + continue; + + r = sd_bus_process(b, &m); + if (r < 0) { + /* treat 'connection reset by peer' as clean exit condition */ + if (r == -ECONNRESET) + r = 0; + + goto finish; + } + + if (m) { + r = sd_bus_send(a, m, NULL); + if (r < 0) { + log_error_errno(r, "Failed to send message: %m"); + goto finish; + } + } + + if (r > 0) + continue; + + fd = sd_bus_get_fd(a); + if (fd < 0) { + log_error_errno(r, "Failed to get fd: %m"); + goto finish; + } + + events_a = sd_bus_get_events(a); + if (events_a < 0) { + log_error_errno(r, "Failed to get events mask: %m"); + goto finish; + } + + r = sd_bus_get_timeout(a, &timeout_a); + if (r < 0) { + log_error_errno(r, "Failed to get timeout: %m"); + goto finish; + } + + events_b = sd_bus_get_events(b); + if (events_b < 0) { + log_error_errno(r, "Failed to get events mask: %m"); + goto finish; + } + + r = sd_bus_get_timeout(b, &timeout_b); + if (r < 0) { + log_error_errno(r, "Failed to get timeout: %m"); + goto finish; + } + + t = timeout_a; + if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a)) + t = timeout_b; + + if (t == (uint64_t) -1) + ts = NULL; + else { + usec_t nw; + + nw = now(CLOCK_MONOTONIC); + if (t > nw) + t -= nw; + else + t = 0; + + ts = timespec_store(&_ts, t); + } + + { + struct pollfd p[3] = { + {.fd = fd, .events = events_a, }, + {.fd = STDIN_FILENO, .events = events_b & POLLIN, }, + {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }}; + + r = ppoll(p, ELEMENTSOF(p), ts, NULL); + } + if (r < 0) { + log_error("ppoll() failed: %m"); + goto finish; + } + } + + r = 0; + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/test/test-tables.c b/src/test/test-tables.c index aef992ee3c..0be74921fc 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -19,7 +19,6 @@ #include "architecture.h" #include "automount.h" -#include "bus-xml-policy.h" #include "busname.h" #include "cgroup.h" #include "compress.h" @@ -83,8 +82,6 @@ int main(int argc, char **argv) { test_table(path_result, PATH_RESULT); test_table(path_state, PATH_STATE); test_table(path_type, PATH_TYPE); - test_table(policy_item_class, POLICY_ITEM_CLASS); - test_table(policy_item_type, POLICY_ITEM_TYPE); test_table(protect_home, PROTECT_HOME); test_table(protect_system, PROTECT_SYSTEM); test_table(rlimit, RLIMIT); diff --git a/sysusers.d/systemd.conf.m4 b/sysusers.d/systemd.conf.m4 index 317240a9fd..af97509c05 100644 --- a/sysusers.d/systemd.conf.m4 +++ b/sysusers.d/systemd.conf.m4 @@ -6,7 +6,6 @@ # (at your option) any later version. g systemd-journal - - -u systemd-bus-proxy - "systemd Bus Proxy" m4_ifdef(`ENABLE_NETWORKD', u systemd-network - "systemd Network Management" )m4_dnl diff --git a/units/.gitignore b/units/.gitignore index 2fff20a052..e62fd01466 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -1,4 +1,3 @@ -/systemd-bus-proxyd.service.m4 /user@.service.m4 /console-getty.service /console-getty.service.m4 @@ -24,7 +23,6 @@ /systemd-backlight@.service /systemd-binfmt.service /systemd-bootchart.service -/systemd-bus-proxyd.service /systemd-coredump@.service /systemd-firstboot.service /systemd-fsck-root.service diff --git a/units/systemd-bus-proxyd.service.m4.in b/units/systemd-bus-proxyd.service.m4.in deleted file mode 100644 index e75cdb1a59..0000000000 --- a/units/systemd-bus-proxyd.service.m4.in +++ /dev/null @@ -1,25 +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. - -[Unit] -Description=Legacy D-Bus Protocol Compatibility Daemon - -[Service] -ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/0-system/bus -ExecReload=@bindir@/busctl --address=unix:path=/run/dbus/system_bus_socket call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus ReloadConfig -NotifyAccess=main -CapabilityBoundingSet=CAP_IPC_OWNER CAP_SETUID CAP_SETGID CAP_SETPCAP m4_ifdef(`HAVE_SMACK', CAP_MAC_ADMIN ) -PrivateTmp=yes -PrivateDevices=yes -PrivateNetwork=yes -ProtectSystem=full -ProtectHome=yes - -# The proxy manages connections of all users, so it needs an elevated file -# limit. It does proper per-user accounting (indirectly via kdbus), therefore, -# the effective per-user limits stay the same. -LimitNOFILE=16384 diff --git a/units/systemd-bus-proxyd.socket b/units/systemd-bus-proxyd.socket deleted file mode 100644 index 3f80a1d547..0000000000 --- a/units/systemd-bus-proxyd.socket +++ /dev/null @@ -1,12 +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. - -[Unit] -Description=Legacy D-Bus Protocol Compatibility Socket - -[Socket] -ListenStream=/var/run/dbus/system_bus_socket diff --git a/units/user/.gitignore b/units/user/.gitignore index ce9df9e7e1..41a74f5461 100644 --- a/units/user/.gitignore +++ b/units/user/.gitignore @@ -1,2 +1 @@ /systemd-exit.service -/systemd-bus-proxyd.service diff --git a/units/user/systemd-bus-proxyd.service.in b/units/user/systemd-bus-proxyd.service.in deleted file mode 100644 index 6f79707b46..0000000000 --- a/units/user/systemd-bus-proxyd.service.in +++ /dev/null @@ -1,14 +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. - -[Unit] -Description=Legacy D-Bus Protocol Compatibility Daemon - -[Service] -ExecStart=@rootlibexecdir@/systemd-bus-proxyd --address=kernel:path=/sys/fs/kdbus/%U-user/bus -ExecReload=@bindir@/busctl --address=unix:path=/run/user/%U/bus call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus ReloadConfig -NotifyAccess=main diff --git a/units/user/systemd-bus-proxyd.socket b/units/user/systemd-bus-proxyd.socket deleted file mode 100644 index b9efc0e7ce..0000000000 --- a/units/user/systemd-bus-proxyd.socket +++ /dev/null @@ -1,12 +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. - -[Unit] -Description=Legacy D-Bus Protocol Compatibility Socket - -[Socket] -ListenStream=%t/bus -- cgit v1.2.3-54-g00ecf From 32c1f5a57998f2a9e1992af006b83e39e3155830 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Feb 2016 21:29:01 +0100 Subject: time-util: map ALARM clockids to non-ALARM clockids in now() Fixes: #2597 --- src/basic/time-util.c | 24 ++++++++++++++++++++++-- src/libsystemd/sd-event/sd-event.c | 6 +++++- 2 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 3973850b44..510f018d9b 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -42,10 +42,30 @@ static nsec_t timespec_load_nsec(const struct timespec *ts); +static clockid_t map_clock_id(clockid_t c) { + + /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will + * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is + * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on + * those archs. */ + + switch (c) { + + case CLOCK_BOOTTIME_ALARM: + return CLOCK_BOOTTIME; + + case CLOCK_REALTIME_ALARM: + return CLOCK_REALTIME; + + default: + return c; + } +} + usec_t now(clockid_t clock_id) { struct timespec ts; - assert_se(clock_gettime(clock_id, &ts) == 0); + assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0); return timespec_load(&ts); } @@ -53,7 +73,7 @@ usec_t now(clockid_t clock_id) { nsec_t now_nsec(clockid_t clock_id) { struct timespec ts; - assert_se(clock_gettime(clock_id, &ts) == 0); + assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0); return timespec_load_nsec(&ts); } diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index deef6ba9d3..2b46a1ff06 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -2780,9 +2780,13 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { *usec = e->timestamp.monotonic; break; - default: + case CLOCK_BOOTTIME: + case CLOCK_BOOTTIME_ALARM: *usec = e->timestamp_boottime; break; + + default: + assert_not_reached("Unknown clock?"); } return 0; -- cgit v1.2.3-54-g00ecf From b895d15511526b7046c8c51e6689684144a63ae0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Feb 2016 21:33:39 +0100 Subject: core: fix indenting in dump output Fixes: #2593 --- src/core/unit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index d39e3dcaeb..3c4f85e744 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -888,7 +888,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tInstance: %s\n" "%s\tUnit Load State: %s\n" "%s\tUnit Active State: %s\n" - "%s\nState Change Timestamp: %s\n" + "%s\tState Change Timestamp: %s\n" "%s\tInactive Exit Timestamp: %s\n" "%s\tActive Enter Timestamp: %s\n" "%s\tActive Exit Timestamp: %s\n" -- cgit v1.2.3-54-g00ecf From 6d99904f5a263cc119ac79718d83d7136dde349d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 31 Jan 2016 00:10:42 -0500 Subject: test-dns-packet: add framework to read and dump packets Packets are stored in a simple format: ... Packets for some example domains are dumped, to test rr code for various record types. Currently: A AAAA CAA DNSKEY LOC MX NS NSEC OPENPGPKEY SOA SPF TXT The hashing code is executed, but results are not checked. Also build other tests in src/resolve only with --enable-resolve. --- .gitignore | 1 + Makefile.am | 91 ++++++++++--------- src/resolve/resolved-dns-rr.c | 2 +- src/resolve/resolved-dns-rr.h | 2 + .../test-data/_openpgpkey.fedoraproject.org.pkts | Bin 0 -> 986 bytes src/resolve/test-data/fedoraproject.org.pkts | Bin 0 -> 1483 bytes src/resolve/test-data/gandi.net.pkts | Bin 0 -> 1010 bytes src/resolve/test-data/google.com.pkts | Bin 0 -> 747 bytes src/resolve/test-data/root.pkts | Bin 0 -> 1061 bytes ...sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts | Bin 0 -> 330 bytes src/resolve/test-data/teamits.com.pkts | Bin 0 -> 1021 bytes .../test-data/zbyszek@fedoraproject.org.pkts | Bin 0 -> 2533 bytes src/resolve/test-dns-packet.c | 100 +++++++++++++++++++++ 13 files changed, 149 insertions(+), 47 deletions(-) create mode 100644 src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts create mode 100644 src/resolve/test-data/fedoraproject.org.pkts create mode 100644 src/resolve/test-data/gandi.net.pkts create mode 100644 src/resolve/test-data/google.com.pkts create mode 100644 src/resolve/test-data/root.pkts create mode 100644 src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts create mode 100644 src/resolve/test-data/teamits.com.pkts create mode 100644 src/resolve/test-data/zbyszek@fedoraproject.org.pkts create mode 100644 src/resolve/test-dns-packet.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 586b3796b1..81b97c4add 100644 --- a/.gitignore +++ b/.gitignore @@ -184,6 +184,7 @@ /test-dhcp-server /test-dhcp6-client /test-dns-domain +/test-dns-packet /test-dnssec /test-efi-disk.img /test-ellipsize diff --git a/Makefile.am b/Makefile.am index e63015476c..4e6a27a77d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1501,6 +1501,7 @@ tests += \ test-af-list \ test-arphrd-list \ test-dns-domain \ + test-dns-packet \ test-resolve-tables \ test-install-root \ test-rlimit-util \ @@ -1666,16 +1667,6 @@ test_dns_domain_LDADD = \ libsystemd-network.la \ libshared.la -test_resolve_tables_SOURCES = \ - src/resolve/test-resolve-tables.c \ - src/shared/test-tables.h \ - src/resolve/dns-type.c \ - src/resolve/dns-type.h \ - src/resolve/dns_type-from-name.h \ - src/resolve/dns_type-to-name.h - -test_resolve_tables_LDADD = \ - libshared.la if ENABLE_EFI manual_tests += \ @@ -5166,6 +5157,20 @@ EXTRA_DIST += \ # ------------------------------------------------------------------------------ if ENABLE_RESOLVED +basic_dns_sources = \ + src/resolve/resolved-dns-dnssec.c \ + src/resolve/resolved-dns-dnssec.h \ + src/resolve/resolved-dns-packet.c \ + src/resolve/resolved-dns-packet.h \ + src/resolve/resolved-dns-rr.c \ + src/resolve/resolved-dns-rr.h \ + src/resolve/resolved-dns-answer.c \ + src/resolve/resolved-dns-answer.h \ + src/resolve/resolved-dns-question.c \ + src/resolve/resolved-dns-question.h \ + src/resolve/dns-type.c \ + src/resolve/dns-type.h + systemd_resolved_SOURCES = \ src/resolve/resolved.c \ src/resolve/resolved-manager.c \ @@ -5185,14 +5190,7 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-mdns.h \ src/resolve/resolved-mdns.c \ src/resolve/resolved-def.h \ - src/resolve/resolved-dns-rr.h \ - src/resolve/resolved-dns-rr.c \ - src/resolve/resolved-dns-question.h \ - src/resolve/resolved-dns-question.c \ - src/resolve/resolved-dns-answer.h \ - src/resolve/resolved-dns-answer.c \ - src/resolve/resolved-dns-packet.h \ - src/resolve/resolved-dns-packet.c \ + $(basic_dns_sources) \ src/resolve/resolved-dns-query.h \ src/resolve/resolved-dns-query.c \ src/resolve/resolved-dns-synthesize.h \ @@ -5211,14 +5209,10 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-dns-zone.c \ src/resolve/resolved-dns-stream.h \ src/resolve/resolved-dns-stream.c \ - src/resolve/resolved-dns-dnssec.h \ - src/resolve/resolved-dns-dnssec.c \ src/resolve/resolved-dns-trust-anchor.h \ src/resolve/resolved-dns-trust-anchor.c \ src/resolve/resolved-etc-hosts.h \ src/resolve/resolved-etc-hosts.c \ - src/resolve/dns-type.c \ - src/resolve/dns-type.h \ src/shared/gcrypt-util.c \ src/shared/gcrypt-util.h @@ -5280,18 +5274,7 @@ lib_LTLIBRARIES += \ systemd_resolve_SOURCES = \ src/resolve/resolve-tool.c \ - src/resolve/resolved-dns-dnssec.c \ - src/resolve/resolved-dns-dnssec.h \ - src/resolve/resolved-dns-packet.c \ - src/resolve/resolved-dns-packet.h \ - src/resolve/resolved-dns-rr.c \ - src/resolve/resolved-dns-rr.h \ - src/resolve/resolved-dns-answer.c \ - src/resolve/resolved-dns-answer.h \ - src/resolve/resolved-dns-question.c \ - src/resolve/resolved-dns-question.h \ - src/resolve/dns-type.c \ - src/resolve/dns-type.h \ + $(basic_dns_sources) \ src/shared/gcrypt-util.c \ src/shared/gcrypt-util.h @@ -5312,20 +5295,36 @@ tests += \ manual_tests += \ test-dnssec-complex +test_resolve_tables_SOURCES = \ + src/resolve/test-resolve-tables.c \ + src/resolve/dns_type-from-name.h \ + src/resolve/dns_type-to-name.h \ + $(basic_dns_sources) \ + src/shared/test-tables.h + +test_resolve_tables_LDADD = \ + libshared.la + +test_dns_packet_SOURCES = \ + src/resolve/test-dns-packet.c \ + $(basic_dns_sources) + +test_dns_packet_LDADD = \ + libshared.la + +EXTRA_DIST += \ + src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts \ + src/resolve/test-data/fedoraproject.org.pkts \ + src/resolve/test-data/gandi.net.pkts \ + src/resolve/test-data/google.com.pkts \ + src/resolve/test-data/root.pkts \ + src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts \ + src/resolve/test-data/teamits.com.pkts \ + src/resolve/test-data/zbyszek@fedoraproject.org.pkts + test_dnssec_SOURCES = \ src/resolve/test-dnssec.c \ - src/resolve/resolved-dns-packet.c \ - src/resolve/resolved-dns-packet.h \ - src/resolve/resolved-dns-rr.c \ - src/resolve/resolved-dns-rr.h \ - src/resolve/resolved-dns-answer.c \ - src/resolve/resolved-dns-answer.h \ - src/resolve/resolved-dns-question.c \ - src/resolve/resolved-dns-question.h \ - src/resolve/resolved-dns-dnssec.c \ - src/resolve/resolved-dns-dnssec.h \ - src/resolve/dns-type.c \ - src/resolve/dns-type.h + $(basic_dns_sources) test_dnssec_LDADD = \ libshared.la diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 783ec7516c..2803ec017e 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1302,7 +1302,7 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr) { return !r; } -static void dns_resource_record_hash_func(const void *i, struct siphash *state) { +void dns_resource_record_hash_func(const void *i, struct siphash *state) { const DnsResourceRecord *rr = i; assert(rr); diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 37c4487332..01c7091645 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -325,6 +325,8 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr); DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); +void dns_resource_record_hash_func(const void *i, struct siphash *state); + extern const struct hash_ops dns_resource_key_hash_ops; extern const struct hash_ops dns_resource_record_hash_ops; diff --git a/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts b/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts new file mode 100644 index 0000000000..15de02e997 Binary files /dev/null and b/src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts differ diff --git a/src/resolve/test-data/fedoraproject.org.pkts b/src/resolve/test-data/fedoraproject.org.pkts new file mode 100644 index 0000000000..17874844d9 Binary files /dev/null and b/src/resolve/test-data/fedoraproject.org.pkts differ diff --git a/src/resolve/test-data/gandi.net.pkts b/src/resolve/test-data/gandi.net.pkts new file mode 100644 index 0000000000..5ef51e0c8e Binary files /dev/null and b/src/resolve/test-data/gandi.net.pkts differ diff --git a/src/resolve/test-data/google.com.pkts b/src/resolve/test-data/google.com.pkts new file mode 100644 index 0000000000..f98c4cd855 Binary files /dev/null and b/src/resolve/test-data/google.com.pkts differ diff --git a/src/resolve/test-data/root.pkts b/src/resolve/test-data/root.pkts new file mode 100644 index 0000000000..54ba668c75 Binary files /dev/null and b/src/resolve/test-data/root.pkts differ diff --git a/src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts b/src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts new file mode 100644 index 0000000000..a854249532 Binary files /dev/null and b/src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts differ diff --git a/src/resolve/test-data/teamits.com.pkts b/src/resolve/test-data/teamits.com.pkts new file mode 100644 index 0000000000..11deb39677 Binary files /dev/null and b/src/resolve/test-data/teamits.com.pkts differ diff --git a/src/resolve/test-data/zbyszek@fedoraproject.org.pkts b/src/resolve/test-data/zbyszek@fedoraproject.org.pkts new file mode 100644 index 0000000000..f0a6f982df Binary files /dev/null and b/src/resolve/test-data/zbyszek@fedoraproject.org.pkts differ diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c new file mode 100644 index 0000000000..d8a5d9bbef --- /dev/null +++ b/src/resolve/test-dns-packet.c @@ -0,0 +1,100 @@ +/*** + This file is part of systemd + + Copyright 2016 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 . +***/ + +#include + +#include "alloc-util.h" +#include "fileio.h" +#include "macro.h" +#include "log.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" +#include "string-util.h" + +#define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1) + +static uint64_t hash(DnsResourceRecord *rr) { + struct siphash state; + + siphash24_init(&state, HASH_KEY.bytes); + dns_resource_record_hash_func(rr, &state); + return siphash24_finalize(&state); +} + +static void test_packet_from_file(const char* filename, bool canonical) { + _cleanup_free_ char *data = NULL; + size_t data_size, packet_size, offset; + + assert_se(read_full_file(filename, &data, &data_size) >= 0); + assert_se(data); + assert_se(data_size > 8); + + log_info("============== %s %s==============", filename, canonical ? "canonical " : ""); + + for (offset = 0; offset < data_size; offset += 8 + packet_size) { + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL, *p2 = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL, *rr2 = NULL; + const char *s, *s2; + uint64_t hash1, hash2; + + packet_size = le64toh( *(uint64_t*)(data + offset) ); + assert_se(packet_size > 0); + assert_se(offset + 8 + packet_size <= data_size); + + assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0) >= 0); + + assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0); + assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0); + + s = dns_resource_record_to_string(rr); + assert_se(s); + puts(s); + + hash1 = hash(rr); + + assert_se(dns_resource_record_to_wire_format(rr, canonical) >= 0); + + assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0) >= 0); + assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0); + assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0); + + s2 = dns_resource_record_to_string(rr); + assert_se(s2); + assert_se(streq(s, s2)); + + hash2 = hash(rr); + assert_se(hash1 == hash2); + } +} + +int main(int argc, char **argv) { + int i; + + log_parse_environment(); + + for (i = 1; i < argc; i++) { + test_packet_from_file(argv[i], false); + puts(""); + test_packet_from_file(argv[i], true); + if (i + 1 < argc) + puts(""); + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3-54-g00ecf From fff85dbe15475c35fed2af66fabef3bdfb94f389 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 11 Feb 2016 09:18:32 -0500 Subject: test-dns-packet: allow running without arguments --- Makefile.am | 4 ++++ src/resolve/test-dns-packet.c | 27 +++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 4e6a27a77d..754772156c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5309,6 +5309,10 @@ test_dns_packet_SOURCES = \ src/resolve/test-dns-packet.c \ $(basic_dns_sources) +test_dns_packet_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DRESOLVE_TEST_DIR=\"$(abs_top_srcdir)/src/resolve/test-data\" + test_dns_packet_LDADD = \ libshared.la diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index d8a5d9bbef..1abbd3fa2e 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -18,14 +18,17 @@ ***/ #include +#include #include "alloc-util.h" #include "fileio.h" -#include "macro.h" +#include "glob-util.h" #include "log.h" +#include "macro.h" #include "resolved-dns-packet.h" #include "resolved-dns-rr.h" #include "string-util.h" +#include "strv.h" #define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1) @@ -84,15 +87,27 @@ static void test_packet_from_file(const char* filename, bool canonical) { } int main(int argc, char **argv) { - int i; + int i, N; + _cleanup_globfree_ glob_t g = {}; + _cleanup_strv_free_ char **globs = NULL; + char **fnames; log_parse_environment(); - for (i = 1; i < argc; i++) { - test_packet_from_file(argv[i], false); + if (argc >= 2) { + N = argc - 1; + fnames = argv + 1; + } else { + assert_se(glob(RESOLVE_TEST_DIR "/*.pkts", GLOB_NOSORT, NULL, &g) == 0); + N = g.gl_pathc; + fnames = g.gl_pathv; + } + + for (i = 0; i < N; i++) { + test_packet_from_file(fnames[i], false); puts(""); - test_packet_from_file(argv[i], true); - if (i + 1 < argc) + test_packet_from_file(fnames[i], true); + if (i + 1 < N) puts(""); } -- cgit v1.2.3-54-g00ecf From fa45182ed6b833017dde5a7cee27cdf25985790a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 31 Jan 2016 16:23:00 -0500 Subject: Fix hashing of TLSA packets Also add example files with TLSA and SSHFP records. --- Makefile.am | 4 +++- src/resolve/resolved-dns-rr.c | 2 +- src/resolve/test-data/_443._tcp.fedoraproject.org.pkts | Bin 0 -> 169 bytes src/resolve/test-data/kyhwana.org.pkts | Bin 0 -> 1803 bytes 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 src/resolve/test-data/_443._tcp.fedoraproject.org.pkts create mode 100644 src/resolve/test-data/kyhwana.org.pkts (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 754772156c..8ab04e74ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5324,7 +5324,9 @@ EXTRA_DIST += \ src/resolve/test-data/root.pkts \ src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts \ src/resolve/test-data/teamits.com.pkts \ - src/resolve/test-data/zbyszek@fedoraproject.org.pkts + src/resolve/test-data/zbyszek@fedoraproject.org.pkts \ + src/resolve/test-data/_443._tcp.fedoraproject.org.pkts \ + src/resolve/test-data/kyhwana.org.pkts test_dnssec_SOURCES = \ src/resolve/test-dnssec.c \ diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 2803ec017e..422bbe4bc4 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1429,7 +1429,7 @@ void dns_resource_record_hash_func(const void *i, struct siphash *state) { siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state); siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state); siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state); - siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state); + siphash24_compress(rr->tlsa.data, rr->tlsa.data_size, state); break; case DNS_TYPE_OPENPGPKEY: diff --git a/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts b/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts new file mode 100644 index 0000000000..a383c6286d Binary files /dev/null and b/src/resolve/test-data/_443._tcp.fedoraproject.org.pkts differ diff --git a/src/resolve/test-data/kyhwana.org.pkts b/src/resolve/test-data/kyhwana.org.pkts new file mode 100644 index 0000000000..e28a725c9a Binary files /dev/null and b/src/resolve/test-data/kyhwana.org.pkts differ -- cgit v1.2.3-54-g00ecf From 95052df3760523e1f3bb9705c918d85aae7fb431 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 31 Jan 2016 16:21:00 -0500 Subject: resolve: parse CAA records --- src/basic/escape.c | 28 ++++++++++++++++++++++++++++ src/basic/escape.h | 1 + src/resolve/resolved-dns-packet.c | 27 +++++++++++++++++++++++++++ src/resolve/resolved-dns-rr.c | 36 ++++++++++++++++++++++++++++++++++++ src/resolve/resolved-dns-rr.h | 8 ++++++++ 5 files changed, 100 insertions(+) (limited to 'src') diff --git a/src/basic/escape.c b/src/basic/escape.c index f276c36c56..d59aa9f42f 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -415,6 +415,34 @@ char *xescape(const char *s, const char *bad) { return r; } +char *octescape(const char *s, size_t len) { + char *r, *t; + const char *f; + + /* Escapes all chars in bad, in addition to \ and " chars, + * in \nnn style escaping. */ + + r = new(char, len * 4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; f < s + len; f++) { + + if (*f < ' ' || *f >= 127 || *f == '\\' || *f == '"') { + *(t++) = '\\'; + *(t++) = '0' + (*f >> 6); + *(t++) = '0' + ((*f >> 3) & 8); + *(t++) = '0' + (*f & 8); + } else + *(t++) = *f; + } + + *t = 0; + + return r; + +} + static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { assert(bad); diff --git a/src/basic/escape.h b/src/basic/escape.h index ac8f5f3910..bc25646a3d 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -50,6 +50,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit); char *xescape(const char *s, const char *bad); +char *octescape(const char *s, size_t len); char *shell_escape(const char *s, const char *bad); char *shell_maybe_quote(const char *s); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 6a9a1f732d..4c4d16d109 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -1086,6 +1086,18 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL); break; + case DNS_TYPE_CAA: + r = dns_packet_append_uint8(p, rr->caa.flags, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_string(p, rr->caa.tag, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, rr->caa.value, rr->caa.value_size, NULL); + break; + case DNS_TYPE_OPT: case DNS_TYPE_OPENPGPKEY: case _DNS_TYPE_INVALID: /* unparseable */ @@ -1967,6 +1979,21 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl break; + case DNS_TYPE_CAA: + r = dns_packet_read_uint8(p, &rr->caa.flags, NULL); + if (r < 0) + return r; + + r = dns_packet_read_string(p, &rr->caa.tag, NULL); + if (r < 0) + return r; + + r = dns_packet_read_memdup(p, + rdlength + offset - p->rindex, + &rr->caa.value, &rr->caa.value_size, NULL); + + break; + case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */ case DNS_TYPE_OPENPGPKEY: default: diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 422bbe4bc4..35c0de1a6d 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -24,6 +24,7 @@ #include "alloc-util.h" #include "dns-domain.h" #include "dns-type.h" +#include "escape.h" #include "hexdecoct.h" #include "resolved-dns-dnssec.h" #include "resolved-dns-packet.h" @@ -492,6 +493,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { free(rr->tlsa.data); break; + case DNS_TYPE_CAA: + free(rr->caa.tag); + free(rr->caa.value); + break; + case DNS_TYPE_OPENPGPKEY: default: free(rr->generic.data); @@ -699,6 +705,12 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor a->tlsa.matching_type == b->tlsa.matching_type && FIELD_EQUAL(a->tlsa, b->tlsa, data); + case DNS_TYPE_CAA: + return a->caa.flags == b->caa.flags && + streq(a->caa.tag, b->caa.tag) && + FIELD_EQUAL(a->caa, b->caa, value); + + case DNS_TYPE_OPENPGPKEY: default: return FIELD_EQUAL(a->generic, b->generic, data); } @@ -1142,6 +1154,24 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { break; } + case DNS_TYPE_CAA: { + _cleanup_free_ char *value; + + value = octescape(rr->caa.value, rr->caa.value_size); + if (!value) + return NULL; + + r = asprintf(&s, "%s %u %s \"%s\"", + k, + rr->caa.flags, + rr->caa.tag, + value); + if (r < 0) + return NULL; + + break; + } + case DNS_TYPE_OPENPGPKEY: { int n; @@ -1432,6 +1462,12 @@ void dns_resource_record_hash_func(const void *i, struct siphash *state) { siphash24_compress(rr->tlsa.data, rr->tlsa.data_size, state); break; + case DNS_TYPE_CAA: + siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state); + string_hash_func(rr->caa.tag, state); + siphash24_compress(rr->caa.value, rr->caa.value_size, state); + break; + case DNS_TYPE_OPENPGPKEY: default: siphash24_compress(rr->generic.data, rr->generic.data_size, state); diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 01c7091645..b75676912b 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -251,6 +251,14 @@ struct DnsResourceRecord { void *data; size_t data_size; } tlsa; + + /* https://tools.ietf.org/html/rfc6844 */ + struct { + uint8_t flags; + char *tag; + void *value; + size_t value_size; + } caa; }; }; -- cgit v1.2.3-54-g00ecf From 718af59e9ac1a525b0a73b99a74bc376f1b4d49d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 1 Feb 2016 21:35:44 -0500 Subject: resolve: always align flags to 8th column and print CAA flags Left-over unknown flags are printed numerically. Otherwise, it wouldn't be known what bits are remaining without knowning what the known bits are. A test case is added to verify the flag printing code: ============== src/resolve/test-data/fake-caa.pkts ============== google.com. IN CAA 0 issue "symantec.com" google.com. IN CAA 128 issue "symantec.com" -- Flags: critical google.com. IN CAA 129 issue "symantec.com" -- Flags: critical 1 google.com. IN CAA 22 issue "symantec.com" -- Flags: 22 --- Makefile.am | 3 ++- src/resolve/dns-type.h | 3 +++ src/resolve/resolved-dns-rr.c | 31 ++++++++++++++++--------------- src/resolve/test-data/fake-caa.pkts | Bin 0 -> 196 bytes 4 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 src/resolve/test-data/fake-caa.pkts (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 8ab04e74ba..5d39967f2c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5326,7 +5326,8 @@ EXTRA_DIST += \ src/resolve/test-data/teamits.com.pkts \ src/resolve/test-data/zbyszek@fedoraproject.org.pkts \ src/resolve/test-data/_443._tcp.fedoraproject.org.pkts \ - src/resolve/test-data/kyhwana.org.pkts + src/resolve/test-data/kyhwana.org.pkts \ + src/resolve/test-data/fake-caa.pkts test_dnssec_SOURCES = \ src/resolve/test-dnssec.c \ diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index d025544bab..ea51dfdb65 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -154,3 +154,6 @@ const char *tlsa_selector_to_string(uint8_t selector); /* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.4 */ const char *tlsa_matching_type_to_string(uint8_t selector); + +/* https://tools.ietf.org/html/rfc6844#section-5.1 */ +#define CAA_FLAG_CRITICAL (1u << 7) diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 35c0de1a6d..d54645fc7a 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -980,7 +980,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { case DNS_TYPE_DNSKEY: { _cleanup_free_ char *alg = NULL; char *ss; - int n, n1; + int n; uint16_t key_tag; key_tag = dnssec_keytag(rr, true); @@ -989,9 +989,8 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (r < 0) return NULL; - r = asprintf(&s, "%s %n%u %u %s %n", + r = asprintf(&s, "%s %u %u %s %n", k, - &n1, rr->dnskey.flags, rr->dnskey.protocol, alg, @@ -1006,14 +1005,12 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { return NULL; r = asprintf(&ss, "%s\n" - "%*s-- Flags:%s%s%s\n" - "%*s-- Key tag: %u", + " -- Flags:%s%s%s\n" + " -- Key tag: %u", s, - n1, "", rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "", rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "", rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "", - n1, "", key_tag); if (r < 0) return NULL; @@ -1139,13 +1136,13 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { return NULL; r = asprintf(&ss, "%s\n" - "%*s-- Cert. usage: %s\n" - "%*s-- Selector: %s\n" - "%*s-- Matching type: %s", + " -- Cert. usage: %s\n" + " -- Selector: %s\n" + " -- Matching type: %s", s, - n - 6, "", cert_usage, - n - 6, "", selector, - n - 6, "", matching_type); + cert_usage, + selector, + matching_type); if (r < 0) return NULL; free(s); @@ -1161,11 +1158,15 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (!value) return NULL; - r = asprintf(&s, "%s %u %s \"%s\"", + r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u", k, rr->caa.flags, rr->caa.tag, - value); + value, + rr->caa.flags ? "\n -- Flags:" : "", + rr->caa.flags & CAA_FLAG_CRITICAL ? " critical" : "", + rr->caa.flags & ~CAA_FLAG_CRITICAL ? " " : "", + rr->caa.flags & ~CAA_FLAG_CRITICAL); if (r < 0) return NULL; diff --git a/src/resolve/test-data/fake-caa.pkts b/src/resolve/test-data/fake-caa.pkts new file mode 100644 index 0000000000..1c3ecc5491 Binary files /dev/null and b/src/resolve/test-data/fake-caa.pkts differ -- cgit v1.2.3-54-g00ecf From 4de282cf9324ab13d17ac334244d0d7cae2df37d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Feb 2016 22:51:55 +0100 Subject: build-sys: drop libsystemd-{id128,daemon,login,journal}.so compat libs They have long been obsolete, and upstream distros and packages have mostly switched over, let's get rid of it for good. --- .gitignore | 1 - Makefile.am | 139 ------------------------------- autogen.sh | 10 +-- configure.ac | 12 --- src/compat-libs/.gitignore | 1 - src/compat-libs/libsystemd-daemon.pc.in | 19 ----- src/compat-libs/libsystemd-daemon.sym | 27 ------ src/compat-libs/libsystemd-id128.pc.in | 18 ---- src/compat-libs/libsystemd-id128.sym | 21 ----- src/compat-libs/libsystemd-journal.pc.in | 19 ----- src/compat-libs/libsystemd-journal.sym | 111 ------------------------ src/compat-libs/libsystemd-login.pc.in | 18 ---- src/compat-libs/libsystemd-login.sym | 87 ------------------- src/compat-libs/linkwarning.h | 35 -------- 14 files changed, 5 insertions(+), 513 deletions(-) delete mode 100644 src/compat-libs/.gitignore delete mode 100644 src/compat-libs/libsystemd-daemon.pc.in delete mode 100644 src/compat-libs/libsystemd-daemon.sym delete mode 100644 src/compat-libs/libsystemd-id128.pc.in delete mode 100644 src/compat-libs/libsystemd-id128.sym delete mode 100644 src/compat-libs/libsystemd-journal.pc.in delete mode 100644 src/compat-libs/libsystemd-journal.sym delete mode 100644 src/compat-libs/libsystemd-login.pc.in delete mode 100644 src/compat-libs/libsystemd-login.sym delete mode 100644 src/compat-libs/linkwarning.h (limited to 'src') diff --git a/.gitignore b/.gitignore index 586b3796b1..2b27d541c7 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,6 @@ /hostnamectl /install-tree /journalctl -/libsystemd-*.c /libtool /linuxx64.efi.stub /localectl diff --git a/Makefile.am b/Makefile.am index 5a8fc2fe23..adaf2920e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,24 +46,6 @@ LIBSYSTEMD_CURRENT=14 LIBSYSTEMD_REVISION=0 LIBSYSTEMD_AGE=14 -# The following four libraries only exist for compatibility reasons, -# their version info should not be bumped anymore -LIBSYSTEMD_LOGIN_CURRENT=9 -LIBSYSTEMD_LOGIN_REVISION=3 -LIBSYSTEMD_LOGIN_AGE=9 - -LIBSYSTEMD_DAEMON_CURRENT=0 -LIBSYSTEMD_DAEMON_REVISION=12 -LIBSYSTEMD_DAEMON_AGE=0 - -LIBSYSTEMD_ID128_CURRENT=0 -LIBSYSTEMD_ID128_REVISION=28 -LIBSYSTEMD_ID128_AGE=0 - -LIBSYSTEMD_JOURNAL_CURRENT=11 -LIBSYSTEMD_JOURNAL_REVISION=5 -LIBSYSTEMD_JOURNAL_AGE=11 - # Dirs of external packages dbuspolicydir=@dbuspolicydir@ dbussessionservicedir=@dbussessionservicedir@ @@ -5789,127 +5771,6 @@ EXTRA_DIST += \ test/loopy.service.d \ test/loopy.service.d/compat.conf -# ------------------------------------------------------------------------------ -if ENABLE_COMPAT_LIBS -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' <$< >$@ - -BUILT_SOURCES += \ - libsystemd-journal.c \ - libsystemd-login.c \ - libsystemd-id128.c \ - libsystemd-daemon.c - -nodist_libsystemd_journal_la_SOURCES = \ - libsystemd-journal.c - -libsystemd_journal_la_SOURCES = \ - src/compat-libs/libsystemd-journal.sym - -libsystemd_journal_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -imacros$(top_srcdir)/src/compat-libs/linkwarning.h - -libsystemd_journal_la_LDFLAGS = \ - $(AM_LDFLAGS) \ - -version-info $(LIBSYSTEMD_JOURNAL_CURRENT):$(LIBSYSTEMD_JOURNAL_REVISION):$(LIBSYSTEMD_JOURNAL_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-journal.sym - -libsystemd_journal_la_LIBADD = \ - libsystemd-journal-internal.la \ - libsystemd-internal.la - -nodist_libsystemd_login_la_SOURCES = \ - libsystemd-login.c - -libsystemd_login_la_SOURCES = \ - src/compat-libs/libsystemd-login.sym - -libsystemd_login_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -imacros$(top_srcdir)/src/compat-libs/linkwarning.h - -libsystemd_login_la_LDFLAGS = \ - $(AM_LDFLAGS) \ - -version-info $(LIBSYSTEMD_LOGIN_CURRENT):$(LIBSYSTEMD_LOGIN_REVISION):$(LIBSYSTEMD_LOGIN_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-login.sym - -libsystemd_login_la_LIBADD = \ - libsystemd-internal.la - -nodist_libsystemd_id128_la_SOURCES = \ - libsystemd-id128.c - -libsystemd_id128_la_SOURCES = \ - src/compat-libs/libsystemd-id128.sym - -libsystemd_id128_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -imacros$(top_srcdir)/src/compat-libs/linkwarning.h - -libsystemd_id128_la_LDFLAGS = \ - $(AM_LDFLAGS) \ - -version-info $(LIBSYSTEMD_ID128_CURRENT):$(LIBSYSTEMD_ID128_REVISION):$(LIBSYSTEMD_ID128_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-id128.sym - -libsystemd_id128_la_LIBADD = \ - libsystemd-internal.la - -nodist_libsystemd_daemon_la_SOURCES = \ - libsystemd-daemon.c - -libsystemd_daemon_la_SOURCES = \ - src/compat-libs/libsystemd-daemon.sym - -libsystemd_daemon_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -imacros$(top_srcdir)/src/compat-libs/linkwarning.h - -libsystemd_daemon_la_LDFLAGS = \ - $(AM_LDFLAGS) \ - -version-info $(LIBSYSTEMD_DAEMON_CURRENT):$(LIBSYSTEMD_DAEMON_REVISION):$(LIBSYSTEMD_DAEMON_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/compat-libs/libsystemd-daemon.sym - -libsystemd_daemon_la_LIBADD = \ - libsystemd-internal.la - -lib_LTLIBRARIES += \ - libsystemd-journal.la \ - libsystemd-login.la \ - libsystemd-id128.la \ - libsystemd-daemon.la - -pkgconfiglib_DATA += \ - src/compat-libs/libsystemd-journal.pc \ - src/compat-libs/libsystemd-login.pc \ - src/compat-libs/libsystemd-id128.pc \ - src/compat-libs/libsystemd-daemon.pc - -# move lib from $(libdir) to $(rootlibdir) and update devel link, if needed -compat-lib-install-hook: - libname=libsystemd-login.so && $(move-to-rootlibdir) - libname=libsystemd-journal.so && $(move-to-rootlibdir) - libname=libsystemd-id128.so && $(move-to-rootlibdir) - libname=libsystemd-daemon.so && $(move-to-rootlibdir) - -compat-lib-uninstall-hook: - rm -f $(DESTDIR)$(rootlibdir)/libsystemd-login.so* - rm -f $(DESTDIR)$(rootlibdir)/libsystemd-journal.so* - rm -f $(DESTDIR)$(rootlibdir)/libsystemd-id128.so* - rm -f $(DESTDIR)$(rootlibdir)/libsystemd-daemon.so* - -INSTALL_EXEC_HOOKS += compat-lib-install-hook -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 \ - src/compat-libs/libsystemd-daemon.pc.in - # ------------------------------------------------------------------------------ substitutions = \ '|rootlibexecdir=$(rootlibexecdir)|' \ diff --git a/autogen.sh b/autogen.sh index 607a9682dd..3a0695816e 100755 --- a/autogen.sh +++ b/autogen.sh @@ -55,16 +55,16 @@ fi cd $oldpwd if [ "x$1" = "xc" ]; then - $topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args + $topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-kdbus $args make clean elif [ "x$1" = "xg" ]; then - $topdir/configure CFLAGS='-g -Og -ftrapv' --enable-compat-libs --enable-kdbus $args + $topdir/configure CFLAGS='-g -Og -ftrapv' --enable-kdbus $args make clean elif [ "x$1" = "xa" ]; then - $topdir/configure CFLAGS='-g -O0 -Wsuggest-attribute=pure -Wsuggest-attribute=const -ftrapv' --enable-compat-libs --enable-kdbus $args + $topdir/configure CFLAGS='-g -O0 -Wsuggest-attribute=pure -Wsuggest-attribute=const -ftrapv' --enable-kdbus $args make clean elif [ "x$1" = "xl" ]; then - $topdir/configure CC=clang CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args + $topdir/configure CC=clang CFLAGS='-g -O0 -ftrapv' --enable-kdbus $args make clean elif [ "x$1" = "xs" ]; then scan-build $topdir/configure CFLAGS='-std=gnu99 -g -O0 -ftrapv' --enable-kdbus $args @@ -75,6 +75,6 @@ else echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo - echo "$topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-compat-libs --enable-kdbus $args" + echo "$topdir/configure CFLAGS='-g -O0 -ftrapv' --enable-kdbus $args" echo fi diff --git a/configure.ac b/configure.ac index 59cc9fd99e..262f9e4fff 100644 --- a/configure.ac +++ b/configure.ac @@ -362,17 +362,6 @@ AC_ARG_ENABLE([utmp], AS_HELP_STRING([--disable-utmp], [disable utmp/wtmp log ha AS_IF([test "x$have_utmp" = "xyes"], [AC_DEFINE(HAVE_UTMP, 1, [Define if utmp/wtmp support is enabled])]) AM_CONDITIONAL([HAVE_UTMP], [test "x$have_utmp" = "xyes"]) -# ------------------------------------------------------------------------------ -have_compat_libs=no -AC_ARG_ENABLE([compat_libs], AS_HELP_STRING([--enable-compat-libs],[Enable creation of compatibility libraries]), - [case "${enableval}" in - yes) have_compat_libs=yes ;; - no) have_compat_libs=no ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-compat-libs) ;; - esac], - [have_compat_libs=no]) -AM_CONDITIONAL([ENABLE_COMPAT_LIBS], [test "$have_compat_libs" = "yes"]) - # ------------------------------------------------------------------------------ have_coverage=no AC_ARG_ENABLE(coverage, AS_HELP_STRING([--enable-coverage], [enable test coverage])) @@ -1600,7 +1589,6 @@ AC_MSG_RESULT([ test coverage: ${have_coverage} Split /usr: ${enable_split_usr} SysV compatibility: ${SYSTEM_SYSV_COMPAT} - compatibility libraries: ${have_compat_libs} utmp/wtmp support: ${have_utmp} ldconfig support: ${enable_ldconfig} hibernate support: ${enable_hibernate} diff --git a/src/compat-libs/.gitignore b/src/compat-libs/.gitignore deleted file mode 100644 index 662c154cdd..0000000000 --- a/src/compat-libs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/libsystemd-*.pc diff --git a/src/compat-libs/libsystemd-daemon.pc.in b/src/compat-libs/libsystemd-daemon.pc.in deleted file mode 100644 index 847afc9d60..0000000000 --- a/src/compat-libs/libsystemd-daemon.pc.in +++ /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: - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd Daemon Utility Library - deprecated -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd -Cflags: -I${includedir} diff --git a/src/compat-libs/libsystemd-daemon.sym b/src/compat-libs/libsystemd-daemon.sym deleted file mode 100644 index f440238931..0000000000 --- a/src/compat-libs/libsystemd-daemon.sym +++ /dev/null @@ -1,27 +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: -***/ - -/* Original symbols from systemd v31 */ - -LIBSYSTEMD_DAEMON_31 { -global: - sd_booted; - sd_is_fifo; - sd_is_mq; - sd_is_socket; - sd_is_socket_inet; - sd_is_socket_unix; - sd_is_special; - sd_listen_fds; - sd_notify; - sd_notifyf; -local: - *; -}; diff --git a/src/compat-libs/libsystemd-id128.pc.in b/src/compat-libs/libsystemd-id128.pc.in deleted file mode 100644 index 80f8fee6c3..0000000000 --- a/src/compat-libs/libsystemd-id128.pc.in +++ /dev/null @@ -1,18 +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. - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd 128 Bit ID Utility Library - deprecated -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd -Cflags: -I${includedir} diff --git a/src/compat-libs/libsystemd-id128.sym b/src/compat-libs/libsystemd-id128.sym deleted file mode 100644 index 604c0026c6..0000000000 --- a/src/compat-libs/libsystemd-id128.sym +++ /dev/null @@ -1,21 +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. -***/ - -/* Original symbols from systemd v38 */ - -LIBSYSTEMD_ID128_38 { -global: - sd_id128_to_string; - sd_id128_from_string; - sd_id128_randomize; - sd_id128_get_machine; - sd_id128_get_boot; -local: - *; -}; diff --git a/src/compat-libs/libsystemd-journal.pc.in b/src/compat-libs/libsystemd-journal.pc.in deleted file mode 100644 index 395f71005b..0000000000 --- a/src/compat-libs/libsystemd-journal.pc.in +++ /dev/null @@ -1,19 +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. - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd Journal Utility Library - deprecated -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Requires: libsystemd = @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd -Cflags: -I${includedir} diff --git a/src/compat-libs/libsystemd-journal.sym b/src/compat-libs/libsystemd-journal.sym deleted file mode 100644 index 4eb15910d2..0000000000 --- a/src/compat-libs/libsystemd-journal.sym +++ /dev/null @@ -1,111 +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. -***/ - -/* Original symbols from systemd v38 */ - -LIBSYSTEMD_JOURNAL_38 { -global: - sd_journal_print; - sd_journal_printv; - sd_journal_send; - sd_journal_sendv; - sd_journal_stream_fd; - sd_journal_open; - sd_journal_close; - sd_journal_previous; - sd_journal_next; - sd_journal_previous_skip; - sd_journal_next_skip; - sd_journal_get_realtime_usec; - sd_journal_get_monotonic_usec; - sd_journal_get_data; - sd_journal_enumerate_data; - sd_journal_restart_data; - sd_journal_add_match; - sd_journal_flush_matches; - sd_journal_seek_head; - sd_journal_seek_tail; - sd_journal_seek_monotonic_usec; - sd_journal_seek_realtime_usec; - sd_journal_seek_cursor; - sd_journal_get_cursor; - sd_journal_get_fd; - sd_journal_process; -local: - *; -}; - -LIBSYSTEMD_JOURNAL_183 { -global: - sd_journal_print_with_location; - sd_journal_printv_with_location; - sd_journal_send_with_location; - sd_journal_sendv_with_location; -} LIBSYSTEMD_JOURNAL_38; - -LIBSYSTEMD_JOURNAL_184 { -global: - sd_journal_get_cutoff_realtime_usec; - sd_journal_get_cutoff_monotonic_usec; -} LIBSYSTEMD_JOURNAL_183; - -LIBSYSTEMD_JOURNAL_187 { -global: - sd_journal_wait; - sd_journal_open_directory; - sd_journal_add_disjunction; -} LIBSYSTEMD_JOURNAL_184; - -LIBSYSTEMD_JOURNAL_188 { -global: - sd_journal_perror; - sd_journal_perror_with_location; -} LIBSYSTEMD_JOURNAL_187; - -LIBSYSTEMD_JOURNAL_190 { -global: - sd_journal_get_usage; -} LIBSYSTEMD_JOURNAL_188; - -LIBSYSTEMD_JOURNAL_195 { -global: - sd_journal_test_cursor; - sd_journal_query_unique; - sd_journal_enumerate_unique; - sd_journal_restart_unique; -} LIBSYSTEMD_JOURNAL_190; - -LIBSYSTEMD_JOURNAL_196 { -global: - sd_journal_get_catalog; - sd_journal_get_catalog_for_message_id; - sd_journal_set_data_threshold; - sd_journal_get_data_threshold; -} LIBSYSTEMD_JOURNAL_195; - -LIBSYSTEMD_JOURNAL_198 { -global: - sd_journal_reliable_fd; -} LIBSYSTEMD_JOURNAL_196; - -LIBSYSTEMD_JOURNAL_201 { -global: - sd_journal_get_events; - sd_journal_get_timeout; -} LIBSYSTEMD_JOURNAL_198; - -LIBSYSTEMD_JOURNAL_202 { -global: - sd_journal_add_conjunction; -} LIBSYSTEMD_JOURNAL_201; - -LIBSYSTEMD_JOURNAL_205 { -global: - sd_journal_open_files; -} LIBSYSTEMD_JOURNAL_202; diff --git a/src/compat-libs/libsystemd-login.pc.in b/src/compat-libs/libsystemd-login.pc.in deleted file mode 100644 index db3f79c99a..0000000000 --- a/src/compat-libs/libsystemd-login.pc.in +++ /dev/null @@ -1,18 +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. - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd Login Utility Library - deprecated -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd -Cflags: -I${includedir} diff --git a/src/compat-libs/libsystemd-login.sym b/src/compat-libs/libsystemd-login.sym deleted file mode 100644 index 54aa91c609..0000000000 --- a/src/compat-libs/libsystemd-login.sym +++ /dev/null @@ -1,87 +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. -***/ - -/* Original symbols from systemd v31 */ - -LIBSYSTEMD_LOGIN_31 { -global: - sd_get_seats; - sd_get_sessions; - sd_get_uids; - sd_login_monitor_flush; - sd_login_monitor_get_fd; - sd_login_monitor_new; - sd_login_monitor_unref; - sd_pid_get_owner_uid; - sd_pid_get_session; - sd_seat_can_multi_session; - sd_seat_get_active; - sd_seat_get_sessions; - sd_session_get_seat; - sd_session_get_uid; - sd_session_is_active; - sd_uid_get_seats; - sd_uid_get_sessions; - sd_uid_get_state; - sd_uid_is_on_seat; -local: - *; -}; - -LIBSYSTEMD_LOGIN_38 { -global: - sd_pid_get_unit; - sd_session_get_service; -} LIBSYSTEMD_LOGIN_31; - -LIBSYSTEMD_LOGIN_43 { -global: - sd_session_get_type; - sd_session_get_class; - sd_session_get_display; -} LIBSYSTEMD_LOGIN_38; - -LIBSYSTEMD_LOGIN_186 { -global: - sd_session_get_state; - sd_seat_can_tty; - sd_seat_can_graphical; -} LIBSYSTEMD_LOGIN_43; - -LIBSYSTEMD_LOGIN_198 { -global: - sd_session_get_tty; -} LIBSYSTEMD_LOGIN_186; - -LIBSYSTEMD_LOGIN_201 { -global: - sd_login_monitor_get_events; - sd_login_monitor_get_timeout; -} LIBSYSTEMD_LOGIN_198; - -LIBSYSTEMD_LOGIN_202 { -global: - sd_pid_get_user_unit; - sd_pid_get_machine_name; -} LIBSYSTEMD_LOGIN_201; - -LIBSYSTEMD_LOGIN_203 { -global: - sd_get_machine_names; -} LIBSYSTEMD_LOGIN_202; - -LIBSYSTEMD_LOGIN_205 { -global: - sd_pid_get_slice; -} LIBSYSTEMD_LOGIN_203; - -LIBSYSTEMD_LOGIN_207 { -global: - sd_session_get_vt; -} LIBSYSTEMD_LOGIN_205; diff --git a/src/compat-libs/linkwarning.h b/src/compat-libs/linkwarning.h deleted file mode 100644 index 79ece9e7d1..0000000000 --- a/src/compat-libs/linkwarning.h +++ /dev/null @@ -1,35 +0,0 @@ -/*** - This file is part of systemd, but is heavily based on - glibc's libc-symbols.h. - - Copyright (C) 1995-1998,2000-2006,2008,2009 Free Software Foundation, Inc - - 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 . -***/ - -#pragma once - -#define __make_section_unallocated(section_string) \ - asm (".section " section_string "\n\t.previous"); - -#define __sec_comment "\n#APP\n\t#" - -#define link_warning(symbol, msg) \ - __make_section_unallocated (".gnu.warning." #symbol) \ - static const char __evoke_link_warning_##symbol[] \ - __attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \ - = msg - -#define obsolete_lib(name, lib) \ - link_warning(name, #name " was moved to libsystemd. Do not use " #lib ".") -- cgit v1.2.3-54-g00ecf From 2621af534689d8f608181ef4f61a3b498a310d8a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Feb 2016 23:10:23 +0100 Subject: util-lib: drop json parser This was used by the dkr logic, which is gone now, hence remove this too. Should we need it one day again the git history never forgets... Note that this only covers the JSON parser. The JSON generator used by "journalctl -o json" remains, as its much much simpler and requires no infrastructure except printf() and the most basic escaping. --- .gitignore | 1 - Makefile.am | 9 - src/basic/json.c | 871 --------------------------------------------------- src/basic/json.h | 90 ------ src/test/test-json.c | 202 ------------ 5 files changed, 1173 deletions(-) delete mode 100644 src/basic/json.c delete mode 100644 src/basic/json.h delete mode 100644 src/test/test-json.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 2b27d541c7..b2c60c71dc 100644 --- a/.gitignore +++ b/.gitignore @@ -216,7 +216,6 @@ /test-journal-stream /test-journal-syslog /test-journal-verify -/test-json /test-libsystemd-sym* /test-libudev /test-libudev-sym* diff --git a/Makefile.am b/Makefile.am index adaf2920e3..849c68aa14 100644 --- a/Makefile.am +++ b/Makefile.am @@ -895,8 +895,6 @@ libbasic_la_SOURCES = \ src/basic/audit-util.h \ src/basic/xml.c \ src/basic/xml.h \ - src/basic/json.c \ - src/basic/json.h \ src/basic/barrier.c \ src/basic/barrier.h \ src/basic/async.c \ @@ -1459,7 +1457,6 @@ tests += \ test-tables \ test-device-nodes \ test-xml \ - test-json \ test-architecture \ test-socket-util \ test-fdset \ @@ -1922,12 +1919,6 @@ test_xml_SOURCES = \ test_xml_LDADD = \ libshared.la -test_json_SOURCES = \ - src/test/test-json.c - -test_json_LDADD = \ - libshared.la - test_list_SOURCES = \ src/test/test-list.c diff --git a/src/basic/json.c b/src/basic/json.c deleted file mode 100644 index daa98fc815..0000000000 --- a/src/basic/json.c +++ /dev/null @@ -1,871 +0,0 @@ -/*** - 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 . -***/ - -#include -#include -#include -#include -#include - -#include "alloc-util.h" -#include "hexdecoct.h" -#include "json.h" -#include "macro.h" -#include "string-util.h" -#include "utf8.h" - -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; - - if (!line) - return; - - for (;;) { - const char *f; - - f = memchr(p, '\n', n); - if (!f) - return; - - n -= (f - p) + 1; - p = f + 1; - (*line)++; - } -} - -static int unhex_ucs2(const char *c, uint16_t *ret) { - int aa, bb, cc, dd; - uint16_t x; - - assert(c); - assert(ret); - - aa = unhexchar(c[0]); - if (aa < 0) - return -EINVAL; - - bb = unhexchar(c[1]); - if (bb < 0) - return -EINVAL; - - cc = unhexchar(c[2]); - if (cc < 0) - return -EINVAL; - - dd = unhexchar(c[3]); - if (dd < 0) - return -EINVAL; - - x = ((uint16_t) aa << 12) | - ((uint16_t) bb << 8) | - ((uint16_t) cc << 4) | - ((uint16_t) dd); - - if (x <= 0) - return -EINVAL; - - *ret = x; - - return 0; -} - -static int json_parse_string(const char **p, char **ret) { - _cleanup_free_ char *s = NULL; - size_t n = 0, allocated = 0; - const char *c; - - assert(p); - assert(*p); - assert(ret); - - c = *p; - - if (*c != '"') - return -EINVAL; - - c++; - - for (;;) { - int len; - - /* Check for EOF */ - if (*c == 0) - return -EINVAL; - - /* Check for control characters 0x00..0x1f */ - if (*c > 0 && *c < ' ') - return -EINVAL; - - /* Check for control character 0x7f */ - if (*c == 0x7f) - return -EINVAL; - - if (*c == '"') { - if (!s) { - s = strdup(""); - if (!s) - return -ENOMEM; - } else - s[n] = 0; - - *p = c + 1; - - *ret = s; - s = NULL; - return JSON_STRING; - } - - if (*c == '\\') { - char ch = 0; - c++; - - if (*c == 0) - return -EINVAL; - - if (IN_SET(*c, '"', '\\', '/')) - ch = *c; - else if (*c == 'b') - ch = '\b'; - else if (*c == 'f') - ch = '\f'; - else if (*c == 'n') - ch = '\n'; - else if (*c == 'r') - ch = '\r'; - else if (*c == 't') - ch = '\t'; - else if (*c == 'u') { - char16_t x; - int r; - - r = unhex_ucs2(c + 1, &x); - if (r < 0) - return r; - - c += 5; - - if (!GREEDY_REALLOC(s, allocated, n + 4)) - return -ENOMEM; - - if (!utf16_is_surrogate(x)) - n += utf8_encode_unichar(s + n, (char32_t) x); - else if (utf16_is_trailing_surrogate(x)) - return -EINVAL; - else { - char16_t y; - - if (c[0] != '\\' || c[1] != 'u') - return -EINVAL; - - r = unhex_ucs2(c + 2, &y); - if (r < 0) - return r; - - c += 6; - - if (!utf16_is_trailing_surrogate(y)) - return -EINVAL; - - n += utf8_encode_unichar(s + n, utf16_surrogate_pair_to_unichar(x, y)); - } - - continue; - } else - return -EINVAL; - - if (!GREEDY_REALLOC(s, allocated, n + 2)) - return -ENOMEM; - - s[n++] = ch; - c ++; - continue; - } - - len = utf8_encoded_valid_unichar(c); - if (len < 0) - return len; - - if (!GREEDY_REALLOC(s, allocated, n + len + 1)) - return -ENOMEM; - - memcpy(s + n, c, len); - n += len; - c += len; - } -} - -static int json_parse_number(const char **p, union json_value *ret) { - bool negative = false, exponent_negative = false, is_double = false; - double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0; - intmax_t i = 0; - const char *c; - - assert(p); - assert(*p); - assert(ret); - - c = *p; - - if (*c == '-') { - negative = true; - c++; - } - - if (*c == '0') - c++; - else { - if (!strchr("123456789", *c) || *c == 0) - return -EINVAL; - - do { - if (!is_double) { - int64_t t; - - t = 10 * i + (*c - '0'); - if (t < i) /* overflow */ - is_double = false; - else - i = t; - } - - x = 10.0 * x + (*c - '0'); - c++; - } while (strchr("0123456789", *c) && *c != 0); - } - - if (*c == '.') { - is_double = true; - c++; - - if (!strchr("0123456789", *c) || *c == 0) - return -EINVAL; - - do { - y = 10.0 * y + (*c - '0'); - shift = 10.0 * shift; - c++; - } while (strchr("0123456789", *c) && *c != 0); - } - - if (*c == 'e' || *c == 'E') { - is_double = true; - c++; - - if (*c == '-') { - exponent_negative = true; - c++; - } else if (*c == '+') - c++; - - if (!strchr("0123456789", *c) || *c == 0) - return -EINVAL; - - do { - exponent = 10.0 * exponent + (*c - '0'); - c++; - } while (strchr("0123456789", *c) && *c != 0); - } - - *p = c; - - if (is_double) { - ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10((exponent_negative ? -1.0 : 1.0) * exponent); - return JSON_REAL; - } else { - ret->integer = negative ? -i : i; - return JSON_INTEGER; - } -} - -int json_tokenize( - const char **p, - char **ret_string, - union json_value *ret_value, - void **state, - unsigned *line) { - - const char *c; - int t; - int r; - - enum { - STATE_NULL, - STATE_VALUE, - STATE_VALUE_POST, - }; - - assert(p); - assert(*p); - assert(ret_string); - assert(ret_value); - assert(state); - - t = PTR_TO_INT(*state); - c = *p; - - if (t == STATE_NULL) { - if (line) - *line = 1; - t = STATE_VALUE; - } - - for (;;) { - const char *b; - - b = c + strspn(c, WHITESPACE); - if (*b == 0) - return JSON_END; - - inc_lines(line, c, b - c); - c = b; - - switch (t) { - - case STATE_VALUE: - - if (*c == '{') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE); - return JSON_OBJECT_OPEN; - - } else if (*c == '}') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE_POST); - return JSON_OBJECT_CLOSE; - - } else if (*c == '[') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE); - return JSON_ARRAY_OPEN; - - } else if (*c == ']') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE_POST); - return JSON_ARRAY_CLOSE; - - } else if (*c == '"') { - r = json_parse_string(&c, ret_string); - if (r < 0) - return r; - - *ret_value = JSON_VALUE_NULL; - *p = c; - *state = INT_TO_PTR(STATE_VALUE_POST); - return r; - - } else if (strchr("-0123456789", *c)) { - r = json_parse_number(&c, ret_value); - if (r < 0) - return r; - - *ret_string = NULL; - *p = c; - *state = INT_TO_PTR(STATE_VALUE_POST); - return r; - - } else if (startswith(c, "true")) { - *ret_string = NULL; - ret_value->boolean = true; - *p = c + 4; - *state = INT_TO_PTR(STATE_VALUE_POST); - return JSON_BOOLEAN; - - } else if (startswith(c, "false")) { - *ret_string = NULL; - ret_value->boolean = false; - *p = c + 5; - *state = INT_TO_PTR(STATE_VALUE_POST); - return JSON_BOOLEAN; - - } else if (startswith(c, "null")) { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 4; - *state = INT_TO_PTR(STATE_VALUE_POST); - return JSON_NULL; - - } else - return -EINVAL; - - case STATE_VALUE_POST: - - if (*c == ':') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE); - return JSON_COLON; - } else if (*c == ',') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE); - return JSON_COMMA; - } else if (*c == '}') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE_POST); - return JSON_OBJECT_CLOSE; - } else if (*c == ']') { - *ret_string = NULL; - *ret_value = JSON_VALUE_NULL; - *p = c + 1; - *state = INT_TO_PTR(STATE_VALUE_POST); - return JSON_ARRAY_CLOSE; - } else - return -EINVAL; - } - - } -} - -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/basic/json.h b/src/basic/json.h deleted file mode 100644 index a4509f680f..0000000000 --- a/src/basic/json.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -/*** - 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 . -***/ - -#include -#include -#include - -#include "macro.h" -#include "util.h" - -enum { - JSON_END, - JSON_COLON, - JSON_COMMA, - JSON_OBJECT_OPEN, - JSON_OBJECT_CLOSE, - JSON_ARRAY_OPEN, - JSON_ARRAY_CLOSE, - JSON_STRING, - JSON_REAL, - JSON_INTEGER, - JSON_BOOLEAN, - 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/test/test-json.c b/src/test/test-json.c deleted file mode 100644 index 3fe2f58d04..0000000000 --- a/src/test/test-json.c +++ /dev/null @@ -1,202 +0,0 @@ -/*** - 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 . -***/ - -#include - -#include "alloc-util.h" -#include "json.h" -#include "string-util.h" -#include "util.h" - -static void test_one(const char *data, ...) { - void *state = NULL; - va_list ap; - - va_start(ap, data); - - for (;;) { - _cleanup_free_ char *str = NULL; - union json_value v = {}; - int t, tt; - - t = json_tokenize(&data, &str, &v, &state, NULL); - tt = va_arg(ap, int); - - assert_se(t == tt); - - if (t == JSON_END || t < 0) - break; - - else if (t == JSON_STRING) { - const char *nn; - - nn = va_arg(ap, const char *); - assert_se(streq_ptr(nn, str)); - - } else if (t == JSON_REAL) { - double d; - - d = va_arg(ap, double); - assert_se(fabs(d - v.real) < 0.001); - - } else if (t == JSON_INTEGER) { - intmax_t i; - - i = va_arg(ap, intmax_t); - assert_se(i == v.integer); - - } else if (t == JSON_BOOLEAN) { - bool b; - - b = va_arg(ap, int); - assert_se(b == v.boolean); - } - } - - 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); - test_one("", JSON_END); - test_one(" ", JSON_END); - test_one("0", JSON_INTEGER, (intmax_t) 0, JSON_END); - test_one("1234", JSON_INTEGER, (intmax_t) 1234, JSON_END); - test_one("3.141", JSON_REAL, 3.141, JSON_END); - test_one("0.0", JSON_REAL, 0.0, JSON_END); - test_one("7e3", JSON_REAL, 7e3, JSON_END); - test_one("-7e-3", JSON_REAL, -7e-3, JSON_END); - test_one("true", JSON_BOOLEAN, true, JSON_END); - test_one("false", JSON_BOOLEAN, false, JSON_END); - test_one("null", JSON_NULL, JSON_END); - test_one("{}", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END); - test_one("\t {\n} \n", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END); - test_one("[]", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END); - test_one("\t [] \n\n", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END); - test_one("\"\"", JSON_STRING, "", JSON_END); - test_one("\"foo\"", JSON_STRING, "foo", JSON_END); - test_one("\"foo\\nfoo\"", JSON_STRING, "foo\nfoo", JSON_END); - test_one("{\"foo\" : \"bar\"}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_STRING, "bar", JSON_OBJECT_CLOSE, JSON_END); - test_one("{\"foo\" : [true, false]}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_ARRAY_OPEN, JSON_BOOLEAN, true, JSON_COMMA, JSON_BOOLEAN, false, JSON_ARRAY_CLOSE, JSON_OBJECT_CLOSE, JSON_END); - test_one("\"\xef\xbf\xbd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END); - test_one("\"\\ufffd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END); - test_one("\"\\uf\"", -EINVAL); - test_one("\"\\ud800a\"", -EINVAL); - 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; -} -- cgit v1.2.3-54-g00ecf From 479050b36302a360048c2af5e79683d14ad56fb3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Feb 2016 23:29:57 +0100 Subject: core: drop Capabilities= setting The setting is hardly useful (since its effect is generally reduced to zero due to file system caps), and with the advent of ambient caps an actually useful replacement exists, hence let's get rid of this. I am pretty sure this was unused and our man page already recommended against its use, hence this should be a safe thing to remove. --- TODO | 2 -- man/sd_bus_creds_get_pid.xml | 14 +++----- man/systemd.exec.xml | 55 +++++++++---------------------- src/core/dbus-execute.c | 19 ++--------- src/core/execute.c | 62 ++--------------------------------- src/core/execute.h | 3 -- src/core/load-fragment-gperf.gperf.m4 | 2 +- src/core/load-fragment.c | 33 ------------------- src/core/load-fragment.h | 1 - 9 files changed, 27 insertions(+), 164 deletions(-) (limited to 'src') diff --git a/TODO b/TODO index 7437938bf0..837b825024 100644 --- a/TODO +++ b/TODO @@ -38,8 +38,6 @@ Features: * cache sd_event_now() result from before the first iteration... -* remove Capabilities=, after all AmbientCapabilities= and CapabilityBoundingSet= should be enough. - * support for the new copy_file_range() syscall * add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml index 3bcda46656..4c05835568 100644 --- a/man/sd_bus_creds_get_pid.xml +++ b/man/sd_bus_creds_get_pid.xml @@ -406,15 +406,11 @@ For processes that are not part of a session, returns -ENXIO. - sd_bus_creds_has_effective_cap() will - check whether the capability specified by - capability was set in the effective - capabilities mask. A positive return value means that is was - set, zero means that it was not set, and a negative return - value indicates an error. See - capabilities7 - and Capabilities= and - CapabilityBoundingSet= settings in + sd_bus_creds_has_effective_cap() will check whether the capability specified by + capability was set in the effective capabilities mask. A positive return value means that it + was set, zero means that it was not set, and a negative return value indicates an error. See capabilities7 and the + AmbientCapabilities= and CapabilityBoundingSet= settings in systemd.exec5. diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index f0f77c5091..008565c14b 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -778,32 +778,21 @@ CapabilityBoundingSet= - Controls which capabilities to include in the - capability bounding set for the executed process. See - capabilities7 - for details. Takes a whitespace-separated list of capability - names as read by - cap_from_name3, - e.g. CAP_SYS_ADMIN, - CAP_DAC_OVERRIDE, - CAP_SYS_PTRACE. 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 effect of the assignment inverted. Note that - this option also affects the respective capabilities in the - effective, permitted and inheritable capability sets, on top - of what Capabilities= does. If this option - is not used, the capability bounding set is not modified on - process execution, hence no limits on the capabilities of the - process are enforced. This option may appear more than once, in - which case the bounding sets are merged. If the empty string - is assigned to this option, the bounding set is reset to the - empty capability set, and all prior settings have no effect. - If set to ~ (without any further argument), - the bounding set is reset to the full set of available - capabilities, also undoing any previous - settings. + Controls which capabilities to include in the capability bounding set for the executed + process. See capabilities7 for + details. Takes a whitespace-separated list of capability names as read by cap_from_name3, + e.g. CAP_SYS_ADMIN, CAP_DAC_OVERRIDE, + CAP_SYS_PTRACE. 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 effect of the assignment inverted. Note that this option also affects the respective + capabilities in the effective, permitted and inheritable capability sets. If this option is not used, the + capability bounding set is not modified on process execution, hence no limits on the capabilities of the + process are enforced. This option may appear more than once, in which case the bounding sets are merged. If the + empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior + settings have no effect. If set to ~ (without any further argument), the bounding set is + reset to the full set of available capabilities, also undoing any previous settings. @@ -853,20 +842,6 @@ for details. - - Capabilities= - Controls the - capabilities7 - set for the executed process. Take a capability string - describing the effective, permitted and inherited capability - sets as documented in - cap_from_text3. - Note that these capability sets are usually influenced (and - filtered) by the capabilities attached to the executed file. - Due to that CapabilityBoundingSet= is - probably a much more useful setting. - - ReadWriteDirectories= ReadOnlyDirectories= diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index f2fc301f8e..973a60187d 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -312,7 +312,7 @@ static int property_get_ambient_capabilities( return sd_bus_message_append(reply, "t", c->capability_ambient_set); } -static int property_get_capabilities( +static int property_get_empty_string( sd_bus *bus, const char *path, const char *interface, @@ -321,23 +321,10 @@ static int property_get_capabilities( void *userdata, sd_bus_error *error) { - ExecContext *c = userdata; - _cleanup_cap_free_charp_ char *t = NULL; - const char *s; - assert(bus); assert(reply); - assert(c); - - if (c->capabilities) - s = t = cap_to_text(c->capabilities, NULL); - else - s = ""; - - if (!s) - return -ENOMEM; - return sd_bus_message_append(reply, "s", s); + return sd_bus_message_append(reply, "s", ""); } static int property_get_syscall_filter( @@ -700,7 +687,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/execute.c b/src/core/execute.c index 30f7e05b90..184c72dbe7 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -746,10 +746,10 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_ static int enforce_user(const ExecContext *context, uid_t uid) { assert(context); - /* Sets (but doesn't lookup) the uid and make sure we keep the + /* Sets (but doesn't look up) the uid and make sure we keep the * capabilities while doing so. */ - if (context->capabilities || context->capability_ambient_set != 0) { + if (context->capability_ambient_set != 0) { /* First step: If we need to keep capabilities but * drop privileges we need to make sure we keep our @@ -761,31 +761,9 @@ static int enforce_user(const ExecContext *context, uid_t uid) { if (prctl(PR_SET_SECUREBITS, sb) < 0) return -errno; } - - /* Second step: set the capabilities. This will reduce - * the capabilities to the minimum we need. */ - - if (context->capabilities) { - _cleanup_cap_free_ cap_t d = NULL; - static const cap_value_t bits[] = { - CAP_SETUID, /* Necessary so that we can run setresuid() below */ - CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */ - }; - - d = cap_dup(context->capabilities); - if (!d) - return -errno; - - if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 || - cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) - return -errno; - - if (cap_set_proc(d) < 0) - return -errno; - } } - /* Third step: actually set the uids */ + /* Second step: actually set the uids */ if (setresuid(uid, uid, uid) < 0) return -errno; @@ -1874,21 +1852,6 @@ static int exec_child( *exit_status = EXIT_CAPABILITIES; return r; } - - if (context->capabilities) { - - /* The capabilities in ambient set need to be also in the inherited - * set. If they aren't, trying to get them will fail. Add the ambient - * set inherited capabilities to the capability set in the context. - * This is needed because if capabilities are set (using "Capabilities=" - * keyword), they will override whatever we set now. */ - - r = capability_update_inherited_set(context->capabilities, context->capability_ambient_set); - if (r < 0) { - *exit_status = EXIT_CAPABILITIES; - return r; - } - } } if (context->user) { @@ -1927,12 +1890,6 @@ static int exec_child( return -errno; } - if (context->capabilities) - if (cap_set_proc(context->capabilities) < 0) { - *exit_status = EXIT_CAPABILITIES; - return -errno; - } - if (context->no_new_privileges) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { *exit_status = EXIT_NO_NEW_PRIVILEGES; @@ -2175,11 +2132,6 @@ void exec_context_done(ExecContext *c) { c->pam_name = mfree(c->pam_name); - if (c->capabilities) { - cap_free(c->capabilities); - c->capabilities = NULL; - } - c->read_only_dirs = strv_free(c->read_only_dirs); c->read_write_dirs = strv_free(c->read_write_dirs); c->inaccessible_dirs = strv_free(c->inaccessible_dirs); @@ -2538,14 +2490,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, strna(lvl_str)); } - if (c->capabilities) { - _cleanup_cap_free_charp_ char *t; - - t = cap_to_text(c->capabilities, NULL); - if (t) - fprintf(f, "%sCapabilities: %s\n", prefix, t); - } - if (c->secure_bits) fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n", prefix, diff --git a/src/core/execute.h b/src/core/execute.h index f7205701f4..41148bcea2 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -155,10 +155,7 @@ struct ExecContext { unsigned long mount_flags; uint64_t capability_bounding_set; - uint64_t capability_ambient_set; - - cap_t capabilities; int secure_bits; int syslog_priority; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index fde64c9747..5568b4696f 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -45,7 +45,7 @@ $1.SyslogIdentifier, config_parse_unit_string_printf, 0, $1.SyslogFacility, config_parse_log_facility, 0, offsetof($1, exec_context.syslog_priority) $1.SyslogLevel, config_parse_log_level, 0, offsetof($1, exec_context.syslog_priority) $1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) -$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) +$1.Capabilities, config_parse_warn_compat, DISABLED_LEGACY, offsetof($1, exec_context) $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) $1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set) $1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index ba551fb41d..b31bf83f47 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -951,38 +951,6 @@ int config_parse_exec_cpu_affinity(const char *unit, return 0; } -int config_parse_exec_capabilities(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) { - - ExecContext *c = data; - cap_t cap; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - cap = cap_from_text(rvalue); - if (!cap) { - log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue); - return 0; - } - - if (c->capabilities) - cap_free(c->capabilities); - c->capabilities = cap; - - return 0; -} - int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, @@ -3797,7 +3765,6 @@ void unit_dump_config_items(FILE *f) { { config_parse_input, "INPUT" }, { config_parse_log_facility, "FACILITY" }, { config_parse_log_level, "LEVEL" }, - { config_parse_exec_capabilities, "CAPABILITIES" }, { config_parse_exec_secure_bits, "SECUREBITS" }, { config_parse_capability_set, "BOUNDINGSET" }, { config_parse_limit, "LIMIT" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 372d05a61d..34f15afa62 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -52,7 +52,6 @@ int config_parse_exec_io_priority(const char *unit, const char *filename, unsign int config_parse_exec_cpu_sched_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_exec_cpu_sched_prio(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_cpu_affinity(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_capabilities(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_secure_bits(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_capability_set(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_limit(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); -- cgit v1.2.3-54-g00ecf From 6577bbe751b0ced40237be469c82a110bb0056dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 12 Feb 2016 23:44:22 +0100 Subject: build-sys: drop Makefile symlink in src/basic/linux The dir is not used otherwise, hence let's drop the Makefile, so that the dir stops to exist, too. --- src/basic/linux/Makefile | 1 - 1 file changed, 1 deletion(-) delete mode 120000 src/basic/linux/Makefile (limited to 'src') diff --git a/src/basic/linux/Makefile b/src/basic/linux/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/basic/linux/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 0655ef96fd88e3443009486256ce7bab43a27e56 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 12:03:16 +0100 Subject: build-sys: drop aufs-util.[ch] Left over cruft from the dkr excercise. --- Makefile.am | 2 -- src/import/aufs-util.c | 73 -------------------------------------------------- src/import/aufs-util.h | 22 --------------- 3 files changed, 97 deletions(-) delete mode 100644 src/import/aufs-util.c delete mode 100644 src/import/aufs-util.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 849c68aa14..6e4f1d0720 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5025,8 +5025,6 @@ systemd_pull_SOURCES = \ src/import/import-compress.h \ src/import/curl-util.c \ src/import/curl-util.h \ - src/import/aufs-util.c \ - src/import/aufs-util.h \ src/import/qcow2-util.c \ src/import/qcow2-util.h diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c deleted file mode 100644 index 44aa6e2170..0000000000 --- a/src/import/aufs-util.c +++ /dev/null @@ -1,73 +0,0 @@ -/*** - 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 . -***/ - -#include - -#include "aufs-util.h" -#include "rm-rf.h" -#include "string-util.h" -#include "util.h" - -static int nftw_cb( - const char *fpath, - const struct stat *sb, - int flag, - struct FTW *ftwbuf) { - - const char *fn, *original; - char *p; - int r; - - fn = fpath + ftwbuf->base; - - /* We remove all whiteout files, and all whiteouts */ - - original = startswith(fn, ".wh."); - if (!original) - return FTW_CONTINUE; - - log_debug("Removing whiteout indicator %s.", fpath); - r = rm_rf(fpath, REMOVE_ROOT|REMOVE_PHYSICAL); - if (r < 0) - return FTW_STOP; - - if (!startswith(fn, ".wh..wh.")) { - - p = alloca(ftwbuf->base + strlen(original)); - strcpy(mempcpy(p, fpath, ftwbuf->base), original); - - log_debug("Removing deleted file %s.", p); - r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL); - if (r < 0) - return FTW_STOP; - } - - return FTW_CONTINUE; -} - -int aufs_resolve(const char *path) { - int r; - - errno = 0; - r = nftw(path, nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); - if (r == FTW_STOP) - return errno > 0 ? -errno : -EIO; - - return 0; -} diff --git a/src/import/aufs-util.h b/src/import/aufs-util.h deleted file mode 100644 index e474a50897..0000000000 --- a/src/import/aufs-util.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -/*** - 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 . -***/ - -int aufs_resolve(const char *path); -- cgit v1.2.3-54-g00ecf From 1d9b8e58340e0fdc77158f04c36f5e6736754259 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 12:28:04 +0100 Subject: util: drop two unused calls from src/basic/ --- src/basic/fdset.c | 13 ------------- src/basic/fdset.h | 1 - src/basic/fs-util.c | 18 ------------------ src/basic/fs-util.h | 1 - 4 files changed, 33 deletions(-) (limited to 'src') diff --git a/src/basic/fdset.c b/src/basic/fdset.c index 3674d3ed9d..06f8ecbdbc 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -94,19 +94,6 @@ int fdset_put(FDSet *s, int fd) { return set_put(MAKE_SET(s), FD_TO_PTR(fd)); } -int fdset_consume(FDSet *s, int fd) { - int r; - - assert(s); - assert(fd >= 0); - - r = fdset_put(s, fd); - if (r <= 0) - safe_close(fd); - - return r; -} - int fdset_put_dup(FDSet *s, int fd) { int copy, r; diff --git a/src/basic/fdset.h b/src/basic/fdset.h index 12d0cef761..16efe5bdf2 100644 --- a/src/basic/fdset.h +++ b/src/basic/fdset.h @@ -32,7 +32,6 @@ FDSet* fdset_free(FDSet *s); int fdset_put(FDSet *s, int fd); int fdset_put_dup(FDSet *s, int fd); -int fdset_consume(FDSet *s, int fd); bool fdset_contains(FDSet *s, int fd); int fdset_remove(FDSet *s, int fd); diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 3ef1b90edd..51268828af 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -283,24 +283,6 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { return 0; } -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { - assert(fd >= 0); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != MODE_INVALID) - if (fchmod(fd, mode) < 0) - return -errno; - - if (uid != UID_INVALID || gid != GID_INVALID) - if (fchown(fd, uid, gid) < 0) - return -errno; - - return 0; -} - int fchmod_umask(int fd, mode_t m) { mode_t u; int r; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 0e2fcb21b9..0d23f8635f 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -43,7 +43,6 @@ int readlink_and_canonicalize(const char *p, char **r); int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); 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 fchmod_umask(int fd, mode_t mode); -- cgit v1.2.3-54-g00ecf From dd422d1e5b6a62bc634ae22d0627f70d4900814b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 12:28:28 +0100 Subject: tree-wide: make more global variables static let's export as little as we can --- src/basic/mempool.h | 2 +- src/cgtop/cgtop.c | 4 ++-- src/rc-local-generator/rc-local-generator.c | 2 +- src/sysv-generator/sysv-generator.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/mempool.h b/src/basic/mempool.h index fea7841bcf..0618b8dd22 100644 --- a/src/basic/mempool.h +++ b/src/basic/mempool.h @@ -36,7 +36,7 @@ void* mempool_alloc0_tile(struct mempool *mp); void mempool_free_tile(struct mempool *mp, void *p); #define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \ -struct mempool pool_name = { \ +static struct mempool pool_name = { \ .tile_size = sizeof(tile_type), \ .at_least = alloc_at_least, \ } diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 60d6da3246..9c0e82ebb3 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -72,13 +72,13 @@ static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; static char* arg_machine = NULL; +static bool arg_recursive = true; -enum { +static enum { COUNT_PIDS, COUNT_USERSPACE_PROCESSES, COUNT_ALL_PROCESSES, } arg_count = COUNT_PIDS; -static bool arg_recursive = true; static enum { ORDER_PATH, diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c index 9e9c161993..618bbe428d 100644 --- a/src/rc-local-generator/rc-local-generator.c +++ b/src/rc-local-generator/rc-local-generator.c @@ -36,7 +36,7 @@ #define RC_LOCAL_SCRIPT_PATH_STOP "/sbin/halt.local" #endif -const char *arg_dest = "/tmp"; +static const char *arg_dest = "/tmp"; static int add_symlink(const char *service, const char *where) { _cleanup_free_ char *from = NULL, *to = NULL; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 5a6818a79d..b5925a47dc 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -70,7 +70,7 @@ static const struct { UP must be read before DOWN */ }; -const char *arg_dest = "/tmp"; +static const char *arg_dest = "/tmp"; typedef struct SysvStub { char *name; -- cgit v1.2.3-54-g00ecf From afe773b01a704b98a350a36fa518bfcd6a54323b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 11 Feb 2016 23:24:14 -0500 Subject: basic/strv: fix strv_join for first empty argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Empty strings were ignored in strv_join, but only if they were at the beginning of the string. Empty strings after at least one non-empty item were treated normally. Previously: {"x"} → "x" {"x", ""} → "x" {"x", "", ""} → "x::" {""} → "" {"", ""} → "" {"", "", ""} → "" {"", "x"} → "x" {"", "x", ""} → "x:" Now: {"x"} → "x" {"x", ""} → "x" {"x", "", ""} → "x::" {""} → "" {"", ""} → ":" {"", "", ""} → "::" {"", "x"} → ":x" {"", "x", ""} → ":x:" --- src/basic/strv.c | 4 ++-- src/test/test-strv.c | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/strv.c b/src/basic/strv.c index b5d4d8191b..8282298dca 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -371,7 +371,7 @@ char *strv_join(char **l, const char *separator) { n = 0; STRV_FOREACH(s, l) { - if (n != 0) + if (s != l) n += k; n += strlen(*s); } @@ -382,7 +382,7 @@ char *strv_join(char **l, const char *separator) { e = r; STRV_FOREACH(s, l) { - if (e != r) + if (s != l) e = stpcpy(e, separator); e = stpcpy(e, *s); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 2b2f76cc7f..ef451c6abf 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -70,6 +70,18 @@ static const char* const input_table_none[] = { NULL, }; +static const char* const input_table_two_empties[] = { + "", + "", + NULL, +}; + +static const char* const input_table_one_empty[] = { + "", + NULL, +}; + + static const char* const input_table_quotes[] = { "\"", "'", @@ -130,7 +142,7 @@ static void test_strv_find_startswith(void) { } static void test_strv_join(void) { - _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL; + _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL; p = strv_join((char **)input_table_multiple, ", "); assert_se(p); @@ -151,6 +163,14 @@ static void test_strv_join(void) { t = strv_join((char **)input_table_none, ", "); assert_se(t); assert_se(streq(t, "")); + + v = strv_join((char **)input_table_two_empties, ", "); + assert_se(v); + assert_se(streq(v, ", ")); + + w = strv_join((char **)input_table_one_empty, ", "); + assert_se(w); + assert_se(streq(w, "")); } static void test_strv_quote_unquote(const char* const *split, const char *quoted) { @@ -653,6 +673,8 @@ int main(int argc, char *argv[]) { test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\""); test_strv_quote_unquote(input_table_one, "\"one\""); test_strv_quote_unquote(input_table_none, ""); + test_strv_quote_unquote(input_table_one_empty, "\"\""); + test_strv_quote_unquote(input_table_two_empties, "\"\" \"\""); test_strv_quote_unquote(input_table_quotes, QUOTES_STRING); test_strv_quote_unquote(input_table_spaces, SPACES_STRING); -- cgit v1.2.3-54-g00ecf From cf98937cc73201a71fabbd35fd9853cbe2790ed0 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 11 Feb 2016 23:33:09 -0500 Subject: activate: allow multiple, possibly invalid, fd names Previous code only allowed a single name to be passed, and duplicated it over all descriptors. For the sake of testing, allow different names and in arbitrary number. If just one is given, duplicate it to match the number of sockets. This matches previuos behaviour. Since this is a testing tool, it seems useful to allow passing invalid names to test application behaviour with invalid names. Hence, only warn. When warning, escape the name. --- man/systemd-activate.xml | 16 +++++---- src/activate/activate.c | 84 ++++++++++++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml index 995e6eecce..a8e17f2a2a 100644 --- a/man/systemd-activate.xml +++ b/man/systemd-activate.xml @@ -136,13 +136,15 @@ - NAME - - Specify a name for the activation file - descriptors. This is equivalent to setting - FileDescriptorName= in socket unit files, and - enables use of - sd_listen_fds_with_names3. + NAME:NAME... + + Specify names for the file descriptors passed. This is equivalent to setting + FileDescriptorName= in socket unit files, and enables use of + sd_listen_fds_with_names3. + Multiple entries may be specifies using separate options or by separating names with colons + (:) in one option. In case more names are given than descriptors, superflous ones willl be + ignored. In case less names are given than descriptors, the remaining file descriptors will be unnamed. + diff --git a/src/activate/activate.c b/src/activate/activate.c index 0db4967edb..23244fdc62 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -27,6 +27,7 @@ #include "sd-daemon.h" #include "alloc-util.h" +#include "escape.h" #include "fd-util.h" #include "log.h" #include "macro.h" @@ -40,7 +41,7 @@ static bool arg_accept = false; static int arg_socket_type = SOCK_STREAM; static char** arg_args = NULL; static char** arg_setenv = NULL; -static const char *arg_fdname = NULL; +static char **arg_fdnames = NULL; static bool arg_inetd = false; static int add_epoll(int epoll_fd, int fd) { @@ -134,7 +135,6 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, _cleanup_free_ char *joined = NULL; unsigned n_env = 0, length; const char *tocopy; - unsigned i; char **s; int r; @@ -224,25 +224,30 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0) return log_oom(); - if (arg_fdname) { + if (arg_fdnames) { + _cleanup_free_ char *names = NULL; + size_t len; char *e; + int i; + + len = strv_length(arg_fdnames); + if (len == 1) + for (i = 1; i < n_fds; i++) { + r = strv_extend(&arg_fdnames, arg_fdnames[0]); + if (r < 0) + return log_error_errno(r, "Failed to extend strv: %m"); + } + else if (len != (unsigned) n_fds) + log_warning("The number of fd names is different than number of fds: %zu vs %d", + len, n_fds); - e = strappend("LISTEN_FDNAMES=", arg_fdname); - if (!e) + names = strv_join(arg_fdnames, ":"); + if (!names) return log_oom(); - for (i = 1; i < (unsigned) n_fds; i++) { - char *c; - - c = strjoin(e, ":", arg_fdname, NULL); - if (!c) { - free(e); - return log_oom(); - } - - free(e); - e = c; - } + e = strappend("LISTEN_FDNAMES=", names); + if (!e) + return log_oom(); envp[n_env++] = e; } @@ -339,14 +344,15 @@ static void help(void) { printf("%s [OPTIONS...]\n\n" "Listen on sockets and launch child on connection.\n\n" "Options:\n" - " -h --help Show this help and exit\n" - " --version Print version string and exit\n" - " -l --listen=ADDR Listen for raw connections at ADDR\n" - " -d --datagram Listen on datagram instead of stream socket\n" - " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n" - " -a --accept Spawn separate child for each connection\n" - " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n" - " --inetd Enable inetd file descriptor passing protocol\n" + " -h --help Show this help and exit\n" + " --version Print version string and exit\n" + " -l --listen=ADDR Listen for raw connections at ADDR\n" + " -d --datagram Listen on datagram instead of stream socket\n" + " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n" + " -a --accept Spawn separate child for each connection\n" + " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n" + " --fdname=NAME[:NAME...] Specify names for file descriptors\n" + " --inetd Enable inetd file descriptor passing protocol\n" "\n" "Note: file descriptors from sd_listen_fds() will be passed through.\n" , program_invocation_short_name); @@ -424,14 +430,30 @@ static int parse_argv(int argc, char *argv[]) { break; - case ARG_FDNAME: - if (!fdname_is_valid(optarg)) { - log_error("File descriptor name %s is not valid, refusing.", optarg); - return -EINVAL; - } + case ARG_FDNAME: { + _cleanup_strv_free_ char **names; + char **s; + + names = strv_split(optarg, ":"); + if (!names) + return log_oom(); + + STRV_FOREACH(s, names) + if (!fdname_is_valid(*s)) { + _cleanup_free_ char *esc; - arg_fdname = optarg; + esc = cescape(*s); + log_warning("File descriptor name \"%s\" is not valid.", esc); + } + + /* Empty optargs means one empty name */ + r = strv_extend_strv(&arg_fdnames, + strv_isempty(names) ? STRV_MAKE("") : names, + false); + if (r < 0) + return log_error_errno(r, "strv_extend_strv: %m"); break; + } case ARG_INETD: arg_inetd = true; -- cgit v1.2.3-54-g00ecf From c2cf6e0b9d3de8039ec56f8abd774308126b97f8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 18:19:14 +0100 Subject: resolved: fix DNSSECSupported Link object property name By mistake the "DNSSECSupported" bus property of the Link object got named "DNSSECSupport". Internally, it's named correctly, and the counterpart on the "Manager" object got named correctly too. Technically this rename is an API break, but given that the interface is not documented or widely announced yet, and just 3 days in a published release, let's just fix this, and hope nobody notices. --- src/resolve/resolved-link-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index df7516f4f4..cfad37df6c 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -457,7 +457,7 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0), SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0), SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0), - SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0), + SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0), SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0), SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0), -- cgit v1.2.3-54-g00ecf From 36b693a6a901dd321a7c4f8f82ed44072d04497e Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sat, 13 Feb 2016 23:55:15 +0600 Subject: service: remove unnecessary check We call dual_timestamp_serialize() only if the s->watchdog_timestamp is set. But the dual_timestamp_serialize() already checks a given dual timestamp by the call of the dual_timestamp_is_set(). So we can remove this check safely. --- src/core/service.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/service.c b/src/core/service.c index ed24417859..1f6d821db3 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2134,8 +2134,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { } } - if (dual_timestamp_is_set(&s->watchdog_timestamp)) - dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp); + dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp); unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); -- cgit v1.2.3-54-g00ecf From 0a90fe9648d80c8b679d8529f5590d12a271531c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 20:01:52 +0100 Subject: resolved: drop references to two bus error codes no longer used --- src/libsystemd/sd-bus/bus-common-errors.c | 2 -- src/libsystemd/sd-bus/bus-common-errors.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 3c19f2b108..6370061daf 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -68,10 +68,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_NAME_SERVERS, ESRCH), 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, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_ABORTED, ECANCELED), - SD_BUS_ERROR_MAP(BUS_ERROR_CONNECTION_FAILURE, ECONNREFUSED), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SERVICE, EUNATCH), SD_BUS_ERROR_MAP(BUS_ERROR_DNSSEC_FAILED, EHOSTUNREACH), SD_BUS_ERROR_MAP(BUS_ERROR_NO_TRUST_ANCHOR, EHOSTUNREACH), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index fab8748f46..464834979a 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -67,10 +67,8 @@ #define BUS_ERROR_NO_NAME_SERVERS "org.freedesktop.resolve1.NoNameServers" #define BUS_ERROR_INVALID_REPLY "org.freedesktop.resolve1.InvalidReply" #define BUS_ERROR_NO_SUCH_RR "org.freedesktop.resolve1.NoSuchRR" -#define BUS_ERROR_NO_RESOURCES "org.freedesktop.resolve1.NoResources" #define BUS_ERROR_CNAME_LOOP "org.freedesktop.resolve1.CNameLoop" #define BUS_ERROR_ABORTED "org.freedesktop.resolve1.Aborted" -#define BUS_ERROR_CONNECTION_FAILURE "org.freedesktop.resolve1.ConnectionFailure" #define BUS_ERROR_NO_SUCH_SERVICE "org.freedesktop.resolve1.NoSuchService" #define BUS_ERROR_DNSSEC_FAILED "org.freedesktop.resolve1.DnssecFailed" #define BUS_ERROR_NO_TRUST_ANCHOR "org.freedesktop.resolve1.NoTrustAnchor" -- cgit v1.2.3-54-g00ecf From 12e1893af312b515cc6a1496c673c22f42b53b7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 20:02:30 +0100 Subject: resolved: fix definition of SD_RESOLVED_FLAGS_MAKE --- src/resolve/resolved-dns-packet.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 0bf34d270c..416335d0a2 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -262,11 +262,9 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family, return f|(family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4); case DNS_PROTOCOL_MDNS: - return family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4; + return f|(family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4); default: - break; + return f; } - - return 0; } -- cgit v1.2.3-54-g00ecf From ee116b54a3d0feb3f724f87ccf3f4cbb647d7e73 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 20:03:01 +0100 Subject: resolved: rename "SearchDomains" property in the Manager interface to "Domains" Another property name fuck-up. The property contains both search and routing domains and hence should be exposed as "Domains" rather than "SearchDomains". The counterpart in the Link object was correctly named, and the SetLinkDomains() and SetDomains() setter calls too, hence let's get this right, too. (Yepp, a minor API break actually, but given that this was so far not documented, and only 3 days public let's fix this now) --- src/resolve/resolved-bus.c | 10 +++++----- src/resolve/resolved-link-bus.c | 4 ++-- src/resolve/resolved-link-bus.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index fc5e6beca0..00076fdf1a 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1198,7 +1198,7 @@ static int bus_property_get_dns_servers( return sd_bus_message_close_container(reply); } -static int bus_property_get_search_domains( +static int bus_property_get_domains( sd_bus *bus, const char *path, const char *interface, @@ -1396,8 +1396,8 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda return call_link_method(userdata, message, bus_link_method_set_dns_servers, error); } -static int bus_method_set_link_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return call_link_method(userdata, message, bus_link_method_set_search_domains, error); +static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_domains, error); } static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -1449,7 +1449,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0), SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0), - SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0), + SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0), SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0), SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0), SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0), @@ -1462,7 +1462,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0), SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0), - SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_search_domains, 0), + SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0), SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0), SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0), SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0), diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index cfad37df6c..7f21891819 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -239,7 +239,7 @@ clear: return r; } -int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { +int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { Link *l = userdata; int r; @@ -460,7 +460,7 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0), SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0), - SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0), + SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0), SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0), SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0), SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0), diff --git a/src/resolve/resolved-link-bus.h b/src/resolve/resolved-link-bus.h index 31e6cd2b45..646031b631 100644 --- a/src/resolve/resolved-link-bus.h +++ b/src/resolve/resolved-link-bus.h @@ -30,7 +30,7 @@ char *link_bus_path(Link *link); int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); -int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error); -- cgit v1.2.3-54-g00ecf From c3be369faa5f73c3b97c0088876bafdbfef43dae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 20:26:30 +0100 Subject: resolved: extend ResolveHostname() bus call so that it can parse IP addresses If the hostname passed to ResolveHostname() is actually an IP address that is correctly formatted as string parse it as such, avoid any DNS traffic and return the data in parsed form. This is useful for clients which can simply call the bus function now without caring about the precise formatting of specified hostnames. This mimics getaddrinfo()'s behaviour with the AI_NUMERICHOST flag set. Note that this logic is only implemented for ResolveHostname(), but not for calls such as ResolveRecord(), for which only DNS domain names may be used as input. The "authenticated" flag is set for look-ups of this type, after all no untrusted network traffic is involved. --- src/resolve/resolved-bus.c | 72 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 00076fdf1a..6f08c43327 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -23,6 +23,7 @@ #include "dns-domain.h" #include "resolved-bus.h" #include "resolved-def.h" +#include "resolved-dns-synthesize.h" #include "resolved-link-bus.h" static int reply_query_state(DnsQuery *q) { @@ -233,6 +234,65 @@ static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus return 0; } +static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname, int family, uint64_t flags) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_free_ char *canonical = NULL; + union in_addr_union parsed; + int r, ff; + + /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it, + * let's not attempt to look it up. */ + + r = in_addr_from_string_auto(hostname, &ff, &parsed); + if (r < 0) /* not an address */ + return 0; + + if (family != AF_UNSPEC && ff != family) + return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family."); + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(iiay)"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'r', "iiay"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "ii", ifindex, ff); + if (r < 0) + return r; + + r = sd_bus_message_append_array(reply, 'y', &parsed, FAMILY_ADDRESS_SIZE(ff)); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS + * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner + * omissions are always done the same way). */ + r = in_addr_to_string(ff, &parsed, &canonical); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "st", canonical, + SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true)); + if (r < 0) + return r; + + return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL); +} + static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; Manager *m = userdata; @@ -254,15 +314,19 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - r = dns_name_is_valid(hostname); + r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error); if (r < 0) return r; - if (r == 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname); - r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error); + r = parse_as_address(message, ifindex, hostname, family, flags); + if (r != 0) + return r; + + r = dns_name_is_valid(hostname); if (r < 0) return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname); r = dns_question_new_address(&question_utf8, family, hostname, false); if (r < 0) -- cgit v1.2.3-54-g00ecf From 317f2fc9e71c39eb5b3c2269b25f7f977e61db34 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Feb 2016 20:32:11 +0100 Subject: busctl: when formatting message contents, make sure to print all whitespaces Previously we'd miss a necessary whitespace at the end of arrays, if more data was following. --- src/libsystemd/sd-bus/busctl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 35fabf038c..772ab62d5b 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -501,8 +501,10 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) { } basic; r = sd_bus_message_peek_type(m, &type, &contents); - if (r <= 0) + if (r < 0) return r; + if (r == 0) + return needs_space; if (bus_type_is_container(type) > 0) { @@ -533,18 +535,23 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) { fputc(' ', f); fprintf(f, "%u", n); + needs_space = true; + } else if (type == SD_BUS_TYPE_VARIANT) { if (needs_space) fputc(' ', f); fprintf(f, "%s", contents); + needs_space = true; } - r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT)); + r = format_cmdline(m, f, needs_space); if (r < 0) return r; + needs_space = r > 0; + r = sd_bus_message_exit_container(m); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From bacef2a229a9bee12adbea92dfb47db8757441c8 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 12 Feb 2016 08:41:44 +0100 Subject: missing.h: define IFLA_EXT_MASK We already define IFLA_PROMISCUITY and some other of these masks in order to allow building with older headers. Define IFLA_EXT_MASK too, which was added in the same kernel version as IFLA_PROMISCUITY (v3.10). --- src/basic/missing.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/basic/missing.h b/src/basic/missing.h index 36b060496a..4d3764c022 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -714,6 +714,7 @@ static inline int setns(int fd, int nstype) { #endif #if !HAVE_DECL_IFLA_PHYS_PORT_ID +#define IFLA_EXT_MASK 29 #undef IFLA_PROMISCUITY #define IFLA_PROMISCUITY 30 #define IFLA_NUM_TX_QUEUES 31 -- cgit v1.2.3-54-g00ecf From 8ecdcb5525c94ffa6ed206e6250b3e51803883eb Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 15 Feb 2016 16:11:51 +0100 Subject: dhcp: assert the success of sd_event_now() The function must never fail. --- src/libsystemd-network/sd-dhcp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index cad1a52c09..5fd59f7dd3 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -958,7 +958,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) { client->timeout_resend = sd_event_source_unref(client->timeout_resend); if (client->start_delay) { - sd_event_now(client->event, clock_boottime_or_monotonic(), &usec); + assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0); usec += client->start_delay; } -- cgit v1.2.3-54-g00ecf From ebf30a086dfa526ca048cf14ae16bb403f3dcd12 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 16 Feb 2016 00:01:44 +0600 Subject: time-util: introduce deserialize_timestamp_value() The time-util.c provides dual_timestamp_deserialize() function to convert value to usec_t and set it as value of ts->monotonic and ts->realtime. There are some places in code which do the same but only for one clockid_t (realtime or monotonic), when dual_timestamp_deserialize() sets value of both. This patch introduces the deserialize_timestamp_value() which converts a given value to usec_t and write it to a given timestamp. --- src/basic/time-util.c | 13 +++++++++++++ src/basic/time-util.h | 1 + 2 files changed, 14 insertions(+) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 510f018d9b..ac5988fdf9 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -459,6 +459,19 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) { return 0; } +int deserialize_timestamp_value(const char *value, usec_t *timestamp) { + int r; + + assert(value); + + r = safe_atou64(value, timestamp); + + if (r < 0) + return log_debug_errno(r, "Failed to parse finish timestamp value \"%s\": %m", value); + + return r; +} + int parse_timestamp(const char *t, usec_t *usec) { static const struct { const char *name; diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 9894e626c5..a826ad75ec 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -99,6 +99,7 @@ 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); int dual_timestamp_deserialize(const char *value, dual_timestamp *t); +int deserialize_timestamp_value(const char *value, usec_t *timestamp); int parse_timestamp(const char *t, usec_t *usec); -- cgit v1.2.3-54-g00ecf From 8e1afa0a5dcb95da633acd5004a56bbfc9bf9423 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 16 Feb 2016 00:04:09 +0600 Subject: machine: use deserialize_timestamp_value() which is introduced in the ebf30a086dfa commit. --- src/machine/machine.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/machine/machine.c b/src/machine/machine.c index 406d5a4b85..7e92ffc474 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -299,17 +299,8 @@ int machine_load(Machine *m) { m->class = c; } - if (realtime) { - unsigned long long l; - if (sscanf(realtime, "%llu", &l) > 0) - m->timestamp.realtime = l; - } - - if (monotonic) { - unsigned long long l; - if (sscanf(monotonic, "%llu", &l) > 0) - m->timestamp.monotonic = l; - } + deserialize_timestamp_value(realtime, &m->timestamp.realtime); + deserialize_timestamp_value(monotonic, &m->timestamp.monotonic); if (netif) { size_t allocated = 0, nr = 0; -- cgit v1.2.3-54-g00ecf From d4c6cc937c4943d3195e0d2169bb52c466507b8e Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 16 Feb 2016 00:04:49 +0600 Subject: logind: use deserialize_timestamp_value() which is introduced in the ebf30a086d commit. --- src/login/logind-session.c | 13 ++----------- src/login/logind-user.c | 13 ++----------- 2 files changed, 4 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 417b7f5d98..9874cdae5e 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -446,17 +446,8 @@ int session_load(Session *s) { safe_close(fd); } - if (realtime) { - unsigned long long l; - if (sscanf(realtime, "%llu", &l) > 0) - s->timestamp.realtime = l; - } - - if (monotonic) { - unsigned long long l; - if (sscanf(monotonic, "%llu", &l) > 0) - s->timestamp.monotonic = l; - } + deserialize_timestamp_value(realtime, &s->timestamp.realtime); + deserialize_timestamp_value(monotonic, &s->timestamp.monotonic); if (controller) { if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 6b9c69cc45..aa27f73a87 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -321,17 +321,8 @@ int user_load(User *u) { if (s && s->display && display_is_local(s->display)) u->display = s; - if (realtime) { - unsigned long long l; - if (sscanf(realtime, "%llu", &l) > 0) - u->timestamp.realtime = l; - } - - if (monotonic) { - unsigned long long l; - if (sscanf(monotonic, "%llu", &l) > 0) - u->timestamp.monotonic = l; - } + deserialize_timestamp_value(realtime, &u->timestamp.realtime); + deserialize_timestamp_value(monotonic, &u->timestamp.monotonic); return r; } -- cgit v1.2.3-54-g00ecf From 4524439edb7d6050ba8a7779cdb7305e6ceb621c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 15 Feb 2016 11:57:48 -0500 Subject: systemctl: include -M or -H arguments in the hint https://github.com/systemd/systemd/issues/2431 Some newlines are added, but the output will still exceed 80 columns in many cases. The fallback for oom conditions is changed from "n/a" to something "", and a similar pattern is used for the new code. This way we have a realistic fallback for oom, which seems nicer than making the whole function return an error code which would then have to be propagated. $ systemctl -M fedora-rawhide restart systemd-networkd.service Job for systemd-networkd.service failed because start of the service was attempted too often. See "systemctl -M fedora-rawhide status systemd-networkd.service" and "journalctl -M fedora-rawhide -xe" for details. To force a start use "systemctl -M fedora-rawhide reset-failed systemd-networkd.service" followed by "systemctl -M fedora-rawhide start systemd-networkd.service" again. --- src/shared/bus-util.c | 46 ++++++++++++++++++++++++++-------------------- src/shared/bus-util.h | 2 +- src/systemctl/systemctl.c | 18 ++++++++++++++++-- 3 files changed, 43 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 38557f0b8d..1fcf3f6a7f 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -2028,20 +2028,23 @@ static const struct { { "start-limit", "start of the service was attempted too often" } }; -static void log_job_error_with_service_result(const char* service, const char *result, const char *extra_args) { - _cleanup_free_ char *service_shell_quoted = NULL, *systemctl_extra_args = NULL; +static void log_job_error_with_service_result(const char* service, const char *result, const char** extra_args) { + _cleanup_free_ char *service_shell_quoted = NULL, *_systemctl, *_journalctl; + const char *systemctl = "systemctl", *journalctl = "journalct"; assert(service); service_shell_quoted = shell_maybe_quote(service); - systemctl_extra_args = strjoin("systemctl ", extra_args, " ", NULL); - if (!systemctl_extra_args) { - log_oom(); - return; - } + if (extra_args && extra_args[1]) { + assert(extra_args[0] == NULL); - systemctl_extra_args = strstrip(systemctl_extra_args); + extra_args[0] = "systemctl"; + systemctl = _systemctl = strv_join((char**) extra_args, " "); + + extra_args[0] = "journalctl"; + journalctl = _journalctl = strv_join((char**) extra_args, " "); + } if (!isempty(result)) { unsigned i; @@ -2051,30 +2054,33 @@ static void log_job_error_with_service_result(const char* service, const char *r break; if (i < ELEMENTSOF(explanations)) { - log_error("Job for %s failed because %s. See \"%s status %s\" and \"journalctl -xe\" for details.\n", + log_error("Job for %s failed because %s.\n" + "See \"%s status %s\" and \"%s -xe\" for details.\n", service, explanations[i].explanation, - systemctl_extra_args, - strna(service_shell_quoted)); - + systemctl ?: "systemctl ", + service_shell_quoted ?: "", + journalctl ?: "journalctl "); goto finish; } } - log_error("Job for %s failed. See \"%s status %s\" and \"journalctl -xe\" for details.\n", + log_error("Job for %s failed. See \"%s status %s\" and \"%s -xe\" for details.\n", service, - systemctl_extra_args, - strna(service_shell_quoted)); + systemctl ?: "systemctl ", + service_shell_quoted ?: "", + journalctl ?: "journalctl "); finish: /* For some results maybe additional explanation is required */ if (streq_ptr(result, "start-limit")) - log_info("To force a start use \"%1$s reset-failed %2$s\" followed by \"%1$s start %2$s\" again.", - systemctl_extra_args, - strna(service_shell_quoted)); + log_info("To force a start use \"%1$s reset-failed %2$s\"\n" + "followed by \"%1$s start %2$s\" again.", + systemctl ?: "systemctl ", + service_shell_quoted ?: ""); } -static int check_wait_response(BusWaitForJobs *d, bool quiet, const char *extra_args) { +static int check_wait_response(BusWaitForJobs *d, bool quiet, const char** extra_args) { int r = 0; assert(d->result); @@ -2125,7 +2131,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char *extra_ return r; } -int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char *extra_args) { +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char** extra_args) { int r = 0; assert(d); diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 204da55682..26d338beec 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -180,7 +180,7 @@ typedef struct BusWaitForJobs BusWaitForJobs; 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, const char *extra_args); +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char** extra_args); int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet); DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 908ccabf8a..44c13cf4d7 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2778,9 +2778,23 @@ static int start_unit(int argc, char *argv[], void *userdata) { } if (!arg_no_block) { - int q; + int q, arg_count = 1; + const char* extra_args[5] = {NULL}; + + /* leave first empty for the actual command name*/ + if (arg_scope != UNIT_FILE_SYSTEM) + extra_args[arg_count++] = "--user"; + + assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE)); + if (arg_transport == BUS_TRANSPORT_REMOTE) { + extra_args[arg_count++] = "-H"; + extra_args[arg_count++] = arg_host; + } else if (arg_transport == BUS_TRANSPORT_MACHINE) { + extra_args[arg_count++] = "-M"; + extra_args[arg_count++] = arg_host; + } - q = bus_wait_for_jobs(w, arg_quiet, arg_scope != UNIT_FILE_SYSTEM ? "--user" : NULL); + q = bus_wait_for_jobs(w, arg_quiet, extra_args); if (q < 0) return q; -- cgit v1.2.3-54-g00ecf From b895a7353b739e7186f6f51f3a415485b5afd80f Mon Sep 17 00:00:00 2001 From: Benjamin Robin Date: Mon, 15 Feb 2016 23:26:34 +0100 Subject: time-util: Rename and fix call of deserialize_timestamp_value() The deserialize_timestamp_value() is renamed timestamp_deserialize() to be more consistent with dual_timestamp_deserialize() And add the NULL check back on realtime and monotonic --- src/basic/time-util.c | 7 +++---- src/basic/time-util.h | 2 +- src/login/logind-session.c | 6 ++++-- src/login/logind-user.c | 6 ++++-- src/machine/machine.c | 6 ++++-- 5 files changed, 16 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index ac5988fdf9..0b4f5ab5b9 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -449,7 +449,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) { assert(t); if (sscanf(value, "%llu %llu", &a, &b) != 2) { - log_debug("Failed to parse finish timestamp value %s.", value); + log_debug("Failed to parse dual timestamp value \"%s\": %m", value); return -EINVAL; } @@ -459,15 +459,14 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) { return 0; } -int deserialize_timestamp_value(const char *value, usec_t *timestamp) { +int timestamp_deserialize(const char *value, usec_t *timestamp) { int r; assert(value); r = safe_atou64(value, timestamp); - if (r < 0) - return log_debug_errno(r, "Failed to parse finish timestamp value \"%s\": %m", value); + return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value); return r; } diff --git a/src/basic/time-util.h b/src/basic/time-util.h index a826ad75ec..77e3cd08d4 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -99,7 +99,7 @@ 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); int dual_timestamp_deserialize(const char *value, dual_timestamp *t); -int deserialize_timestamp_value(const char *value, usec_t *timestamp); +int timestamp_deserialize(const char *value, usec_t *timestamp); int parse_timestamp(const char *t, usec_t *usec); diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 9874cdae5e..e088225beb 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -446,8 +446,10 @@ int session_load(Session *s) { safe_close(fd); } - deserialize_timestamp_value(realtime, &s->timestamp.realtime); - deserialize_timestamp_value(monotonic, &s->timestamp.monotonic); + if (realtime) + timestamp_deserialize(realtime, &s->timestamp.realtime); + if (monotonic) + timestamp_deserialize(monotonic, &s->timestamp.monotonic); if (controller) { if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) diff --git a/src/login/logind-user.c b/src/login/logind-user.c index aa27f73a87..a826321bf0 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -321,8 +321,10 @@ int user_load(User *u) { if (s && s->display && display_is_local(s->display)) u->display = s; - deserialize_timestamp_value(realtime, &u->timestamp.realtime); - deserialize_timestamp_value(monotonic, &u->timestamp.monotonic); + if (realtime) + timestamp_deserialize(realtime, &u->timestamp.realtime); + if (monotonic) + timestamp_deserialize(monotonic, &u->timestamp.monotonic); return r; } diff --git a/src/machine/machine.c b/src/machine/machine.c index 7e92ffc474..7a7a1bb42b 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -299,8 +299,10 @@ int machine_load(Machine *m) { m->class = c; } - deserialize_timestamp_value(realtime, &m->timestamp.realtime); - deserialize_timestamp_value(monotonic, &m->timestamp.monotonic); + if (realtime) + timestamp_deserialize(realtime, &m->timestamp.realtime); + if (monotonic) + timestamp_deserialize(monotonic, &m->timestamp.monotonic); if (netif) { size_t allocated = 0, nr = 0; -- cgit v1.2.3-54-g00ecf From c11bda1e3ca774ec09adab868e716dd8a84d5614 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 15 Feb 2016 19:06:53 -0500 Subject: systemctl: fix style to avoid modification of array passed by caller Followup for 4524439edb7d. --- src/shared/bus-util.c | 31 +++++++++++++++---------------- src/shared/bus-util.h | 2 +- src/systemctl/systemctl.c | 5 ++--- 3 files changed, 18 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 1fcf3f6a7f..c87eaf63d8 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -2028,8 +2028,8 @@ static const struct { { "start-limit", "start of the service was attempted too often" } }; -static void log_job_error_with_service_result(const char* service, const char *result, const char** extra_args) { - _cleanup_free_ char *service_shell_quoted = NULL, *_systemctl, *_journalctl; +static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) { + _cleanup_free_ char *service_shell_quoted = NULL; const char *systemctl = "systemctl", *journalctl = "journalct"; assert(service); @@ -2037,13 +2037,11 @@ static void log_job_error_with_service_result(const char* service, const char *r service_shell_quoted = shell_maybe_quote(service); if (extra_args && extra_args[1]) { - assert(extra_args[0] == NULL); + _cleanup_free_ char *t; - extra_args[0] = "systemctl"; - systemctl = _systemctl = strv_join((char**) extra_args, " "); - - extra_args[0] = "journalctl"; - journalctl = _journalctl = strv_join((char**) extra_args, " "); + t = strv_join((char**) extra_args, " "); + systemctl = strjoina("systemctl ", t ?: "", NULL); + journalctl = strjoina("journalctl ", t ?: "", NULL); } if (!isempty(result)) { @@ -2058,29 +2056,30 @@ static void log_job_error_with_service_result(const char* service, const char *r "See \"%s status %s\" and \"%s -xe\" for details.\n", service, explanations[i].explanation, - systemctl ?: "systemctl ", + systemctl, service_shell_quoted ?: "", - journalctl ?: "journalctl "); + journalctl); goto finish; } } - log_error("Job for %s failed. See \"%s status %s\" and \"%s -xe\" for details.\n", + log_error("Job for %s failed.\n" + "See \"%s status %s\" and \"%s -xe\" for details.\n", service, - systemctl ?: "systemctl ", + systemctl, service_shell_quoted ?: "", - journalctl ?: "journalctl "); + journalctl); finish: /* For some results maybe additional explanation is required */ if (streq_ptr(result, "start-limit")) log_info("To force a start use \"%1$s reset-failed %2$s\"\n" "followed by \"%1$s start %2$s\" again.", - systemctl ?: "systemctl ", + systemctl, service_shell_quoted ?: ""); } -static int check_wait_response(BusWaitForJobs *d, bool quiet, const char** extra_args) { +static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) { int r = 0; assert(d->result); @@ -2131,7 +2130,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char** extra return r; } -int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char** extra_args) { +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) { int r = 0; assert(d); diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 26d338beec..fcda1b2c6c 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -180,7 +180,7 @@ typedef struct BusWaitForJobs BusWaitForJobs; 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, const char** extra_args); +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args); int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet); DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 44c13cf4d7..c75d12c136 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2778,10 +2778,9 @@ static int start_unit(int argc, char *argv[], void *userdata) { } if (!arg_no_block) { - int q, arg_count = 1; - const char* extra_args[5] = {NULL}; + int q, arg_count = 0; + const char* extra_args[4] = {}; - /* leave first empty for the actual command name*/ if (arg_scope != UNIT_FILE_SYSTEM) extra_args[arg_count++] = "--user"; -- cgit v1.2.3-54-g00ecf From 4edc2c9b6b5b921873eb82e58719ed4d9e0d69bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 22:50:01 +0100 Subject: networkd: FIONREAD is not reliable on some sockets Fixes: #2457 --- src/basic/socket-util.c | 34 ++++++++++++++++++++++++++++++++ src/basic/socket-util.h | 2 ++ src/libsystemd-network/sd-dhcp-client.c | 23 +++++++++------------ src/libsystemd-network/sd-dhcp-server.c | 9 ++++----- src/libsystemd-network/sd-dhcp6-client.c | 13 ++++++------ src/libsystemd-network/sd-ndisc.c | 13 +++++------- src/resolve/resolved-manager.c | 10 ++++------ 7 files changed, 64 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 49e5f5b125..58512686e3 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -936,3 +936,37 @@ int receive_one_fd(int transport_fd, int flags) { return *(int*) CMSG_DATA(found); } + +ssize_t next_datagram_size_fd(int fd) { + ssize_t l; + int k; + + /* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will + * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD dosn't + * do. This difference is actually of major importance as we need to be sure that the size returned here + * actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of + * the wrong size. */ + + l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC); + if (l < 0) { + if (errno == EOPNOTSUPP) + goto fallback; + + return -errno; + } + if (l == 0) + goto fallback; + + return l; + +fallback: + k = 0; + + /* Some sockets (AF_PACKET) do not support null-sized recv() with MSG_TRUNC set, let's fall back to FIONREAD + * for them. Checksums don't matter for raw sockets anyway, hence this should be fine. */ + + if (ioctl(fd, FIONREAD, &k) < 0) + return -errno; + + return (ssize_t) k; +} diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 92edc1dc22..d17a2f35f8 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -133,5 +133,7 @@ int send_one_fd_sa(int transport_fd, #define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags) int receive_one_fd(int transport_fd, int flags); +ssize_t next_datagram_size_fd(int fd); + #define CMSG_FOREACH(cmsg, mh) \ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 5fd59f7dd3..62099dd3f4 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1525,20 +1525,17 @@ static int client_receive_message_udp(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp_client *client = userdata; _cleanup_free_ DHCPMessage *message = NULL; - int buflen = 0, len, r; const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } }; const struct ether_addr *expected_chaddr = NULL; uint8_t expected_hlen = 0; + ssize_t len, buflen; assert(s); assert(client); - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return -errno; - else if (buflen < 0) - /* this can't be right */ - return -EIO; + buflen = next_datagram_size_fd(fd); + if (buflen < 0) + return buflen; message = malloc0(buflen); if (!message) @@ -1616,17 +1613,15 @@ static int client_receive_message_raw(sd_event_source *s, int fd, }; struct cmsghdr *cmsg; bool checksum = true; - int buflen = 0, len, r; + ssize_t buflen, len; + int r; assert(s); assert(client); - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return -errno; - else if (buflen < 0) - /* this can't be right */ - return -EIO; + buflen = next_datagram_size_fd(fd); + if (buflen < 0) + return buflen; packet = malloc0(buflen); if (!packet) diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index ad3a37b722..54ff1a3f28 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -955,14 +955,13 @@ static int server_receive_message(sd_event_source *s, int fd, .msg_controllen = sizeof(cmsgbuf), }; struct cmsghdr *cmsg; - int buflen = 0, len; + ssize_t buflen, len; assert(server); - if (ioctl(fd, FIONREAD, &buflen) < 0) - return -errno; - else if (buflen < 0) - return -EIO; + buflen = next_datagram_size_fd(fd); + if (buflen < 0) + return buflen; message = malloc(buflen); if (!message) diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 5b6b9cbcac..7d56d4cc60 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -33,6 +33,7 @@ #include "in-addr-util.h" #include "network-internal.h" #include "random-util.h" +#include "socket-util.h" #include "string-table.h" #include "util.h" @@ -891,18 +892,16 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); _cleanup_free_ DHCP6Message *message = NULL; - int r, buflen, len; + ssize_t buflen, len; + int r = 0; assert(s); assert(client); assert(client->event); - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return -errno; - else if (buflen < 0) - /* This really should not happen */ - return -EIO; + buflen = next_datagram_size_fd(fd); + if (buflen < 0) + return buflen; message = malloc(buflen); if (!message) diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 519d2aa36b..bae6a49fe6 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -491,19 +491,16 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r struct cmsghdr *cmsg; struct in6_addr *gw; unsigned lifetime; - ssize_t len; - int r, pref, stateful, buflen = 0; + ssize_t len, buflen; + int r, pref, stateful; assert(s); assert(nd); assert(nd->event); - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return -errno; - else if (buflen < 0) - /* This really should not happen */ - return -EIO; + buflen = next_datagram_size_fd(fd); + if (buflen < 0) + return buflen; iov.iov_len = buflen; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index bf5efe4cfa..7f9073448a 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -617,18 +617,16 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { struct msghdr mh = {}; struct cmsghdr *cmsg; struct iovec iov; - int ms = 0, r; - ssize_t l; + ssize_t ms, l; + int r; assert(m); assert(fd >= 0); assert(ret); - r = ioctl(fd, FIONREAD, &ms); - if (r < 0) - return -errno; + ms = next_datagram_size_fd(fd); if (ms < 0) - return -EIO; + return ms; r = dns_packet_new(&p, protocol, ms); if (r < 0) -- cgit v1.2.3-54-g00ecf From b9f65a60c28d191bb9bbd5668593e56885250644 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 16 Feb 2016 18:42:45 +0600 Subject: main: no need to set errno manually If we are not PID 1 and started as init, we executing systemctl with execv(). Here no need to set errno manually, because in a failure case, because the execv() anyway will set errno depends on a error. --- src/core/main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index e2088574c0..c725a686f1 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1313,7 +1313,6 @@ int main(int argc, char *argv[]) { /* This is compatibility support for SysV, where * calling init as a user is identical to telinit. */ - errno = -ENOENT; execv(SYSTEMCTL_BINARY_PATH, argv); log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m"); return 1; -- cgit v1.2.3-54-g00ecf From 61ecb465b1c803316cb55bae0c2d7cf3c0008589 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 18:40:02 +0100 Subject: resolved: turn on DNSSEC by default, unless configured otherwise Let's make sure DNSSEC gets more testing, by defaulting DNSSEC to "allow-downgrade" mode. Since distros should probably not ship DNSSEC enabled by default add a configure switch to disable this again. DNSSEC in "allow-downgrade" mode should mostly work without affecting user experience. There's one exception: some captive portal systems rewrite DNS in order to redirect HTTP traffic to the captive portal. If these systems implement DNS servers that are otherwise DNSSEC-capable (which in fact is pretty unlikely, but still...), then this will result in the captive portal being inaccessible. To fix this support in NetworkManager (or any other network management solution that does captive portal detection) is required, which simply turns off DNSSEC during the captive portal detection, and resets it back to the default (i.e. on) after captive portal authentication is complete. --- Makefile.am | 1 + NEWS | 17 +++++++++++++++++ configure.ac | 19 +++++++++++++++++-- src/resolve/resolved-manager.c | 2 +- src/resolve/resolved.conf.in | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 9bc0bf2c05..8c151f538f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5759,6 +5759,7 @@ substitutions = \ '|PYTHON=$(PYTHON)|' \ '|NTP_SERVERS=$(NTP_SERVERS)|' \ '|DNS_SERVERS=$(DNS_SERVERS)|' \ + '|DEFAULT_DNSSEC_MODE=$(DEFAULT_DNSSEC_MODE)|' \ '|systemuidmax=$(SYSTEM_UID_MAX)|' \ '|systemgidmax=$(SYSTEM_GID_MAX)|' \ '|TTY_GID=$(TTY_GID)|' \ diff --git a/NEWS b/NEWS index 80e59c53d3..0cce79443b 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,23 @@ systemd System and Service Manager CHANGES WITH 230 in spe: + * DNSSEC is now turned on by default in systemd-resolved (in + "allow-downgrade" mode), but may be turned off during compile time by + passing "--with-default-dnssec=no" to "configure" (and of course, + during runtime with DNSSEC= in resolved.conf). We recommend + downstreams to leave this on at least during development cycles and + report any issues with the DNSSEC logic upstream. We are very + interested in collecting feedback about the DNSSEC validator and its + limitations in the wild. Note however, that DNSSEC support is + probably nothing downstreams should turn on in stable distros just + yet, as it might create incompabilities with a few DNS servers and + networks. We tried hard to make sure we downgrade to non-DNSSEC mode + automatically whenever we detect such incompatible setups, but there + might be systems we do not cover yet. Hence: please help us testing + the DNSSEC code, leave this on where you can, report back, but then + again don't consider turning this on in your stable, LTS or + production release just yet. + * Testing tool /usr/lib/systemd/systemd-activate is renamed to systemd-socket-activate and installed into /usr/bin. It is now fully supported. diff --git a/configure.ac b/configure.ac index 262f9e4fff..e72470a199 100644 --- a/configure.ac +++ b/configure.ac @@ -1128,6 +1128,20 @@ AC_ARG_WITH(dns-servers, AC_DEFINE_UNQUOTED(DNS_SERVERS, ["$DNS_SERVERS"], [Default DNS Servers]) AC_SUBST(DNS_SERVERS) +AC_ARG_WITH(default-dnssec, + AS_HELP_STRING([--with-default-dnssec=MODE], + [Default DNSSEC mode, defaults to "allow-downgrade"]), + [DEFAULT_DNSSEC_MODE="$withval"], + [DEFAULT_DNSSEC_MODE="allow-downgrade"]) + +AS_CASE("x${DEFAULT_DNSSEC_MODE}", + [xno], [mode=DNSSEC_NO], + [xyes], [mode=DNSSEC_YES], + [xallow-downgrade], [mode=DNSSEC_ALLOW_DOWNGRADE], + AC_MSG_ERROR(Bad DNSSEC mode ${DEFAULT_DNSSEC_MODE})) +AC_DEFINE_UNQUOTED(DEFAULT_DNSSEC_MODE, [$mode], [Default DNSSEC mode]) +AC_SUBST(DEFAULT_DNSSEC_MODE) + # ------------------------------------------------------------------------------ have_networkd=no AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd])) @@ -1559,12 +1573,13 @@ AC_MSG_RESULT([ hostnamed: ${have_hostnamed} timedated: ${have_timedated} timesyncd: ${have_timesyncd} - default NTP servers: ${NTP_SERVERS} + Default NTP servers: ${NTP_SERVERS} time epoch: ${TIME_EPOCH} localed: ${have_localed} networkd: ${have_networkd} resolved: ${have_resolved} - default DNS servers: ${DNS_SERVERS} + Default DNS servers: ${DNS_SERVERS} + Default DNSSEC mode: ${DEFAULT_DNSSEC_MODE} coredump: ${have_coredump} polkit: ${have_polkit} efi: ${have_efi} diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index bf5efe4cfa..09e15fa230 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -485,7 +485,7 @@ int manager_new(Manager **ret) { m->llmnr_support = RESOLVE_SUPPORT_YES; m->mdns_support = RESOLVE_SUPPORT_NO; - m->dnssec_mode = DNSSEC_NO; + m->dnssec_mode = DEFAULT_DNSSEC_MODE; m->read_resolv_conf = true; m->need_builtin_fallbacks = true; m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY; diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index efc9c6733a..a288588924 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -16,4 +16,4 @@ #FallbackDNS=@DNS_SERVERS@ #Domains= #LLMNR=yes -#DNSSEC=no +#DNSSEC=@DEFAULT_DNSSEC_MODE@ -- cgit v1.2.3-54-g00ecf From de085700502b372767fa4c83b91a02522e198897 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 19:06:01 +0100 Subject: build-sys: fix type detection Before this patch existence of char16_t, char32_t, key_serial_t was checked with AC_CHECK_DECLS() which doesn't actually work for types. Correct this to use AC_CHECK_TYPES() instead. Also, while we are at it, change the check for memfd_create() to use AC_CHECK_DECLS() instead of AC_CHECK_FUNCS(). This is a better choice, since a couple of syscalls are defined by glibc but not exported in the header files (pivot_root() for example), and we hence should probably be more picky with memfd_create() too, which glibc might decide to expose one day, but not necessarily in the headers too. --- configure.ac | 9 ++++++--- src/basic/missing.h | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/configure.ac b/configure.ac index e72470a199..614f0553b8 100644 --- a/configure.ac +++ b/configure.ac @@ -295,10 +295,8 @@ CAP_LIBS="$LIBS" LIBS="$save_LIBS" AC_SUBST(CAP_LIBS) -AC_CHECK_FUNCS([memfd_create]) AC_CHECK_FUNCS([__secure_getenv secure_getenv]) -AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, - kcmp, keyctl, key_serial_t, char16_t, char32_t, LO_FLAGS_PARTSCAN], +AC_CHECK_DECLS([memfd_create, gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, keyctl, LO_FLAGS_PARTSCAN], [], [], [[ #include #include @@ -309,6 +307,11 @@ AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renamea #include ]]) +AC_CHECK_TYPES([char16_t, char32_t, key_serial_t], + [], [], [[ +#include +]]) + AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, IFLA_MACVLAN_FLAGS, IFLA_IPVLAN_MODE, diff --git a/src/basic/missing.h b/src/basic/missing.h index 4d3764c022..f3d32362bd 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -167,7 +167,7 @@ static inline int pivot_root(const char *new_root, const char *put_old) { # endif #endif -#ifndef HAVE_MEMFD_CREATE +#if !HAVE_DECL_MEMFD_CREATE static inline int memfd_create(const char *name, unsigned int flags) { return syscall(__NR_memfd_create, name, flags); } @@ -1089,7 +1089,7 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns #define INPUT_PROP_ACCELEROMETER 0x06 #endif -#if !HAVE_DECL_KEY_SERIAL_T +#ifndef HAVE_KEY_SERIAL_T typedef int32_t key_serial_t; #endif @@ -1160,11 +1160,11 @@ static inline key_serial_t request_key(const char *type, const char *description #ifndef IF_OPER_UP #define IF_OPER_UP 6 -#ifndef HAVE_DECL_CHAR32_T +#ifndef HAVE_CHAR32_T #define char32_t uint32_t #endif -#ifndef HAVE_DECL_CHAR16_T +#ifndef HAVE_CHAR16_T #define char16_t uint16_t #endif -- cgit v1.2.3-54-g00ecf From 9dc907f9c93636cb63ca90300fa3b8c03812701f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 19:11:18 +0100 Subject: networkd: rework idle detection logic of networkd This patch makes networkd stay around as long as there is more than just a loopback interface around, or the loopback device isn't fully probed yet, or the loopback device has a .network file attached. In essence, this means networkd stays around now continously as it should, unless it is running in some (container?) environment that really has no interface except a loopback device. Fixes #2577. --- src/network/networkd-manager.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b527191a5a..b8cb7f875d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1091,22 +1091,19 @@ static bool manager_check_idle(void *userdata) { assert(m); + /* Check whether we are idle now. The only case when we decide to be idle is when there's only a loopback + * device around, for which we have no configuration, and which already left the PENDING state. In all other + * cases we are not idle. */ + HASHMAP_FOREACH(link, m->links, i) { - /* we are not woken on udev activity, so let's just wait for the - * pending udev event */ + /* We are not woken on udev activity, so let's just wait for the pending udev event */ if (link->state == LINK_STATE_PENDING) return false; - if (!link->network) - continue; + if ((link->flags & IFF_LOOPBACK) == 0) + return false; - /* we are not woken on netork activity, so let's stay around */ - if (link_lldp_enabled(link) || - link_ipv4ll_enabled(link) || - link_dhcp4_server_enabled(link) || - link_dhcp4_enabled(link) || - link_dhcp6_enabled(link) || - link_ipv6_accept_ra_enabled(link)) + if (link->network) return false; } -- cgit v1.2.3-54-g00ecf From 41815a4aa66c59070dc86aa99eebfa720e8a263e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 15 Feb 2016 21:25:33 +0100 Subject: resolve: print a noisy warning if we show crypto keys that could not be authenticated Doing DNS retrieval on non-authenticated crypt keys is useless, hence warn loudly about it. --- src/resolve/dns-type.c | 17 +++++++++++++++++ src/resolve/dns-type.h | 1 + src/resolve/resolve-tool.c | 17 +++++++++++++++++ 3 files changed, 35 insertions(+) (limited to 'src') diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c index b2f479cae5..78d9d5733f 100644 --- a/src/resolve/dns-type.c +++ b/src/resolve/dns-type.c @@ -193,6 +193,23 @@ bool dns_type_is_obsolete(uint16_t type) { DNS_TYPE_NULL); } +bool dns_type_needs_authentication(uint16_t type) { + + /* Returns true for all (non-obsolete) RR types where records are not useful if they aren't + * authenticated. I.e. everything that contains crypto keys. */ + + return IN_SET(type, + DNS_TYPE_CERT, + DNS_TYPE_SSHFP, + DNS_TYPE_IPSECKEY, + DNS_TYPE_DS, + DNS_TYPE_DNSKEY, + DNS_TYPE_TLSA, + DNS_TYPE_CDNSKEY, + DNS_TYPE_OPENPGPKEY, + DNS_TYPE_CAA); +} + int dns_type_to_af(uint16_t t) { switch (t) { diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index f18ac6eef3..fb7babf12a 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -132,6 +132,7 @@ bool dns_type_is_dnssec(uint16_t type); bool dns_type_is_obsolete(uint16_t type); bool dns_type_may_wildcard(uint16_t type); bool dns_type_apex_only(uint16_t type); +bool dns_type_needs_authentication(uint16_t type); int dns_type_to_af(uint16_t t); bool dns_class_is_pseudo(uint16_t class); diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 9aade8e490..c1be03fbb2 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -339,6 +339,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ uint64_t flags; int r; usec_t ts; + bool needs_authentication = false; assert(name); @@ -421,6 +422,10 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); + + if (dns_type_needs_authentication(t)) + needs_authentication = true; + n++; } if (r < 0) @@ -441,6 +446,18 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ print_source(flags, ts); + if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) { + fflush(stdout); + + fprintf(stderr, "\n%s" + "WARNING: The resources shown contain cryptographic key data which could not be\n" + " authenticated. It is not suitable to authenticate any communication.\n" + " This is usually indication that DNSSEC authentication was not enabled\n" + " or is not available for the selected protocol or DNS servers.%s\n", + ansi_highlight_red(), + ansi_normal()); + } + return 0; } -- cgit v1.2.3-54-g00ecf From 3f51aec8647fe13f4b1e46b2f75ff635403adf91 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 13:18:36 +0100 Subject: core: fix assertion check Fixes: #2632 --- src/core/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/timer.c b/src/core/timer.c index 6f3e6a8db3..3d0bae16e5 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -334,7 +334,7 @@ static void add_random(Timer *t, usec_t *v) { usec_t add; assert(t); - assert(*v); + assert(v); if (t->random_usec == 0) return; -- cgit v1.2.3-54-g00ecf From 6d2353394fc33e923d1ab464c8f88df2a5105ffb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 14:03:47 +0100 Subject: udev: fix cg_unified() return code checking Fixes fall-out from 8b3aa503c171acdb9ec63484a8c50e2680d31e79. Fixes: #2635 --- src/udev/udevd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 2c1c4a967b..bb92f16352 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1715,7 +1715,7 @@ int main(int argc, char *argv[]) { 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) { - if (r == -ENOENT || r == -ENOEXEC) + if (r == -ENOENT || r == -ENOMEDIUM) log_debug_errno(r, "did not find dedicated cgroup: %m"); else log_warning_errno(r, "failed to get cgroup: %m"); -- cgit v1.2.3-54-g00ecf From c77d26122a35a8555953bbe71e4a4ff664f3462c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 14:17:53 +0100 Subject: resolved: make sure to normalize all domain names returned via the bus Most domain names we deal with are normalized anyway (since we read them that way from DNS packets), but some might not (because they are synthesized from unnormalized configuration or so), hence make sure to normalize all names before passing them out to clients, to be fully deterministic. Note that internally we are process normalized and non-normalized names the same way, and while comparing them ignore the differences due to unnormalized names. However, that internal implementation detail really shouldn't spill out the clients, hence make sure to clean it all up. --- src/resolve/resolved-bus.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 6f08c43327..2d94baeb7e 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -140,6 +140,7 @@ static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifin static void bus_method_resolve_hostname_complete(DnsQuery *q) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_free_ char *normalized = NULL; DnsResourceRecord *rr; unsigned added = 0; int ifindex, r; @@ -199,11 +200,17 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { if (r < 0) goto finish; + /* The key names are not necessarily normalized, make sure that they are when we return them to our bus + * clients. */ + r = dns_name_normalize(DNS_RESOURCE_KEY_NAME(canonical->key), &normalized); + if (r < 0) + goto finish; + /* Return the precise spelling and uppercasing and CNAME target reported by the server */ assert(canonical); r = sd_bus_message_append( reply, "st", - DNS_RESOURCE_KEY_NAME(canonical->key), + normalized, SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); if (r < 0) goto finish; @@ -395,13 +402,19 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { question = dns_query_question_for_protocol(q, q->answer_protocol); DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + _cleanup_free_ char *normalized = NULL; + r = dns_question_matches_rr(question, rr, NULL); if (r < 0) goto finish; if (r == 0) continue; - r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name); + r = dns_name_normalize(rr->ptr.name, &normalized); + if (r < 0) + goto finish; + + r = sd_bus_message_append(reply, "(is)", ifindex, normalized); if (r < 0) goto finish; @@ -671,6 +684,7 @@ fail: static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + _cleanup_free_ char *normalized = NULL; DnsQuery *aux; int r; @@ -727,10 +741,14 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) if (r < 0) return r; + r = dns_name_normalize(rr->srv.name, &normalized); + if (r < 0) + return r; + r = sd_bus_message_append( reply, "qqqs", - rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name); + rr->srv.priority, rr->srv.weight, rr->srv.port, normalized); if (r < 0) return r; @@ -776,9 +794,17 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) if (r < 0) return r; + if (canonical) { + normalized = mfree(normalized); + + r = dns_name_normalize(DNS_RESOURCE_KEY_NAME(canonical->key), &normalized); + if (r < 0) + return r; + } + /* Note that above we appended the hostname as encoded in the * SRV, and here the canonical hostname this maps to. */ - r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name); + r = sd_bus_message_append(reply, "s", normalized); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 1ace2438c6936e1d508b5b6c4346fa5ade8cd48e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 15 Feb 2016 13:15:23 -0500 Subject: systemd-resolve: reword --help output The output didn't specify if the default for --cname/--search/--legend and other options was yes or no. Change the description to be explicit about that. Also make the --help output and man page closer. --- man/systemd-resolve.xml | 2 +- src/resolve/resolve-tool.c | 45 +++++++++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index 5bd05368d7..bec6213de2 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -65,7 +65,7 @@ systemd-resolve OPTIONS --type=TYPE - RRDOMAIN + DOMAIN diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index c1be03fbb2..ed9b0353cc 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -976,27 +976,32 @@ static void help_dns_classes(void) { } static void help(void) { - printf("%s [OPTIONS...] NAME...\n" - "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n" + printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n" + "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n" + "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n" + "%1$s [OPTIONS...] --statistics\n" + "%1$s [OPTIONS...] --reset-statistics\n" + "\n" "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " -4 Resolve IPv4 addresses\n" - " -6 Resolve IPv6 addresses\n" - " -i --interface=INTERFACE Look on interface\n" - " -p --protocol=PROTOCOL|help Look via protocol\n" - " -t --type=TYPE|help Query RR with DNS type\n" - " -c --class=CLASS|help Query RR with DNS class\n" - " --service Resolve service (SRV)\n" - " --service-address=BOOL Do [not] resolve address for services\n" - " --service-txt=BOOL Do [not] resolve TXT records for services\n" - " --openpgp Query OpenPGP public key\n" - " --cname=BOOL Do [not] follow CNAME redirects\n" - " --search=BOOL Do [not] use search domains\n" - " --legend=BOOL Do [not] print column headers and meta information\n" - " --statistics Show resolver statistics\n" - " --reset-statistics Reset resolver statistics\n" - , program_invocation_short_name, program_invocation_short_name); + " -h --help Show this help\n" + " --version Show package version\n" + " -4 Resolve IPv4 addresses\n" + " -6 Resolve IPv6 addresses\n" + " -i --interface=INTERFACE Look on interface\n" + " -p --protocol=PROTO|help Look via protocol\n" + " -t --type=TYPE|help Query RR with DNS type\n" + " -c --class=CLASS|help Query RR with DNS class\n" + " --service Resolve service (SRV)\n" + " --service-address=BOOL Resolve address for services (default: yes)\n" + " --service-txt=BOOL Resolve TXT records for services (default: yes)\n" + " --openpgp Query OpenPGP public key\n" + " --cname=BOOL Follow CNAME redirects (default: yes)\n" + " --search=BOOL Use search domains for single-label names\n" + " (default: yes)\n" + " --legend=BOOL Print headers and additional info (default: yes)\n" + " --statistics Show resolver statistics\n" + " --reset-statistics Reset resolver statistics\n" + , program_invocation_short_name); } static int parse_argv(int argc, char *argv[]) { -- cgit v1.2.3-54-g00ecf From 2e74028a5cf636760191656d7fabfa9f43db96e2 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Jan 2016 18:24:28 -0500 Subject: systemd-resolve: allow keys to be dumped in binary form $ systemd-resolve --raw --openpgp zbyszek@fedoraproject.org | pgpdump /dev/stdin --- src/resolve/resolve-tool.c | 40 +++++++++++++++++++++++++++++++++------- src/resolve/resolved-dns-rr.c | 38 ++++++++++++++++++++++++++++++++++++++ src/resolve/resolved-dns-rr.h | 2 ++ 3 files changed, 73 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index ed9b0353cc..a24bb546d4 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -43,6 +43,7 @@ static uint16_t arg_type = 0; static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; +static bool arg_raw = false; static enum { MODE_RESOLVE_HOST, @@ -379,7 +380,6 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - const char *s; uint16_t c, t; int ifindex; const void *d; @@ -413,13 +413,27 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ if (r < 0) return log_error_errno(r, "Failed to parse RR: %m"); - s = dns_resource_record_to_string(rr); - if (!s) - return log_oom(); + if (arg_raw) { + void *data; + ssize_t k; - ifname[0] = 0; - if (ifindex > 0 && !if_indextoname(ifindex, ifname)) - log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); + k = dns_resource_record_payload(rr, &data); + if (k < 0) + return log_error_errno(k, "Cannot dump RR: %m"); + fwrite(data, 1, k, stdout); + } else { + const char *s; + + s = dns_resource_record_to_string(rr); + if (!s) + return log_oom(); + + ifname[0] = 0; + if (ifindex > 0 && !if_indextoname(ifindex, ifname)) + log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); + + printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); + } printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); @@ -1013,6 +1027,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SERVICE_ADDRESS, ARG_SERVICE_TXT, ARG_OPENPGP, + ARG_RAW, ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, @@ -1031,6 +1046,7 @@ static int parse_argv(int argc, char *argv[]) { { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, { "openpgp", no_argument, NULL, ARG_OPENPGP }, + { "raw", no_argument, NULL, ARG_RAW }, { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, @@ -1144,6 +1160,16 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESOLVE_OPENPGP; break; + case ARG_RAW: + if (on_tty()) { + log_error("Refusing to write binary data to tty."); + return -ENOTTY; + } + + arg_raw = true; + arg_legend = false; + break; + case ARG_CNAME: r = parse_boolean(optarg); if (r < 0) diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 6397005a68..919a0d3c2c 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1204,6 +1204,44 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { return s; } +ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) { + assert(rr); + assert(out); + + switch(rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { + case DNS_TYPE_SRV: + case DNS_TYPE_PTR: + case DNS_TYPE_NS: + case DNS_TYPE_CNAME: + case DNS_TYPE_DNAME: + case DNS_TYPE_HINFO: + case DNS_TYPE_SPF: + case DNS_TYPE_TXT: + case DNS_TYPE_A: + case DNS_TYPE_AAAA: + case DNS_TYPE_SOA: + case DNS_TYPE_MX: + case DNS_TYPE_LOC: + case DNS_TYPE_DS: + case DNS_TYPE_SSHFP: + case DNS_TYPE_DNSKEY: + case DNS_TYPE_RRSIG: + case DNS_TYPE_NSEC: + case DNS_TYPE_NSEC3: + return -EINVAL; + + case DNS_TYPE_TLSA: + *out = rr->tlsa.data; + return rr->tlsa.data_size; + + + case DNS_TYPE_OPENPGPKEY: + default: + *out = rr->generic.data; + return rr->generic.data_size; + } +} + int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) { DnsPacket packet = { diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 23749790b4..964bf7e77a 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -303,6 +303,8 @@ int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain); int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa); int dns_resource_key_to_string(const DnsResourceKey *key, char **ret); +ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref); static inline bool dns_key_is_shared(const DnsResourceKey *key) { -- cgit v1.2.3-54-g00ecf From dab48ea63a461e2fe2bd491ba28570424bcaf362 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 31 Jan 2016 00:06:49 -0500 Subject: systemd-resolve: allow whole packets to be dumped in binary form --- man/systemd-resolve.xml | 10 +++++ src/resolve/resolve-tool.c | 109 +++++++++++++++++++++++++++++---------------- 2 files changed, 80 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index bec6213de2..c288fd974e 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -232,6 +232,16 @@ logic is disabled. + + =payload|packet + + Dump the answer as binary data. If there is no argument or if the argument is + payload, the payload of the packet is exported. If the argument is + packet, the whole packet is dumped in wire format, prefixed by + length specified as a little-endian 64-bit number. This format allows multiple packets + to be dumped and unambigously parsed. + + BOOL diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index a24bb546d4..a519074278 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -43,7 +43,14 @@ static uint16_t arg_type = 0; static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; -static bool arg_raw = false; + +typedef enum RawType { + RAW_NONE, + RAW_PAYLOAD, + RAW_PACKET, +} RawType; + +static RawType arg_raw = RAW_NONE; static enum { MODE_RESOLVE_HOST, @@ -332,6 +339,50 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres return 0; } +static int output_rr_packet(const void *d, size_t l, int ifindex) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + int r; + char ifname[IF_NAMESIZE] = ""; + + r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); + if (r < 0) + return log_oom(); + + p->refuse_compression = true; + + r = dns_packet_append_blob(p, d, l, NULL); + if (r < 0) + return log_oom(); + + r = dns_packet_read_rr(p, &rr, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to parse RR: %m"); + + if (arg_raw == RAW_PAYLOAD) { + void *data; + ssize_t k; + + k = dns_resource_record_payload(rr, &data); + if (k < 0) + return log_error_errno(k, "Cannot dump RR: %m"); + fwrite(data, 1, k, stdout); + } else { + const char *s; + + s = dns_resource_record_to_string(rr); + if (!s) + return log_oom(); + + if (ifindex > 0 && !if_indextoname(ifindex, ifname)) + log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); + + printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); + } + + return 0; +} + static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -378,8 +429,6 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ return bus_log_parse_error(r); while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; uint16_t c, t; int ifindex; const void *d; @@ -399,44 +448,17 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_ if (r < 0) return bus_log_parse_error(r); - r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); - if (r < 0) - return log_oom(); - - p->refuse_compression = true; - - r = dns_packet_append_blob(p, d, l, NULL); - if (r < 0) - return log_oom(); + if (arg_raw == RAW_PACKET) { + uint64_t u64 = htole64(l); - r = dns_packet_read_rr(p, &rr, NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to parse RR: %m"); - - if (arg_raw) { - void *data; - ssize_t k; - - k = dns_resource_record_payload(rr, &data); - if (k < 0) - return log_error_errno(k, "Cannot dump RR: %m"); - fwrite(data, 1, k, stdout); + fwrite(&u64, sizeof(u64), 1, stdout); + fwrite(d, 1, l, stdout); } else { - const char *s; - - s = dns_resource_record_to_string(rr); - if (!s) - return log_oom(); - - ifname[0] = 0; - if (ifindex > 0 && !if_indextoname(ifindex, ifname)) - log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); - - printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); + r = output_rr_packet(d, l, ifindex); + if (r < 0) + return r; } - printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); - if (dns_type_needs_authentication(t)) needs_authentication = true; @@ -1012,6 +1034,7 @@ static void help(void) { " --cname=BOOL Follow CNAME redirects (default: yes)\n" " --search=BOOL Use search domains for single-label names\n" " (default: yes)\n" + " --raw[=payload|packet] Dump the answer as binary data\n" " --legend=BOOL Print headers and additional info (default: yes)\n" " --statistics Show resolver statistics\n" " --reset-statistics Reset resolver statistics\n" @@ -1046,7 +1069,7 @@ static int parse_argv(int argc, char *argv[]) { { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, { "openpgp", no_argument, NULL, ARG_OPENPGP }, - { "raw", no_argument, NULL, ARG_RAW }, + { "raw", optional_argument, NULL, ARG_RAW }, { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, @@ -1166,7 +1189,15 @@ static int parse_argv(int argc, char *argv[]) { return -ENOTTY; } - arg_raw = true; + if (optarg == NULL || streq(optarg, "payload")) + arg_raw = RAW_PAYLOAD; + else if (streq(optarg, "packet")) + arg_raw = RAW_PACKET; + else { + log_error("Unknown --raw specifier \"%s\".", optarg); + return -EINVAL; + } + arg_legend = false; break; -- cgit v1.2.3-54-g00ecf From c690b20a8593fa00c09d6120565a1e79fc9cb362 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 3 Feb 2016 21:37:11 -0500 Subject: systemd-resolved: split out inner loop With two nested loops and a switch statements, it's quite hard to understand what break and continue mean. --- src/resolve/resolved-dns-transaction.c | 513 +++++++++++++++++---------------- 1 file changed, 257 insertions(+), 256 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 060c430f3a..1a8ba2e4d5 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -2541,343 +2541,344 @@ static int dns_transaction_copy_validated(DnsTransaction *t) { return 0; } -int dns_transaction_validate_dnssec(DnsTransaction *t) { - _cleanup_(dns_answer_unrefp) DnsAnswer *validated = NULL; - enum { - PHASE_DNSKEY, /* Phase #1, only validate DNSKEYs */ - PHASE_NSEC, /* Phase #2, only validate NSEC+NSEC3 */ - PHASE_ALL, /* Phase #3, validate everything else */ - } phase; +typedef enum { + DNSSEC_PHASE_DNSKEY, /* Phase #1, only validate DNSKEYs */ + DNSSEC_PHASE_NSEC, /* Phase #2, only validate NSEC+NSEC3 */ + DNSSEC_PHASE_ALL, /* Phase #3, validate everything else */ +} Phase; + +static int dnssec_validate_records( + DnsTransaction *t, + Phase phase, + bool *have_nsec, + DnsAnswer **validated) { + DnsResourceRecord *rr; - DnsAnswerFlags flags; int r; - assert(t); + /* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */ - /* We have now collected all DS and DNSKEY RRs in - * t->validated_keys, let's see which RRs we can now - * authenticate with that. */ + DNS_ANSWER_FOREACH(rr, t->answer) { + DnsResourceRecord *rrsig = NULL; + DnssecResult result; - if (t->scope->dnssec_mode == DNSSEC_NO) - return 0; + switch (rr->key->type) { + case DNS_TYPE_RRSIG: + continue; - /* Already validated */ - if (t->answer_dnssec_result != _DNSSEC_RESULT_INVALID) - return 0; + case DNS_TYPE_DNSKEY: + /* We validate DNSKEYs only in the DNSKEY and ALL phases */ + if (phase == DNSSEC_PHASE_NSEC) + continue; + break; - /* Our own stuff needs no validation */ - if (IN_SET(t->answer_source, DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR)) { - t->answer_dnssec_result = DNSSEC_VALIDATED; - t->answer_authenticated = true; - return 0; - } + case DNS_TYPE_NSEC: + case DNS_TYPE_NSEC3: + *have_nsec = true; - /* Cached stuff is not affected by validation. */ - if (t->answer_source != DNS_TRANSACTION_NETWORK) - return 0; + /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */ + if (phase == DNSSEC_PHASE_DNSKEY) + continue; + break; - if (!dns_transaction_dnssec_supported_full(t)) { - /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */ - t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER; - log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id); - return 0; - } + default: + /* We validate all other RRs only in the ALL phases */ + if (phase != DNSSEC_PHASE_ALL) + continue; + } - log_debug("Validating response from transaction %" PRIu16 " (%s).", t->id, dns_transaction_key_string(t)); + r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig); + if (r < 0) + return r; - /* First, see if this response contains any revoked trust - * anchors we care about */ - r = dns_transaction_check_revoked_trust_anchors(t); - if (r < 0) - return r; + log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result)); - /* Third, copy all RRs we acquired successfully from auxiliary RRs over. */ - r = dns_transaction_copy_validated(t); - if (r < 0) - return r; + if (result == DNSSEC_VALIDATED) { - /* Second, see if there are DNSKEYs we already know a - * validated DS for. */ - r = dns_transaction_validate_dnskey_by_ds(t); - if (r < 0) - return r; + if (rr->key->type == DNS_TYPE_DNSKEY) { + /* If we just validated a DNSKEY RRset, then let's add these keys to + * the set of validated keys for this transaction. */ - /* Fourth, remove all DNSKEY and DS RRs again that our trust - * anchor says are revoked. After all we might have marked - * some keys revoked above, but they might still be lingering - * in our validated_keys list. */ - r = dns_transaction_invalidate_revoked_keys(t); - if (r < 0) - return r; + r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; - phase = PHASE_DNSKEY; - for (;;) { - bool changed = false, have_nsec = false; + /* Some of the DNSKEYs we just added might already have been revoked, + * remove them again in that case. */ + r = dns_transaction_invalidate_revoked_keys(t); + if (r < 0) + return r; + } - DNS_ANSWER_FOREACH(rr, t->answer) { - DnsResourceRecord *rrsig = NULL; - DnssecResult result; + /* Add the validated RRset to the new list of validated + * RRsets, and remove it from the unvalidated RRsets. + * We mark the RRset as authenticated and cacheable. */ + r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE); + if (r < 0) + return r; - switch (rr->key->type) { + manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key); - case DNS_TYPE_RRSIG: - continue; + /* Exit the loop, we dropped something from the answer, start from the beginning */ + return 1; + } - case DNS_TYPE_DNSKEY: - /* We validate DNSKEYs only in the DNSKEY and ALL phases */ - if (phase == PHASE_NSEC) - continue; - break; + /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as + * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet, + * we cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */ + if (phase != DNSSEC_PHASE_ALL) + continue; - case DNS_TYPE_NSEC: - case DNS_TYPE_NSEC3: - have_nsec = true; + if (result == DNSSEC_VALIDATED_WILDCARD) { + bool authenticated = false; + const char *source; - /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */ - if (phase == PHASE_DNSKEY) - continue; + /* This RRset validated, but as a wildcard. This means we need + * to prove via NSEC/NSEC3 that no matching non-wildcard RR exists.*/ - break; + /* First step, determine the source of synthesis */ + r = dns_resource_record_source(rrsig, &source); + if (r < 0) + return r; - default: - /* We validate all other RRs only in the ALL phases */ - if (phase != PHASE_ALL) - continue; + r = dnssec_test_positive_wildcard(*validated, + DNS_RESOURCE_KEY_NAME(rr->key), + source, + rrsig->rrsig.signer, + &authenticated); - break; + /* Unless the NSEC proof showed that the key really doesn't exist something is off. */ + if (r == 0) + result = DNSSEC_INVALID; + else { + r = dns_answer_move_by_key(validated, &t->answer, rr->key, + authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key); + + /* Exit the loop, we dropped something from the answer, start from the beginning */ + return 1; } + } - r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig); + if (result == DNSSEC_NO_SIGNATURE) { + r = dns_transaction_requires_rrsig(t, rr); if (r < 0) return r; + if (r == 0) { + /* Data does not require signing. In that case, just copy it over, + * but remember that this is by no means authenticated.*/ + r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + return 1; + } - log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result)); + r = dns_transaction_known_signed(t, rr); + if (r < 0) + return r; + if (r > 0) { + /* This is an RR we know has to be signed. If it isn't this means + * the server is not attaching RRSIGs, hence complain. */ - if (result == DNSSEC_VALIDATED) { + dns_server_packet_rrsig_missing(t->server, t->current_feature_level); - if (rr->key->type == DNS_TYPE_DNSKEY) { - /* If we just validated a - * DNSKEY RRset, then let's - * add these keys to the set - * of validated keys for this - * transaction. */ + if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) { - r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED); - if (r < 0) - return r; + /* Downgrading is OK? If so, just consider the information unsigned */ - /* some of the DNSKEYs we just - * added might already have - * been revoked, remove them - * again in that case. */ - r = dns_transaction_invalidate_revoked_keys(t); + r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); if (r < 0) return r; - } - - /* Add the validated RRset to the new - * list of validated RRsets, and - * remove it from the unvalidated - * RRsets. We mark the RRset as - * authenticated and cacheable. */ - r = dns_answer_move_by_key(&validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE); - if (r < 0) - return r; - manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key); + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + return 1; + } - /* Exit the loop, we dropped something from the answer, start from the beginning */ - changed = true; - break; + /* Otherwise, fail */ + t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER; + return 0; } - /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as - * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet, we - * cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */ - if (phase != PHASE_ALL) - continue; + r = dns_transaction_in_private_tld(t, rr->key); + if (r < 0) + return r; + if (r > 0) { + _cleanup_free_ char *s = NULL; - if (result == DNSSEC_VALIDATED_WILDCARD) { - bool authenticated = false; - const char *source; + /* The data is from a TLD that is proven not to exist, and we are in downgrade + * mode, hence ignore the fact that this was not signed. */ - /* This RRset validated, but as a wildcard. This means we need to prove via NSEC/NSEC3 - * that no matching non-wildcard RR exists.*/ + (void) dns_resource_key_to_string(rr->key, &s); + log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", strna(s ? strstrip(s) : NULL)); - /* First step, determine the source of synthesis */ - r = dns_resource_record_source(rrsig, &source); + r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); if (r < 0) return r; - r = dnssec_test_positive_wildcard( - validated, - DNS_RESOURCE_KEY_NAME(rr->key), - source, - rrsig->rrsig.signer, - &authenticated); - - /* Unless the NSEC proof showed that the key really doesn't exist something is off. */ - if (r == 0) - result = DNSSEC_INVALID; - else { - r = dns_answer_move_by_key(&validated, &t->answer, rr->key, authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0); - if (r < 0) - return r; + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + return 1; + } + } - manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key); + if (IN_SET(result, + DNSSEC_MISSING_KEY, + DNSSEC_SIGNATURE_EXPIRED, + DNSSEC_UNSUPPORTED_ALGORITHM)) { - /* Exit the loop, we dropped something from the answer, start from the beginning */ - changed = true; - break; - } - } + r = dns_transaction_dnskey_authenticated(t, rr); + if (r < 0 && r != -ENXIO) + return r; + if (r == 0) { + /* The DNSKEY transaction was not authenticated, this means there's + * no DS for this, which means it's OK if no keys are found for this signature. */ - if (result == DNSSEC_NO_SIGNATURE) { - r = dns_transaction_requires_rrsig(t, rr); + r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); if (r < 0) return r; - if (r == 0) { - /* Data does not require signing. In that case, just copy it over, - * but remember that this is by no means authenticated.*/ - r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); - if (r < 0) - return r; - manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); - changed = true; - break; - } + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + return 1; + } + } - r = dns_transaction_known_signed(t, rr); + r = dns_transaction_is_primary_response(t, rr); + if (r < 0) + return r; + if (r > 0) { + /* Look for a matching DNAME for this CNAME */ + r = dns_answer_has_dname_for_cname(t->answer, rr); + if (r < 0) + return r; + if (r == 0) { + /* Also look among the stuff we already validated */ + r = dns_answer_has_dname_for_cname(*validated, rr); if (r < 0) return r; - if (r > 0) { - /* This is an RR we know has to be signed. If it isn't this means - * the server is not attaching RRSIGs, hence complain. */ - - dns_server_packet_rrsig_missing(t->server, t->current_feature_level); + } - if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) { + if (r == 0) { + if (IN_SET(result, + DNSSEC_INVALID, + DNSSEC_SIGNATURE_EXPIRED, + DNSSEC_NO_SIGNATURE)) + manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key); + else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */ + manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key); + + /* This is a primary response to our question, and it failed validation. + * That's fatal. */ + t->answer_dnssec_result = result; + return 0; + } - /* Downgrading is OK? If so, just consider the information unsigned */ + /* This is a primary response, but we do have a DNAME RR + * in the RR that can replay this CNAME, hence rely on + * that, and we can remove the CNAME in favour of it. */ + } - r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); - if (r < 0) - return r; + /* This is just some auxiliary data. Just remove the RRset and continue. */ + r = dns_answer_remove_by_key(&t->answer, rr->key); + if (r < 0) + return r; - manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); - changed = true; - break; - } + /* We dropped something from the answer, start from the beginning. */ + return 1; + } - /* Otherwise, fail */ - t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER; - return 0; - } + return 2; /* Finito. */ +} - r = dns_transaction_in_private_tld(t, rr->key); - if (r < 0) - return r; - if (r > 0) { - _cleanup_free_ char *s = NULL; +int dns_transaction_validate_dnssec(DnsTransaction *t) { + _cleanup_(dns_answer_unrefp) DnsAnswer *validated = NULL; + Phase phase; + DnsAnswerFlags flags; + int r; - /* The data is from a TLD that is proven not to exist, and we are in downgrade - * mode, hence ignore the fact that this was not signed. */ + assert(t); - (void) dns_resource_key_to_string(rr->key, &s); - log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", strna(s ? strstrip(s) : NULL)); + /* We have now collected all DS and DNSKEY RRs in + * t->validated_keys, let's see which RRs we can now + * authenticate with that. */ - r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); - if (r < 0) - return r; + if (t->scope->dnssec_mode == DNSSEC_NO) + return 0; - manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); - changed = true; - break; - } - } + /* Already validated */ + if (t->answer_dnssec_result != _DNSSEC_RESULT_INVALID) + return 0; - if (IN_SET(result, - DNSSEC_MISSING_KEY, - DNSSEC_SIGNATURE_EXPIRED, - DNSSEC_UNSUPPORTED_ALGORITHM)) { + /* Our own stuff needs no validation */ + if (IN_SET(t->answer_source, DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR)) { + t->answer_dnssec_result = DNSSEC_VALIDATED; + t->answer_authenticated = true; + return 0; + } - r = dns_transaction_dnskey_authenticated(t, rr); - if (r < 0 && r != -ENXIO) - return r; - if (r == 0) { - /* The DNSKEY transaction was not authenticated, this means there's - * no DS for this, which means it's OK if no keys are found for this signature. */ + /* Cached stuff is not affected by validation. */ + if (t->answer_source != DNS_TRANSACTION_NETWORK) + return 0; - r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); - if (r < 0) - return r; + if (!dns_transaction_dnssec_supported_full(t)) { + /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */ + t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER; + log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id); + return 0; + } - manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); - changed = true; - break; - } - } + log_debug("Validating response from transaction %" PRIu16 " (%s).", t->id, dns_transaction_key_string(t)); - r = dns_transaction_is_primary_response(t, rr); - if (r < 0) - return r; - if (r > 0) { + /* First, see if this response contains any revoked trust + * anchors we care about */ + r = dns_transaction_check_revoked_trust_anchors(t); + if (r < 0) + return r; - /* Look for a matching DNAME for this CNAME */ - r = dns_answer_has_dname_for_cname(t->answer, rr); - if (r < 0) - return r; - if (r == 0) { - /* Also look among the stuff we already validated */ - r = dns_answer_has_dname_for_cname(validated, rr); - if (r < 0) - return r; - } + /* Third, copy all RRs we acquired successfully from auxiliary RRs over. */ + r = dns_transaction_copy_validated(t); + if (r < 0) + return r; - if (r == 0) { - if (IN_SET(result, - DNSSEC_INVALID, - DNSSEC_SIGNATURE_EXPIRED, - DNSSEC_NO_SIGNATURE)) - manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key); - else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */ - manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key); - - /* This is a primary response to our question, and it failed validation. That's - * fatal. */ - t->answer_dnssec_result = result; - return 0; - } + /* Second, see if there are DNSKEYs we already know a + * validated DS for. */ + r = dns_transaction_validate_dnskey_by_ds(t); + if (r < 0) + return r; - /* This is a primary response, but we do have a DNAME RR in the RR that can replay this - * CNAME, hence rely on that, and we can remove the CNAME in favour of it. */ - } + /* Fourth, remove all DNSKEY and DS RRs again that our trust + * anchor says are revoked. After all we might have marked + * some keys revoked above, but they might still be lingering + * in our validated_keys list. */ + r = dns_transaction_invalidate_revoked_keys(t); + if (r < 0) + return r; - /* This is just some auxiliary data. Just remove the RRset and continue. */ - r = dns_answer_remove_by_key(&t->answer, rr->key); - if (r < 0) - return r; + phase = DNSSEC_PHASE_DNSKEY; + for (;;) { + bool have_nsec = false; - /* Exit the loop, we dropped something from the answer, start from the beginning */ - changed = true; - break; - } + r = dnssec_validate_records(t, phase, &have_nsec, &validated); + if (r <= 0) + return r; - /* Restart the inner loop as long as we managed to achieve something */ - if (changed) + /* Try again as long as we managed to achieve something */ + if (r == 1) continue; - if (phase == PHASE_DNSKEY && have_nsec) { + if (phase == DNSSEC_PHASE_DNSKEY && have_nsec) { /* OK, we processed all DNSKEYs, and there are NSEC/NSEC3 RRs, look at those now. */ - phase = PHASE_NSEC; + phase = DNSSEC_PHASE_NSEC; continue; } - if (phase != PHASE_ALL) { - /* OK, we processed all DNSKEYs and NSEC/NSEC3 RRs, look at all the rest now. Note that in this - * third phase we start to remove RRs we couldn't validate. */ - phase = PHASE_ALL; + if (phase != DNSSEC_PHASE_ALL) { + /* OK, we processed all DNSKEYs and NSEC/NSEC3 RRs, look at all the rest now. + * Note that in this third phase we start to remove RRs we couldn't validate. */ + phase = DNSSEC_PHASE_ALL; continue; } -- cgit v1.2.3-54-g00ecf From 1c02e7ba55e3dbb56ab20b329318b5fd5c2eb8f0 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 13 Feb 2016 14:54:15 -0500 Subject: Replace DNS_RESOURCE_KEY_NAME with a version which always returns "." for root This fixes formatting of root domain in debug messages: Old: systemd-resolved[10049]: Requesting DS to validate transaction 19313 (., DNSKEY with key tag: 19036). New: systemd-resolved[10049]: Requesting DS to validate transaction 19313 (, DNSKEY with key tag: 19036). --- src/resolve/resolved-bus.c | 6 +-- src/resolve/resolved-dns-answer.c | 8 ++-- src/resolve/resolved-dns-cache.c | 4 +- src/resolve/resolved-dns-dnssec.c | 52 +++++++++++----------- src/resolve/resolved-dns-packet.c | 4 +- src/resolve/resolved-dns-question.c | 10 ++--- src/resolve/resolved-dns-rr.c | 56 ++++++++++++++--------- src/resolve/resolved-dns-rr.h | 14 ++---- src/resolve/resolved-dns-scope.c | 4 +- src/resolve/resolved-dns-synthesize.c | 14 +++--- src/resolve/resolved-dns-transaction.c | 79 ++++++++++++++++++--------------- src/resolve/resolved-dns-trust-anchor.c | 4 +- src/resolve/resolved-dns-zone.c | 34 +++++++------- src/resolve/resolved-etc-hosts.c | 4 +- src/resolve/resolved-mdns.c | 2 +- 15 files changed, 155 insertions(+), 140 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 2d94baeb7e..a138be2421 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -202,7 +202,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { /* The key names are not necessarily normalized, make sure that they are when we return them to our bus * clients. */ - r = dns_name_normalize(DNS_RESOURCE_KEY_NAME(canonical->key), &normalized); + r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized); if (r < 0) goto finish; @@ -797,7 +797,7 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) if (canonical) { normalized = mfree(normalized); - r = dns_name_normalize(DNS_RESOURCE_KEY_NAME(canonical->key), &normalized); + r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized); if (r < 0) return r; } @@ -959,7 +959,7 @@ static void resolve_service_all_complete(DnsQuery *q) { goto finish; assert(canonical); - r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain); + r = dns_service_split(dns_resource_key_name(canonical->key), &name, &type, &domain); if (r < 0) goto finish; diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 7eb303ab95..c08f7a7edd 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -330,7 +330,7 @@ int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) { if (rr->key->type != DNS_TYPE_NSEC3) continue; - p = DNS_RESOURCE_KEY_NAME(rr->key); + p = dns_resource_key_name(rr->key); r = dns_name_parent(&p); if (r < 0) return r; @@ -363,7 +363,7 @@ int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceReco if (r > 0) { if (soa) { - r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(soa->key)); + r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(soa->key)); if (r < 0) return r; if (r > 0) @@ -840,13 +840,13 @@ bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) { if (rr->key->class != cname->key->class) continue; - r = dns_name_change_suffix(cname->cname.name, rr->dname.name, DNS_RESOURCE_KEY_NAME(rr->key), &n); + r = dns_name_change_suffix(cname->cname.name, rr->dname.name, dns_resource_key_name(rr->key), &n); if (r < 0) return r; if (r == 0) continue; - r = dns_name_equal(n, DNS_RESOURCE_KEY_NAME(cname->key)); + r = dns_name_equal(n, dns_resource_key_name(cname->key)); if (r < 0) return r; if (r > 0) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 9bcc71724e..b8e4bd3dd2 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -524,7 +524,7 @@ static int dns_cache_put_negative( if (i->type == DNS_CACHE_NXDOMAIN) { /* NXDOMAIN entries should apply equally to all types, so we use ANY as * a pseudo type for this purpose here. */ - i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(key)); + i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, dns_resource_key_name(key)); if (!i->key) return -ENOMEM; @@ -759,7 +759,7 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D if (i) return i; - n = DNS_RESOURCE_KEY_NAME(k); + n = dns_resource_key_name(k); /* Check if we have an NXDOMAIN cache item for the name, notice that we use * the pseudo-type ANY for NXDOMAIN cache items. */ diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 7098265929..0af7551425 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -467,7 +467,7 @@ static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) { if (rrsig->rrsig.inception > rrsig->rrsig.expiration) return -EINVAL; - name = DNS_RESOURCE_KEY_NAME(rrsig->key); + name = dns_resource_key_name(rrsig->key); n_key_labels = dns_name_count_labels(name); if (n_key_labels < 0) @@ -651,7 +651,7 @@ int dnssec_verify_rrset( return 0; } - name = DNS_RESOURCE_KEY_NAME(key); + name = dns_resource_key_name(key); /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */ if (dns_type_apex_only(rrsig->rrsig.type_covered)) { @@ -851,7 +851,7 @@ int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnske if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag) return 0; - return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer); + return dns_name_equal(dns_resource_key_name(dnskey->key), rrsig->rrsig.signer); } int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) { @@ -867,7 +867,7 @@ int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) if (rrsig->rrsig.type_covered != key->type) return 0; - return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key)); + return dns_name_equal(dns_resource_key_name(rrsig->key), dns_resource_key_name(key)); } int dnssec_verify_rrset_search( @@ -1070,7 +1070,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, if (ds->ds.digest_size != hash_size) return 0; - r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name)); + r = dnssec_canonicalize(dns_resource_key_name(dnskey->key), owner_name, sizeof(owner_name)); if (r < 0) return r; @@ -1120,7 +1120,7 @@ int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *vali if (ds->key->class != dnskey->key->class) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key)); + r = dns_name_equal(dns_resource_key_name(dnskey->key), dns_resource_key_name(ds->key)); if (r < 0) return r; if (r == 0) @@ -1272,14 +1272,14 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) { if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0) return 0; - a = DNS_RESOURCE_KEY_NAME(rr->key); + a = dns_resource_key_name(rr->key); r = dns_name_parent(&a); /* strip off hash */ if (r < 0) return r; if (r == 0) return 0; - b = DNS_RESOURCE_KEY_NAME(nsec3->key); + b = dns_resource_key_name(nsec3->key); r = dns_name_parent(&b); /* strip off hash */ if (r < 0) return r; @@ -1353,7 +1353,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3 * records from a given zone in a response must use the same * parameters. */ - zone = DNS_RESOURCE_KEY_NAME(key); + zone = dns_resource_key_name(key); for (;;) { DNS_ANSWER_FOREACH_FLAGS(zone_rr, flags, answer) { r = nsec3_is_good(zone_rr, NULL); @@ -1362,7 +1362,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR if (r == 0) continue; - r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr->key), 1, zone); + r = dns_name_equal_skip(dns_resource_key_name(zone_rr->key), 1, zone); if (r < 0) return r; if (r > 0) @@ -1382,7 +1382,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR found_zone: /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */ - p = DNS_RESOURCE_KEY_NAME(key); + p = dns_resource_key_name(key); for (;;) { _cleanup_free_ char *hashed_domain = NULL; @@ -1405,7 +1405,7 @@ found_zone: if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr->key), hashed_domain); + r = dns_name_equal(dns_resource_key_name(enclosure_rr->key), hashed_domain); if (r < 0) return r; if (r > 0) { @@ -1504,7 +1504,7 @@ found_closest_encloser: if (r < 0) return r; - r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain); + r = dns_name_between(dns_resource_key_name(rr->key), next_closer_domain, next_hashed_domain); if (r < 0) return r; if (r > 0) { @@ -1516,7 +1516,7 @@ found_closest_encloser: no_closer = true; } - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain); + r = dns_name_equal(dns_resource_key_name(rr->key), wildcard_domain); if (r < 0) return r; if (r > 0) { @@ -1525,7 +1525,7 @@ found_closest_encloser: wildcard_rr = rr; } - r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain, next_hashed_domain); + r = dns_name_between(dns_resource_key_name(rr->key), wildcard_domain, next_hashed_domain); if (r < 0) return r; if (r > 0) { @@ -1604,7 +1604,7 @@ static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) { if (rr->n_skip_labels_source != 1) return 0; - n = DNS_RESOURCE_KEY_NAME(rr->key); + n = dns_resource_key_name(rr->key); r = dns_label_unescape(&n, label, sizeof(label)); if (r <= 0) return r; @@ -1643,7 +1643,7 @@ static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) { return r; /* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */ - r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix); + r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix); if (r < 0) return r; @@ -1662,7 +1662,7 @@ static int dnssec_nsec_from_parent_zone(DnsResourceRecord *rr, const char *name) if (r <= 0) return r; - r = dns_name_equal(name, DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_name_equal(name, dns_resource_key_name(rr->key)); if (r <= 0) return r; @@ -1685,7 +1685,7 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) { /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */ - r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix); + r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix); if (r < 0) return r; @@ -1706,7 +1706,7 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) { /* p is now the "Next Closer". */ - return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), p, rr->nsec.next_domain_name); + return dns_name_between(dns_resource_key_name(rr->key), p, rr->nsec.next_domain_name); } static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) { @@ -1725,7 +1725,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either... */ - r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix); + r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix); if (r < 0) return r; @@ -1735,7 +1735,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) return r; wc = strjoina("*.", common_suffix, NULL); - return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wc, rr->nsec.next_domain_name); + return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name); } int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) { @@ -1750,7 +1750,7 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */ - name = DNS_RESOURCE_KEY_NAME(key); + name = dns_resource_key_name(key); DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { @@ -1770,7 +1770,7 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r continue; /* Check if this is a direct match. If so, we have encountered a NODATA case */ - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), name); + r = dns_name_equal(dns_resource_key_name(rr->key), name); if (r < 0) return r; if (r == 0) { @@ -1900,7 +1900,7 @@ static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const cha if (r == 0) continue; - r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), name, rr->nsec.next_domain_name); + r = dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name); if (r < 0) return r; @@ -1943,7 +1943,7 @@ static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const cha if (r < 0) return r; - r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), hashed_domain, next_hashed_domain); + r = dns_name_between(dns_resource_key_name(rr->key), hashed_domain, next_hashed_domain); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index c2fc1d8b05..2e41dae656 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -577,7 +577,7 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) saved_size = p->size; - r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, true, NULL); + r = dns_packet_append_name(p, dns_resource_key_name(k), true, true, NULL); if (r < 0) goto fail; @@ -2130,7 +2130,7 @@ int dns_packet_extract(DnsPacket *p) { continue; } - if (!dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key))) { + if (!dns_name_is_root(dns_resource_key_name(rr->key))) { /* If the OPT RR is not owned by the root domain, then it is bad, let's ignore * it. */ log_debug("OPT RR is not owned by root domain, ignoring."); diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c index 8e452e79a4..c8b502d1cd 100644 --- a/src/resolve/resolved-dns-question.c +++ b/src/resolve/resolved-dns-question.c @@ -145,7 +145,7 @@ int dns_question_is_valid_for_query(DnsQuestion *q) { if (q->n_keys > 65535) return 0; - name = DNS_RESOURCE_KEY_NAME(q->keys[0]); + name = dns_resource_key_name(q->keys[0]); if (!name) return 0; @@ -154,7 +154,7 @@ int dns_question_is_valid_for_query(DnsQuestion *q) { assert(q->keys[i]); if (i > 0) { - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name); + r = dns_name_equal(dns_resource_key_name(q->keys[i]), name); if (r <= 0) return r; } @@ -235,7 +235,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, if (cname->key->type == DNS_TYPE_CNAME) d = cname->cname.name; else { - r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination); + r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination); if (r < 0) return r; if (r == 0) @@ -244,7 +244,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, d = destination; } - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), d); + r = dns_name_equal(dns_resource_key_name(key), d); if (r < 0) return r; @@ -291,7 +291,7 @@ const char *dns_question_first_name(DnsQuestion *q) { if (q->n_keys < 1) return NULL; - return DNS_RESOURCE_KEY_NAME(q->keys[0]); + return dns_resource_key_name(q->keys[0]); } int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bool convert_idna) { diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 919a0d3c2c..4e2dd46155 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -66,7 +66,7 @@ DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const D DnsResourceKey *k; char *destination = NULL; - r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination); + r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination); if (r < 0) return NULL; if (r == 0) @@ -96,7 +96,7 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key return 0; } - r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined); + r = dns_name_concat(dns_resource_key_name(key), name, &joined); if (r < 0) return r; @@ -158,6 +158,23 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) { return NULL; } +const char* dns_resource_key_name(const DnsResourceKey *key) { + const char *name; + + if (!key) + return NULL; + + if (key->_name) + name = key->_name; + else + name = (char*) key + sizeof(DnsResourceKey); + + if (dns_name_is_root(name)) + return "."; + else + return name; +} + bool dns_resource_key_is_address(const DnsResourceKey *key) { assert(key); @@ -172,7 +189,7 @@ int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) { if (a == b) return 1; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b)); + r = dns_name_equal(dns_resource_key_name(a), dns_resource_key_name(b)); if (r <= 0) return r; @@ -204,18 +221,18 @@ int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, if (rr->key->type != key->type && key->type != DNS_TYPE_ANY) return 0; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); + r = dns_name_equal(dns_resource_key_name(rr->key), dns_resource_key_name(key)); if (r != 0) return r; if (search_domain) { _cleanup_free_ char *joined = NULL; - r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined); + r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined); if (r < 0) return r; - return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined); + return dns_name_equal(dns_resource_key_name(rr->key), joined); } return 0; @@ -231,9 +248,9 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe return 0; if (cname->type == DNS_TYPE_CNAME) - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname)); + r = dns_name_equal(dns_resource_key_name(key), dns_resource_key_name(cname)); else if (cname->type == DNS_TYPE_DNAME) - r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname)); + r = dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(cname)); else return 0; @@ -243,14 +260,14 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe if (search_domain) { _cleanup_free_ char *joined = NULL; - r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined); + r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined); if (r < 0) return r; if (cname->type == DNS_TYPE_CNAME) - return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname)); + return dns_name_equal(joined, dns_resource_key_name(cname)); else if (cname->type == DNS_TYPE_DNAME) - return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname)); + return dns_name_endswith(joined, dns_resource_key_name(cname)); } return 0; @@ -268,7 +285,7 @@ int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey * if (soa->type != DNS_TYPE_SOA) return 0; - return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa)); + return dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(soa)); } static void dns_resource_key_hash_func(const void *i, struct siphash *state) { @@ -276,7 +293,7 @@ static void dns_resource_key_hash_func(const void *i, struct siphash *state) { assert(k); - dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state); + dns_name_hash_func(dns_resource_key_name(k), state); siphash24_compress(&k->class, sizeof(k->class), state); siphash24_compress(&k->type, sizeof(k->type), state); } @@ -285,7 +302,7 @@ static int dns_resource_key_compare_func(const void *a, const void *b) { const DnsResourceKey *x = a, *y = b; int ret; - ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y)); + ret = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y)); if (ret != 0) return ret; @@ -309,7 +326,7 @@ const struct hash_ops dns_resource_key_hash_ops = { int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) { char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)]; - const char *c, *t, *n; + const char *c, *t; char *s; /* If we cannot convert the CLASS/TYPE into a known string, @@ -327,8 +344,7 @@ int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) { t = tbuf; } - n = DNS_RESOURCE_KEY_NAME(key); - if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0) + if (asprintf(&s, "%s %s %-5s", dns_resource_key_name(key), c, t) < 0) return -ENOMEM; *ret = s; @@ -1299,7 +1315,7 @@ int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) { if (rr->n_skip_labels_signer == (unsigned) -1) return -ENODATA; - n = DNS_RESOURCE_KEY_NAME(rr->key); + n = dns_resource_key_name(rr->key); r = dns_name_skip(n, rr->n_skip_labels_signer, &n); if (r < 0) return r; @@ -1322,7 +1338,7 @@ int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) { if (rr->n_skip_labels_source == (unsigned) -1) return -ENODATA; - n = DNS_RESOURCE_KEY_NAME(rr->key); + n = dns_resource_key_name(rr->key); r = dns_name_skip(n, rr->n_skip_labels_source, &n); if (r < 0) return r; @@ -1362,7 +1378,7 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr) { if (rr->n_skip_labels_source > 1) return 1; - r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*"); + r = dns_name_startswith(dns_resource_key_name(rr->key), "*"); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 964bf7e77a..6feefdfe62 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -26,6 +26,7 @@ #include "hashmap.h" #include "in-addr-util.h" #include "list.h" +#include "string-util.h" typedef struct DnsResourceKey DnsResourceKey; typedef struct DnsResourceRecord DnsResourceRecord; @@ -81,7 +82,7 @@ enum { struct DnsResourceKey { unsigned n_ref; /* (unsigned -1) for const keys, see below */ uint16_t class, type; - char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */ + char *_name; /* don't access directy, use dns_resource_key_name()! */ }; /* Creates a temporary resource key. This is only useful to quickly @@ -260,16 +261,6 @@ struct DnsResourceRecord { }; }; -static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) { - if (!key) - return NULL; - - if (key->_name) - return key->_name; - - return (char*) key + sizeof(DnsResourceKey); -} - static inline const void* DNS_RESOURCE_RECORD_RDATA(DnsResourceRecord *rr) { if (!rr) return NULL; @@ -297,6 +288,7 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name); DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key); DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key); +const char* dns_resource_key_name(const DnsResourceKey *key); bool dns_resource_key_is_address(const DnsResourceKey *key); int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b); int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index a406872a38..66e4585c18 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -514,8 +514,8 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) { * that those should be resolved via LLMNR or search * path only, and should not be leaked onto the * internet. */ - return !(dns_name_is_single_label(DNS_RESOURCE_KEY_NAME(key)) || - dns_name_is_root(DNS_RESOURCE_KEY_NAME(key))); + return !(dns_name_is_single_label(dns_resource_key_name(key)) || + dns_name_is_root(dns_resource_key_name(key))); } /* On mDNS and LLMNR, send A and AAAA queries only on the diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c index f4a43dee8c..e3003411f7 100644 --- a/src/resolve/resolved-dns-synthesize.c +++ b/src/resolve/resolved-dns-synthesize.c @@ -86,7 +86,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key)); + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key)); if (!rr) return -ENOMEM; @@ -100,7 +100,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key)); + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key)); if (!rr) return -ENOMEM; @@ -140,7 +140,7 @@ static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int i if (r < 0) return r; - r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; } @@ -254,11 +254,11 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, .address.in6 = in6addr_loopback, }; - return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n); + return answer_add_addresses_rr(answer, dns_resource_key_name(key), buffer, n); } } - return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n); + return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n); } static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) { @@ -319,7 +319,7 @@ static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifin return n; } - return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n); + return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n); } static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) { @@ -360,7 +360,7 @@ int dns_synthesize_answer( key->class != DNS_CLASS_ANY) continue; - name = DNS_RESOURCE_KEY_NAME(key); + name = dns_resource_key_name(key); if (is_localhost(name)) { diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 1a8ba2e4d5..396fce803c 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -522,7 +522,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { * the IP address, in case this is a reverse * PTR lookup */ - r = dns_name_address(DNS_RESOURCE_KEY_NAME(t->key), &family, &address); + r = dns_name_address(dns_resource_key_name(t->key), &family, &address); if (r < 0) return r; if (r == 0) @@ -1209,7 +1209,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { return 0; } - if (dns_name_is_root(DNS_RESOURCE_KEY_NAME(t->key)) && + if (dns_name_is_root(dns_resource_key_name(t->key)) && t->key->type == DNS_TYPE_DS) { /* Hmm, this is a request for the root DS? A @@ -1494,8 +1494,8 @@ int dns_transaction_go(DnsTransaction *t) { return r; if (t->scope->protocol == DNS_PROTOCOL_LLMNR && - (dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "in-addr.arpa") > 0 || - dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "ip6.arpa") > 0)) { + (dns_name_endswith(dns_resource_key_name(t->key), "in-addr.arpa") > 0 || + dns_name_endswith(dns_resource_key_name(t->key), "ip6.arpa") > 0)) { /* RFC 4795, Section 2.4. says reverse lookups shall * always be made via TCP on LLMNR */ @@ -1708,7 +1708,7 @@ static int dns_transaction_has_unsigned_negative_answer(DnsTransaction *t) { /* Is this key explicitly listed as a negative trust anchor? * If so, it's nothing we need to care about */ - r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key)); + r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key)); if (r < 0) return r; if (r > 0) @@ -1816,7 +1816,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { continue; /* If this RR is in the negative trust anchor, we don't need to validate it. */ - r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key)); if (r < 0) return r; if (r > 0) @@ -1833,7 +1833,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * already have the DNSKEY, and we don't have * to look for more. */ if (rr->rrsig.type_covered == DNS_TYPE_DNSKEY) { - r = dns_name_equal(rr->rrsig.signer, DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_name_equal(rr->rrsig.signer, dns_resource_key_name(rr->key)); if (r < 0) return r; if (r > 0) @@ -1851,7 +1851,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * in another transaction whose additonal RRs * point back to the original transaction, and * we deadlock. */ - r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), rr->rrsig.signer); + r = dns_name_endswith(dns_resource_key_name(t->key), rr->rrsig.signer); if (r < 0) return r; if (r == 0) @@ -1861,7 +1861,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (!dnskey) return -ENOMEM; - log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), rr->rrsig.key_tag); + log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").", + t->id, dns_resource_key_name(rr->key), rr->rrsig.key_tag); r = dns_transaction_request_dnssec_rr(t, dnskey); if (r < 0) return r; @@ -1879,17 +1880,18 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * up in request loops, and want to keep * additional traffic down. */ - r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_name_endswith(dns_resource_key_name(t->key), dns_resource_key_name(rr->key)); if (r < 0) return r; if (r == 0) continue; - ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key)); + ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key)); if (!ds) return -ENOMEM; - log_debug("Requesting DS to validate transaction %" PRIu16" (%s, DNSKEY with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dnssec_keytag(rr, false)); + log_debug("Requesting DS to validate transaction %" PRIu16" (%s, DNSKEY with key tag: %" PRIu16 ").", + t->id, dns_resource_key_name(rr->key), dnssec_keytag(rr, false)); r = dns_transaction_request_dnssec_rr(t, ds); if (r < 0) return r; @@ -1920,11 +1922,12 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (r > 0) continue; - ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key)); + ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key)); if (!ds) return -ENOMEM; - log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned SOA/NS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key)); + log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned SOA/NS RRset).", + t->id, dns_resource_key_name(rr->key)); r = dns_transaction_request_dnssec_rr(t, ds); if (r < 0) return r; @@ -1966,7 +1969,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (r > 0) continue; - name = DNS_RESOURCE_KEY_NAME(rr->key); + name = dns_resource_key_name(rr->key); r = dns_name_parent(&name); if (r < 0) return r; @@ -1977,7 +1980,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (!soa) return -ENOMEM; - log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key)); + log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).", + t->id, dns_resource_key_name(rr->key)); r = dns_transaction_request_dnssec_rr(t, soa); if (r < 0) return r; @@ -2007,11 +2011,12 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (r > 0) continue; - soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, DNS_RESOURCE_KEY_NAME(rr->key)); + soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, dns_resource_key_name(rr->key)); if (!soa) return -ENOMEM; - log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dns_resource_record_to_string(rr)); + log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).", + t->id, dns_resource_key_name(rr->key), dns_resource_record_to_string(rr)); r = dns_transaction_request_dnssec_rr(t, soa); if (r < 0) return r; @@ -2029,7 +2034,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (r > 0) { const char *name; - name = DNS_RESOURCE_KEY_NAME(t->key); + name = dns_resource_key_name(t->key); /* If this was a SOA or NS request, then this * indicates that we are not at a zone apex, hence ask @@ -2042,11 +2047,13 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (r < 0) return r; if (r > 0) - log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key)); + log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS/DS response).", + t->id, dns_resource_key_name(t->key)); else name = NULL; } else - log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key)); + log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", + t->id, dns_resource_key_name(t->key)); if (name) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL; @@ -2118,7 +2125,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * if (dns_type_is_pseudo(rr->key->type)) return -EINVAL; - r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key)); if (r < 0) return r; if (r > 0) @@ -2144,7 +2151,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * if (dt->key->type != DNS_TYPE_DS) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key)); if (r < 0) return r; if (r == 0) @@ -2187,7 +2194,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * continue; if (!parent) { - parent = DNS_RESOURCE_KEY_NAME(rr->key); + parent = dns_resource_key_name(rr->key); r = dns_name_parent(&parent); if (r < 0) return r; @@ -2201,7 +2208,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * } } - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), parent); + r = dns_name_equal(dns_resource_key_name(dt->key), parent); if (r < 0) return r; if (r == 0) @@ -2226,7 +2233,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * if (dt->key->type != DNS_TYPE_SOA) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key)); if (r < 0) return r; if (r == 0) @@ -2273,7 +2280,7 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe if (t->scope->dnssec_mode != DNSSEC_ALLOW_DOWNGRADE) return false; /* In strict DNSSEC mode what doesn't exist, doesn't exist */ - tld = DNS_RESOURCE_KEY_NAME(key); + tld = dns_resource_key_name(key); r = dns_name_parent(&tld); if (r < 0) return r; @@ -2288,7 +2295,7 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe if (dt->key->class != key->class) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), tld); + r = dns_name_equal(dns_resource_key_name(dt->key), tld); if (r < 0) return r; if (r == 0) @@ -2321,7 +2328,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { if (dns_type_is_pseudo(t->key->type)) return -EINVAL; - r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key)); + r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key)); if (r < 0) return r; if (r > 0) @@ -2339,7 +2346,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { return false; } - name = DNS_RESOURCE_KEY_NAME(t->key); + name = dns_resource_key_name(t->key); if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) { @@ -2368,7 +2375,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { if (dt->key->type != DNS_TYPE_SOA) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), name); + r = dns_name_equal(dns_resource_key_name(dt->key), name); if (r < 0) return r; if (r == 0) @@ -2390,7 +2397,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe * the specified RRset is authenticated (i.e. has a matching * DS RR). */ - r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key)); if (r < 0) return r; if (r > 0) @@ -2413,7 +2420,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe if (dt->key->type == DNS_TYPE_DNSKEY) { - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer); + r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer); if (r < 0) return r; if (r == 0) @@ -2430,7 +2437,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe } else if (dt->key->type == DNS_TYPE_DS) { - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer); + r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer); if (r < 0) return r; if (r == 0) @@ -2460,7 +2467,7 @@ static int dns_transaction_known_signed(DnsTransaction *t, DnsResourceRecord *rr * not to be signed, there's a problem with the DNS server */ return rr->key->class == DNS_CLASS_IN && - dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key)); + dns_name_is_root(dns_resource_key_name(rr->key)); } static int dns_transaction_check_revoked_trust_anchors(DnsTransaction *t) { @@ -2642,7 +2649,7 @@ static int dnssec_validate_records( return r; r = dnssec_test_positive_wildcard(*validated, - DNS_RESOURCE_KEY_NAME(rr->key), + dns_resource_key_name(rr->key), source, rrsig->rrsig.signer, &authenticated); diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c index a75337eb6a..77370e7dd5 100644 --- a/src/resolve/resolved-dns-trust-anchor.c +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -651,7 +651,7 @@ static int dns_trust_anchor_check_revoked_one(DnsTrustAnchor *d, DnsResourceReco } } - a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(revoked_dnskey->key))); + a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, dns_resource_key_name(revoked_dnskey->key))); if (a) { DnsResourceRecord *anchor; @@ -698,7 +698,7 @@ int dns_trust_anchor_check_revoked(DnsTrustAnchor *d, DnsResourceRecord *dnskey, /* Could this be interesting to us at all? If not, * there's no point in looking for and verifying a * self-signed RRSIG. */ - if (!dns_trust_anchor_knows_domain_positive(d, DNS_RESOURCE_KEY_NAME(dnskey->key))) + if (!dns_trust_anchor_knows_domain_positive(d, dns_resource_key_name(dnskey->key))) return 0; /* Look for a self-signed RRSIG in the other rrs belonging to this DNSKEY */ diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index f52383cfd1..03813da6a2 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -68,12 +68,12 @@ static void dns_zone_item_remove_and_free(DnsZone *z, DnsZoneItem *i) { else hashmap_remove(z->by_key, i->rr->key); - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key)); + first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key)); LIST_REMOVE(by_name, first, i); if (first) - assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0); + assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0); else - hashmap_remove(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key)); + hashmap_remove(z->by_name, dns_resource_key_name(i->rr->key)); dns_zone_item_free(i); } @@ -147,12 +147,12 @@ static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) { return r; } - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key)); + first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key)); if (first) { LIST_PREPEND(by_name, first, i); - assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0); + assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0); } else { - r = hashmap_put(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key), i); + r = hashmap_put(z->by_name, dns_resource_key_name(i->rr->key), i); if (r < 0) return r; } @@ -169,11 +169,11 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { if (i->probe_transaction) return 0; - t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)), false); + t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), false); if (!t) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)); + key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)); if (!key) return -ENOMEM; @@ -303,7 +303,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns * go through the list by the name and look * for everything manually */ - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + first = hashmap_get(z->by_name, dns_resource_key_name(key)); LIST_FOREACH(by_name, j, first) { if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) continue; @@ -339,7 +339,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns } if (!found) { - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + first = hashmap_get(z->by_name, dns_resource_key_name(key)); LIST_FOREACH(by_name, j, first) { if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) continue; @@ -370,7 +370,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns bool found = false, added = false; int k; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + first = hashmap_get(z->by_name, dns_resource_key_name(key)); LIST_FOREACH(by_name, j, first) { if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) continue; @@ -393,7 +393,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns } if (found && !added) { - r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL); + r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL); if (r < 0) return r; } @@ -418,7 +418,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns if (!found) { bool add_soa = false; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + first = hashmap_get(z->by_name, dns_resource_key_name(key)); LIST_FOREACH(by_name, j, first) { if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) continue; @@ -430,7 +430,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns } if (add_soa) { - r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL); + r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL); if (r < 0) return r; } @@ -482,7 +482,7 @@ void dns_zone_item_conflict(DnsZoneItem *i) { i->state = DNS_ZONE_ITEM_WITHDRAWN; /* Maybe change the hostname */ - if (manager_is_own_hostname(i->scope->manager, DNS_RESOURCE_KEY_NAME(i->rr->key)) > 0) + if (manager_is_own_hostname(i->scope->manager, dns_resource_key_name(i->rr->key)) > 0) manager_next_hostname(i->scope->manager); } @@ -562,7 +562,7 @@ int dns_zone_check_conflicts(DnsZone *zone, DnsResourceRecord *rr) { * so, we'll verify our RRs. */ /* No conflict if we don't have the name at all. */ - first = hashmap_get(zone->by_name, DNS_RESOURCE_KEY_NAME(rr->key)); + first = hashmap_get(zone->by_name, dns_resource_key_name(rr->key)); if (!first) return 0; @@ -593,7 +593,7 @@ int dns_zone_verify_conflicts(DnsZone *zone, DnsResourceKey *key) { /* Somebody else notified us about a possible conflict. Let's * verify if that's true. */ - first = hashmap_get(zone->by_name, DNS_RESOURCE_KEY_NAME(key)); + first = hashmap_get(zone->by_name, dns_resource_key_name(key)); if (!first) return 0; diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c index ee82c96822..6ccbdca20e 100644 --- a/src/resolve/resolved-etc-hosts.c +++ b/src/resolve/resolved-etc-hosts.c @@ -363,7 +363,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) { if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY)) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name); + r = dns_name_equal(dns_resource_key_name(t), name); if (r < 0) return r; if (r > 0) { @@ -413,7 +413,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) { if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY)) continue; - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name); + r = dns_name_equal(dns_resource_key_name(t), name); if (r < 0) return r; if (r == 0) diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index bc8b8b809b..b13b1d0144 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -106,7 +106,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us dns_scope_check_conflicts(scope, p); DNS_ANSWER_FOREACH(rr, p->answer) { - const char *name = DNS_RESOURCE_KEY_NAME(rr->key); + const char *name = dns_resource_key_name(rr->key); DnsTransaction *t; /* If the received reply packet contains ANY record that is not .local or .in-addr.arpa, -- cgit v1.2.3-54-g00ecf From 202b76ae1ae1a63f4fe92053ffbda8435f8b6b7e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 14 Feb 2016 18:51:55 -0500 Subject: Use provided buffer in dns_resource_key_to_string When the buffer is allocated on the stack we do not have to check for failure everywhere. This is especially useful in debug statements, because we can put dns_resource_key_to_string() call in the debug statement, and we do not need a seperate if (log_level >= LOG_DEBUG) for the conversion. dns_resource_key_to_string() is changed not to provide any whitespace padding. Most callers were stripping the whitespace with strstrip(), and it did not look to well anyway. systemd-resolve output is not column aligned anymore. The result of the conversion is not stored in DnsTransaction object anymore. It is used only for debugging, so it seems fine to generate it when needed. Various debug statements are extended to provide more information. --- src/basic/af-list.h | 16 ++++ src/resolve/dns-type.h | 3 + src/resolve/resolved-dns-cache.c | 138 ++++++++++++--------------------- src/resolve/resolved-dns-query.c | 22 ++---- src/resolve/resolved-dns-rr.c | 31 +++----- src/resolve/resolved-dns-rr.h | 7 +- src/resolve/resolved-dns-transaction.c | 71 ++++++++--------- src/resolve/resolved-dns-transaction.h | 3 - src/resolve/resolved-manager.c | 8 +- 9 files changed, 131 insertions(+), 168 deletions(-) (limited to 'src') diff --git a/src/basic/af-list.h b/src/basic/af-list.h index 135248dc64..6a4cc03839 100644 --- a/src/basic/af-list.h +++ b/src/basic/af-list.h @@ -19,7 +19,23 @@ along with systemd; If not, see . ***/ +#include "string-util.h" + const char *af_to_name(int id); int af_from_name(const char *name); +static inline const char* af_to_name_short(int id) { + const char *f; + + if (id == AF_UNSPEC) + return "*"; + + f = af_to_name(id); + if (!f) + return "unknown"; + + assert(startswith(f, "AF_")); + return f + 3; +} + int af_max(void); diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index fb7babf12a..010a47cbe5 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -124,6 +124,9 @@ enum { _DNS_CLASS_INVALID = -1 }; +#define _DNS_CLASS_STRING_MAX (sizeof "CLASS" + DECIMAL_STR_MAX(uint16_t)) +#define _DNS_TYPE_STRING_MAX (sizeof "CLASS" + DECIMAL_STR_MAX(uint16_t)) + bool dns_type_is_pseudo(uint16_t type); bool dns_type_is_valid_query(uint16_t type); bool dns_type_is_valid_rr(uint16_t type); diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index b8e4bd3dd2..4b7672fbbf 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -17,6 +17,9 @@ along with systemd; If not, see . ***/ +#include + +#include "af-list.h" #include "alloc-util.h" #include "dns-domain.h" #include "resolved-dns-answer.h" @@ -180,6 +183,7 @@ void dns_cache_prune(DnsCache *c) { for (;;) { DnsCacheItem *i; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; i = prioq_peek(c->by_expiry); if (!i) @@ -192,8 +196,12 @@ void dns_cache_prune(DnsCache *c) { break; /* Depending whether this is an mDNS shared entry - * either remove only this one RR or the whole - * RRset */ + * either remove only this one RR or the whole RRset */ + log_debug("Removing %scache entry for %s (expired "USEC_FMT"s ago)", + i->shared_owner ? "shared " : "", + dns_resource_key_to_string(i->key, key_str, sizeof key_str), + (t - i->until) / USEC_PER_SEC); + if (i->shared_owner) dns_cache_item_unlink_and_free(c, i); else { @@ -375,8 +383,8 @@ static int dns_cache_put_positive( const union in_addr_union *owner_address) { _cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL; - _cleanup_free_ char *key_str = NULL; DnsCacheItem *existing; + char key_str[DNS_RESOURCE_KEY_STRING_MAX], ifname[IF_NAMESIZE]; int r, k; assert(c); @@ -392,18 +400,9 @@ static int dns_cache_put_positive( /* New TTL is 0? Delete this specific entry... */ if (rr->ttl <= 0) { k = dns_cache_remove_by_rr(c, rr); - - if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(rr->key, &key_str); - if (r < 0) - return r; - - if (k > 0) - log_debug("Removed zero TTL entry from cache: %s", key_str); - else - log_debug("Not caching zero TTL cache entry: %s", key_str); - } - + log_debug("%s: %s", + k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry", + dns_resource_key_to_string(i->key, key_str, sizeof key_str)); return 0; } @@ -450,11 +449,18 @@ static int dns_cache_put_positive( return r; if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(i->key, &key_str); - if (r < 0) - return r; - - log_debug("Added positive cache entry for %s", key_str); + _cleanup_free_ char *t = NULL; + + (void) in_addr_to_string(i->owner_family, &i->owner_address, &t); + + log_debug("Added positive %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s", + i->authenticated ? "authenticated" : "unauthenticated", + i->shared_owner ? " shared" : "", + dns_resource_key_to_string(i->key, key_str, sizeof key_str), + (i->until - timestamp) / USEC_PER_SEC, + i->ifindex == 0 ? "*" : strna(if_indextoname(i->ifindex, ifname)), + af_to_name_short(i->owner_family), + strna(t)); } i = NULL; @@ -473,7 +479,7 @@ static int dns_cache_put_negative( const union in_addr_union *owner_address) { _cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL; - _cleanup_free_ char *key_str = NULL; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; int r; assert(c); @@ -490,14 +496,8 @@ static int dns_cache_put_negative( return 0; if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) { - if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; - - log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s", key_str); - } - + log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s", + dns_resource_key_to_string(i->key, key_str, sizeof key_str)); return 0; } @@ -542,13 +542,10 @@ static int dns_cache_put_negative( if (r < 0) return r; - if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(i->key, &key_str); - if (r < 0) - return r; - - log_debug("Added %s cache entry for %s", i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", key_str); - } + log_debug("Added %s cache entry for %s "USEC_FMT"s", + i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", + dns_resource_key_to_string(i->key, key_str, sizeof key_str), + (i->until - timestamp) / USEC_PER_SEC); i = NULL; return 0; @@ -628,16 +625,10 @@ int dns_cache_put( dns_cache_remove_previous(c, key, answer); if (dns_answer_size(answer) <= 0) { - if (log_get_max_level() >= LOG_DEBUG) { - _cleanup_free_ char *key_str = NULL; - - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; - - log_debug("Not caching negative entry without a SOA record: %s", key_str); - } + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; + log_debug("Not caching negative entry without a SOA record: %s", + dns_resource_key_to_string(key, key_str, sizeof key_str)); return 0; } @@ -801,10 +792,10 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret, bool *authenticated) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; unsigned n = 0; int r; bool nxdomain = false; - _cleanup_free_ char *key_str = NULL; DnsCacheItem *j, *first, *nsec = NULL; bool have_authenticated = false, have_non_authenticated = false; @@ -814,19 +805,12 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r assert(ret); assert(authenticated); - if (key->type == DNS_TYPE_ANY || - key->class == DNS_CLASS_ANY) { - + if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { /* If we have ANY lookups we don't use the cache, so * that the caller refreshes via the network. */ - if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; - - log_debug("Ignoring cache for ANY lookup: %s", key_str); - } + log_debug("Ignoring cache for ANY lookup: %s", + dns_resource_key_to_string(key, key_str, sizeof key_str)); c->n_miss++; @@ -839,13 +823,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r if (!first) { /* If one question cannot be answered we need to refresh */ - if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; - - log_debug("Cache miss for %s", key_str); - } + log_debug("Cache miss for %s", + dns_resource_key_to_string(key, key_str, sizeof key_str)); c->n_miss++; @@ -873,13 +852,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r /* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC RRs from * the lower-zone of a zone cut, but the DS RRs are on the upper zone. */ - if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; - - log_debug("NSEC NODATA cache hit for %s", key_str); - } + log_debug("NSEC NODATA cache hit for %s", + dns_resource_key_to_string(key, key_str, sizeof key_str)); /* We only found an NSEC record that matches our name. * If it says the type doesn't exist report @@ -900,16 +874,10 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r return 0; } - if (log_get_max_level() >= LOG_DEBUG) { - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; - - log_debug("%s cache hit for %s", - n > 0 ? "Positive" : - nxdomain ? "NXDOMAIN" : "NODATA", - key_str); - } + log_debug("%s cache hit for %s", + n > 0 ? "Positive" : + nxdomain ? "NXDOMAIN" : "NODATA", + dns_resource_key_to_string(key, key_str, sizeof key_str)); if (n <= 0) { c->n_hit++; @@ -1031,7 +999,6 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { void dns_cache_dump(DnsCache *cache, FILE *f) { Iterator iterator; DnsCacheItem *i; - int r; if (!cache) return; @@ -1057,14 +1024,9 @@ void dns_cache_dump(DnsCache *cache, FILE *f) { fputs(t, f); fputc('\n', f); } else { - _cleanup_free_ char *z = NULL; - r = dns_resource_key_to_string(j->key, &z); - if (r < 0) { - log_oom(); - continue; - } + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; - fputs(z, f); + fputs(dns_resource_key_to_string(j->key, key_str, sizeof key_str), f); fputs(" -- ", f); fputs(j->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", f); fputc('\n', f); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index a378b2b7f7..a7496aa586 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -421,6 +421,7 @@ int dns_query_new( DnsResourceKey *key; bool good = false; int r; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; assert(m); @@ -471,31 +472,20 @@ int dns_query_new( q->answer_family = AF_UNSPEC; /* First dump UTF8 question */ - DNS_QUESTION_FOREACH(key, question_utf8) { - _cleanup_free_ char *p = NULL; - - r = dns_resource_key_to_string(key, &p); - if (r < 0) - return r; - - log_debug("Looking up RR for %s.", strstrip(p)); - } + DNS_QUESTION_FOREACH(key, question_utf8) + log_debug("Looking up RR for %s.", + dns_resource_key_to_string(key, key_str, sizeof key_str)); /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */ DNS_QUESTION_FOREACH(key, question_idna) { - _cleanup_free_ char *p = NULL; - r = dns_question_contains(question_utf8, key); if (r < 0) return r; if (r > 0) continue; - r = dns_resource_key_to_string(key, &p); - if (r < 0) - return r; - - log_debug("Looking up IDNA RR for %s.", strstrip(p)); + log_debug("Looking up IDNA RR for %s.", + dns_resource_key_to_string(key, key_str, sizeof key_str)); } LIST_PREPEND(queries, m->dns_queries, q); diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 4e2dd46155..d0a86ef206 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -324,31 +324,22 @@ const struct hash_ops dns_resource_key_hash_ops = { .compare = dns_resource_key_compare_func }; -int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) { - char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)]; +char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size) { const char *c, *t; - char *s; + char *ans = buf; /* If we cannot convert the CLASS/TYPE into a known string, use the format recommended by RFC 3597, Section 5. */ c = dns_class_to_string(key->class); - if (!c) { - sprintf(cbuf, "CLASS%u", key->class); - c = cbuf; - } - t = dns_type_to_string(key->type); - if (!t){ - sprintf(tbuf, "TYPE%u", key->type); - t = tbuf; - } - if (asprintf(&s, "%s %s %-5s", dns_resource_key_name(key), c, t) < 0) - return -ENOMEM; + snprintf(buf, buf_size, "%s %s%s%.0u %s%s%.0u", + dns_resource_key_name(key), + c ?: "", c ? "" : "CLASS", c ? 0 : key->class, + t ?: "", t ? "" : "TYPE", t ? 0 : key->class); - *ret = s; - return 0; + return ans; } bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) { @@ -846,8 +837,8 @@ static char *format_txt(DnsTxtItem *first) { } const char *dns_resource_record_to_string(DnsResourceRecord *rr) { - _cleanup_free_ char *k = NULL, *t = NULL; - char *s; + _cleanup_free_ char *t = NULL; + char *s, k[DNS_RESOURCE_KEY_STRING_MAX]; int r; assert(rr); @@ -855,9 +846,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (rr->to_string) return rr->to_string; - r = dns_resource_key_to_string(rr->key, &k); - if (r < 0) - return NULL; + dns_resource_key_to_string(rr->key, k, sizeof(k)); switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 6feefdfe62..646e34598d 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -294,7 +294,12 @@ int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b); int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain); int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain); int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa); -int dns_resource_key_to_string(const DnsResourceKey *key, char **ret); + +/* _DNS_{CLASS,TYPE}_STRING_MAX include one byte for NUL, which we use for space instead below. + * DNS_HOSTNAME_MAX does not include the NUL byte, so we need to add 1. */ +#define DNS_RESOURCE_KEY_STRING_MAX (_DNS_CLASS_STRING_MAX + _DNS_TYPE_STRING_MAX + DNS_HOSTNAME_MAX + 1) + +char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size); ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 396fce803c..3443f71976 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -113,7 +113,6 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_answer_unref(t->validated_keys); dns_resource_key_unref(t->key); - free(t->key_string); free(t); return NULL; @@ -238,6 +237,7 @@ static void dns_transaction_shuffle_id(DnsTransaction *t) { static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { _cleanup_free_ char *pretty = NULL; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; DnsZoneItem *z; assert(t); @@ -250,10 +250,10 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.", t->id, - dns_transaction_key_string(t), + dns_resource_key_to_string(t->key, key_str, sizeof key_str), dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", - t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family), + af_to_name_short(t->scope->family), pretty); /* RFC 4795, Section 4.1 says that the peer with the @@ -286,20 +286,24 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { DnsTransaction *d; Iterator i; const char *st; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; assert(t); assert(!DNS_TRANSACTION_IS_LIVE(state)); - if (state == DNS_TRANSACTION_DNSSEC_FAILED) + if (state == DNS_TRANSACTION_DNSSEC_FAILED) { + dns_resource_key_to_string(t->key, key_str, sizeof key_str); + log_struct(LOG_NOTICE, LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_FAILURE), - LOG_MESSAGE("DNSSEC validation failed for question %s: %s", dns_transaction_key_string(t), dnssec_result_to_string(t->answer_dnssec_result)), + LOG_MESSAGE("DNSSEC validation failed for question %s: %s", key_str, dnssec_result_to_string(t->answer_dnssec_result)), "DNS_TRANSACTION=%" PRIu16, t->id, - "DNS_QUESTION=%s", dns_transaction_key_string(t), + "DNS_QUESTION=%s", key_str, "DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result), "DNS_SERVER=%s", dns_server_string(t->server), "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level), NULL); + } /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction @@ -312,10 +316,10 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).", t->id, - dns_transaction_key_string(t), + dns_resource_key_to_string(t->key, key_str, sizeof key_str), dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", - t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family), + af_to_name_short(t->scope->family), st, t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source), t->answer_authenticated ? "authenticated" : "unsigned"); @@ -1237,8 +1241,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { * might be DS RRs, but we don't know * them, and the DNS server won't tell * them to us (and even if it would, - * we couldn't validate it and trust - * it). */ + * we couldn't validate and trust them. */ dns_transaction_complete(t, DNS_TRANSACTION_NO_TRUST_ANCHOR); return 0; @@ -1425,6 +1428,7 @@ static int dns_transaction_make_packet(DnsTransaction *t) { int dns_transaction_go(DnsTransaction *t) { usec_t ts; int r; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; assert(t); @@ -1434,12 +1438,12 @@ int dns_transaction_go(DnsTransaction *t) { if (r <= 0) return r; - log_debug("Excercising transaction %" PRIu16 " for <%s> on scope %s on %s/%s.", + log_debug("Transaction %" PRIu16 " for <%s> scope %s on %s/%s.", t->id, - dns_transaction_key_string(t), + dns_resource_key_to_string(t->key, key_str, sizeof key_str), dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", - t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family)); + af_to_name_short(t->scope->family)); if (!t->initial_jitter_scheduled && (t->scope->protocol == DNS_PROTOCOL_LLMNR || @@ -1602,11 +1606,14 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource if (r < 0) return r; if (r > 0) { - log_debug("Detected potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).", + char s[DNS_RESOURCE_KEY_STRING_MAX], saux[DNS_RESOURCE_KEY_STRING_MAX]; + + log_debug("Potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).", aux->id, - strna(dns_transaction_key_string(aux)), + dns_resource_key_to_string(t->key, s, sizeof s), t->id, - strna(dns_transaction_key_string(t))); + dns_resource_key_to_string(aux->key, saux, sizeof saux)); + return -ELOOP; } } @@ -2316,6 +2323,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { const char *name; Iterator i; int r; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; assert(t); @@ -2342,7 +2350,8 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { * exist, and we are in downgrade mode, hence ignore * that fact that we didn't get any NSEC RRs.*/ - log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.", dns_transaction_key_string(t)); + log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.", + dns_resource_key_to_string(t->key, key_str, sizeof key_str)); return false; } @@ -2715,13 +2724,13 @@ static int dnssec_validate_records( if (r < 0) return r; if (r > 0) { - _cleanup_free_ char *s = NULL; + char s[DNS_RESOURCE_KEY_STRING_MAX]; /* The data is from a TLD that is proven not to exist, and we are in downgrade * mode, hence ignore the fact that this was not signed. */ - (void) dns_resource_key_to_string(rr->key, &s); - log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", strna(s ? strstrip(s) : NULL)); + log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", + dns_resource_key_to_string(rr->key, s, sizeof s)); r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); if (r < 0) @@ -2805,6 +2814,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { Phase phase; DnsAnswerFlags flags; int r; + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; assert(t); @@ -2837,7 +2847,9 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { return 0; } - log_debug("Validating response from transaction %" PRIu16 " (%s).", t->id, dns_transaction_key_string(t)); + log_debug("Validating response from transaction %" PRIu16 " (%s).", + t->id, + dns_resource_key_to_string(t->key, key_str, sizeof key_str)); /* First, see if this response contains any revoked trust * anchors we care about */ @@ -2929,7 +2941,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { case DNSSEC_NSEC_NXDOMAIN: /* NSEC proves the domain doesn't exist. Very good. */ - log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t)); + log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_NXDOMAIN; t->answer_authenticated = authenticated; @@ -2939,7 +2951,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { case DNSSEC_NSEC_NODATA: /* NSEC proves that there's no data here, very good. */ - log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t)); + log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_authenticated = authenticated; @@ -2949,7 +2961,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { case DNSSEC_NSEC_OPTOUT: /* NSEC3 says the data might not be signed */ - log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t)); + log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_UNSIGNED; t->answer_authenticated = false; @@ -2994,17 +3006,6 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { return 1; } -const char *dns_transaction_key_string(DnsTransaction *t) { - assert(t); - - if (!t->key_string) { - if (dns_resource_key_to_string(t->key, &t->key_string) < 0) - return "n/a"; - } - - return strstrip(t->key_string); -} - static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = { [DNS_TRANSACTION_NULL] = "null", [DNS_TRANSACTION_PENDING] = "pending", diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 4617194711..491c62d772 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -64,7 +64,6 @@ struct DnsTransaction { DnsScope *scope; DnsResourceKey *key; - char *key_string; DnsTransactionState state; @@ -153,8 +152,6 @@ void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source); int dns_transaction_validate_dnssec(DnsTransaction *t); int dns_transaction_request_dnssec_keys(DnsTransaction *t); -const char *dns_transaction_key_string(DnsTransaction *t); - const char* dns_transaction_state_to_string(DnsTransactionState p) _const_; DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 09e15fa230..44aafd0515 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1215,11 +1215,11 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource assert(verdict < _DNSSEC_VERDICT_MAX); if (log_get_max_level() >= LOG_DEBUG) { - _cleanup_free_ char *s = NULL; + char s[DNS_RESOURCE_KEY_STRING_MAX]; - (void) dns_resource_key_to_string(key, &s); - - log_debug("Found verdict for lookup %s: %s", s ? strstrip(s) : "n/a", dnssec_verdict_to_string(verdict)); + log_debug("Found verdict for lookup %s: %s", + dns_resource_key_to_string(key, s, sizeof s), + dnssec_verdict_to_string(verdict)); } m->n_dnssec_verdict[verdict]++; -- cgit v1.2.3-54-g00ecf From 5259c0559c8c0fe6ec54ac20f452fd7d106188c3 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 15 Feb 2016 18:22:11 -0500 Subject: test-resolve-tables: verify that dns type/class length is within limits DNS_TYPE_STRING_MAX causes a problem with the table autogeneration code, change to _DNS_TYPE_STRING_MAX. --- src/resolve/dns-type.h | 4 ++-- src/resolve/test-resolve-tables.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index 010a47cbe5..db9666b970 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -136,7 +136,7 @@ bool dns_type_is_obsolete(uint16_t type); bool dns_type_may_wildcard(uint16_t type); bool dns_type_apex_only(uint16_t type); bool dns_type_needs_authentication(uint16_t type); -int dns_type_to_af(uint16_t t); +int dns_type_to_af(uint16_t type); bool dns_class_is_pseudo(uint16_t class); bool dns_class_is_valid_rr(uint16_t class); @@ -145,7 +145,7 @@ bool dns_class_is_valid_rr(uint16_t class); const char *dns_type_to_string(int type); int dns_type_from_string(const char *s); -const char *dns_class_to_string(uint16_t type); +const char *dns_class_to_string(uint16_t class); int dns_class_from_string(const char *name); /* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.2 */ diff --git a/src/resolve/test-resolve-tables.c b/src/resolve/test-resolve-tables.c index 63660afc87..2d615130e1 100644 --- a/src/resolve/test-resolve-tables.c +++ b/src/resolve/test-resolve-tables.c @@ -21,7 +21,44 @@ #include "test-tables.h" int main(int argc, char **argv) { + uint16_t i; + test_table_sparse(dns_type, DNS_TYPE); + log_info("/* DNS_TYPE */"); + for (i = 0; i < _DNS_TYPE_MAX; i++) { + const char *s; + + s = dns_type_to_string(i); + assert_se(s == NULL || strlen(s) < _DNS_TYPE_STRING_MAX); + + if (s) + log_info("%-*s %s%s%s%s%s%s%s%s%s", + (int) _DNS_TYPE_STRING_MAX - 1, s, + dns_type_is_pseudo(i) ? "pseudo " : "", + dns_type_is_valid_query(i) ? "valid_query " : "", + dns_type_is_valid_rr(i) ? "is_valid_rr " : "", + dns_type_may_redirect(i) ? "may_redirect " : "", + dns_type_is_dnssec(i) ? "dnssec " : "", + dns_type_is_obsolete(i) ? "obsolete " : "", + dns_type_may_wildcard(i) ? "wildcard " : "", + dns_type_apex_only(i) ? "apex_only " : "", + dns_type_needs_authentication(i) ? "needs_authentication" : ""); + } + + log_info("/* DNS_CLASS */"); + for (i = 0; i < _DNS_CLASS_MAX; i++) { + const char *s; + + s = dns_class_to_string(i); + assert_se(s == NULL || strlen(s) < _DNS_CLASS_STRING_MAX); + + if (s) + log_info("%-*s %s%s", + (int) _DNS_CLASS_STRING_MAX - 1, s, + dns_class_is_pseudo(i) ? "is_pseudo " : "", + dns_class_is_valid_rr(i) ? "is_valid_rr " : ""); + } + return EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From 252549990ffb94da3165e1123952ef7075894f5e Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Wed, 17 Feb 2016 22:20:56 +0000 Subject: tests: add test for https://github.com/systemd/systemd/issues/2637 + perl -e 'exit(!(qq{0} eq qq{\x25U}))' exec-spec-interpolation.service: Main process exited, code=exited, status=1/FAILURE exec-spec-interpolation.service: Unit entered failed state. exec-spec-interpolation.service: Failed with result 'exit-code'. PID: 11270 Start Timestamp: Wed 2016-02-17 22:21:31 UTC Exit Timestamp: Wed 2016-02-17 22:21:31 UTC Exit Code: exited Exit Status: 1 Assertion 'service->main_exec_status.status == status_expected' failed at src/test/test-execute.c:65, function check(). Aborting. --- src/test/test-execute.c | 5 +++++ test/test-execute/exec-spec-interpolation.service | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 test/test-execute/exec-spec-interpolation.service (limited to 'src') diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 92857cb5e2..d021be4671 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -263,6 +263,10 @@ static void test_exec_ioschedulingclass(Manager *m) { test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED); } +static void test_exec_spec_interpolation(Manager *m) { + test(m, "exec-spec-interpolation.service", 0, CLD_EXITED); +} + int main(int argc, char *argv[]) { test_function_t tests[] = { test_exec_workingdirectory, @@ -284,6 +288,7 @@ int main(int argc, char *argv[]) { test_exec_capabilityambientset, test_exec_oomscoreadjust, test_exec_ioschedulingclass, + test_exec_spec_interpolation, NULL, }; test_function_t *test = NULL; diff --git a/test/test-execute/exec-spec-interpolation.service b/test/test-execute/exec-spec-interpolation.service new file mode 100644 index 0000000000..3e62662aa9 --- /dev/null +++ b/test/test-execute/exec-spec-interpolation.service @@ -0,0 +1,6 @@ +[Unit] +Description=https://github.com/systemd/systemd/issues/2637 + +[Service] +Type=oneshot +ExecStart=/bin/sh -x -c "perl -e 'exit(!(qq{%%U} eq qq{\\x25U}))'" -- cgit v1.2.3-54-g00ecf From bd1b973fb326e9b7587494fd6108e5ded46e9163 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Wed, 17 Feb 2016 22:32:36 +0000 Subject: core: revert "core: resolve specifier in config_parse_exec()" This reverts commit cb48dfca6a8bc15d9081651001a16bf51e03838a. Exec*-settings resolve specifiers twice: %%U -> config_parse_exec [cb48dfca6a8] -> %U -> service_spawn -> 0 Fixes #2637 --- src/core/load-fragment.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b31bf83f47..4a65d174b8 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -574,9 +574,7 @@ int config_parse_exec( void *data, void *userdata) { - _cleanup_free_ char *cmd = NULL; ExecCommand **e = data; - Unit *u = userdata; const char *p; bool semicolon; int r; @@ -585,7 +583,6 @@ int config_parse_exec( assert(lvalue); assert(rvalue); assert(e); - assert(u); e += ltype; rvalue += strspn(rvalue, WHITESPACE); @@ -596,13 +593,7 @@ int config_parse_exec( return 0; } - r = unit_full_printf(u, rvalue, &cmd); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); - return 0; - } - - p = cmd; + p = rvalue; do { _cleanup_free_ char *path = NULL, *firstword = NULL; bool separate_argv0 = false, ignore = false; -- cgit v1.2.3-54-g00ecf From 82d1d24093e2f17cc6550e8f16be85fa4376c182 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 17 Feb 2016 21:08:57 -0500 Subject: systemd-resolve: easy querying of TLSA records $ systemd-resolve --tlsa fedoraproject.org _443._tcp.fedoraproject.org IN TLSA 0 0 1 GUAL5bejH7czkXcAeJ0vCiRxwMnVBsDlBMBsFtfLF8A= -- Cert. usage: CA constraint -- Selector: Full Certificate -- Matching type: SHA-256 $ systemd-resolve --tlsa=tcp fedoraproject.org:443 _443._tcp.fedoraproject.org IN TLSA 0 0 1 GUAL5bejH7czkXcAeJ0vCiRxwMnVBsDlBMBsFtfLF8A= ... $ systemd-resolve --tlsa=udp fedoraproject.org _443._udp.fedoraproject.org: resolve call failed: '_443._udp.fedoraproject.org' not found v2: - use uint16_t - refuse port 0 --- man/systemd-resolve.xml | 40 ++++++++++++++++++- src/resolve/resolve-tool.c | 97 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 134 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index c288fd974e..320663ce69 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -83,6 +83,13 @@ USER@DOMAIN + + systemd-resolve + OPTIONS + --tlsa + DOMAIN:PORT + + systemd-resolve OPTIONS @@ -121,10 +128,15 @@ is assumed to be a domain name, that is already prefixed with an SRV type, and an SRV lookup is done (no TXT). - The switch may be use to query PGP keys stored as the + The switch may be used to query PGP keys stored as OPENPGPKEY resource records. When this option is specified one or more e-mail address must be specified. + The switch maybe be used to query TLS public + keys stored as + TLSA resource records. + When this option is specified one or more domain names must be specified. + The switch may be used to show resolver statistics, including information about the number of successful and failed DNSSEC validations. @@ -216,6 +228,20 @@ printed. + + + + Enables TLSA resource record resolution (see above). + A query will be performed for each of the specified names prefixed with + the port and family + (_port._family.domain). + The port number may be specified after a colon + (:), otherwise 443 will be used + by default. The family may be specified as an argument after + , otherwise tcp will be + used. + + BOOL @@ -323,6 +349,18 @@ d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproje mQINBFBHPMsBEACeInGYJCb+7TurKfb6wGyTottCDtiSJB310i37/6ZYoeIay/5soJjlMyf MFQ9T2XNT/0LM6gTa0MpC1st9LnzYTMsT6tzRly1D1UbVI6xw0g0vE5y2Cjk3xUwAynCsSs ... + + + + + Retrieve a TLS key (<literal>=tcp</literal> and + <literal>:443</literal> could be skipped) + + $ systemd-resolve --tlsa=tcp fedoraproject.org:443 +_443._tcp.fedoraproject.org IN TLSA 0 0 1 GUAL5bejH7czkXcAeJ0vCiRxwMnVBsDlBMBsFtfLF8A= + -- Cert. usage: CA constraint + -- Selector: Full Certificate + -- Matching type: SHA-256 diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index a519074278..484fbb4d92 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -44,12 +44,19 @@ static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; +typedef enum ServiceFamily { + SERVICE_FAMILY_TCP, + SERVICE_FAMILY_UDP, + SERVICE_FAMILY_SCTP, + _SERVICE_FAMILY_INVALID = -1, +} ServiceFamily; +static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP; + typedef enum RawType { RAW_NONE, RAW_PAYLOAD, RAW_PACKET, } RawType; - static RawType arg_raw = RAW_NONE; static enum { @@ -57,10 +64,34 @@ static enum { MODE_RESOLVE_RECORD, MODE_RESOLVE_SERVICE, MODE_RESOLVE_OPENPGP, + MODE_RESOLVE_TLSA, MODE_STATISTICS, MODE_RESET_STATISTICS, } arg_mode = MODE_RESOLVE_HOST; +static ServiceFamily service_family_from_string(const char *s) { + if (s == NULL || streq(s, "tcp")) + return SERVICE_FAMILY_TCP; + if (streq(s, "udp")) + return SERVICE_FAMILY_UDP; + if (streq(s, "sctp")) + return SERVICE_FAMILY_SCTP; + return _SERVICE_FAMILY_INVALID; +} + +static const char* service_family_to_string(ServiceFamily service) { + switch(service) { + case SERVICE_FAMILY_TCP: + return "_tcp"; + case SERVICE_FAMILY_UDP: + return "_udp"; + case SERVICE_FAMILY_SCTP: + return "_sctp"; + default: + assert_not_reached("invalid service"); + } +} + static void print_source(uint64_t flags, usec_t rtt) { char rtt_str[FORMAT_TIMESTAMP_MAX]; @@ -844,6 +875,38 @@ static int resolve_openpgp(sd_bus *bus, const char *address) { arg_type ?: DNS_TYPE_OPENPGPKEY); } +static int resolve_tlsa(sd_bus *bus, const char *address) { + const char *port; + uint16_t port_num = 443; + _cleanup_free_ char *full = NULL; + int r; + + assert(bus); + assert(address); + + port = strrchr(address, ':'); + if (port) { + r = safe_atou16(port + 1, &port_num); + if (r < 0 || port_num == 0) + return log_error_errno(r, "Invalid port \"%s\".", port + 1); + + address = strndupa(address, port - address); + } + + r = asprintf(&full, "_%u.%s.%s", + port_num, + service_family_to_string(arg_service_family), + address); + if (r < 0) + return log_oom(); + + log_debug("Looking up \"%s\".", full); + + return resolve_record(bus, full, + arg_class ?: DNS_CLASS_IN, + arg_type ?: DNS_TYPE_TLSA); +} + static int show_statistics(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -1031,6 +1094,7 @@ static void help(void) { " --service-address=BOOL Resolve address for services (default: yes)\n" " --service-txt=BOOL Resolve TXT records for services (default: yes)\n" " --openpgp Query OpenPGP public key\n" + " --tlsa Query TLS public key\n" " --cname=BOOL Follow CNAME redirects (default: yes)\n" " --search=BOOL Use search domains for single-label names\n" " (default: yes)\n" @@ -1050,6 +1114,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SERVICE_ADDRESS, ARG_SERVICE_TXT, ARG_OPENPGP, + ARG_TLSA, ARG_RAW, ARG_SEARCH, ARG_STATISTICS, @@ -1069,6 +1134,7 @@ static int parse_argv(int argc, char *argv[]) { { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, { "openpgp", no_argument, NULL, ARG_OPENPGP }, + { "tlsa", optional_argument, NULL, ARG_TLSA }, { "raw", optional_argument, NULL, ARG_RAW }, { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, @@ -1183,6 +1249,15 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESOLVE_OPENPGP; break; + case ARG_TLSA: + arg_mode = MODE_RESOLVE_TLSA; + arg_service_family = service_family_from_string(optarg); + if (arg_service_family < 0) { + log_error("Unknown service family \"%s\".", optarg); + return -EINVAL; + } + break; + case ARG_RAW: if (on_tty()) { log_error("Refusing to write binary data to tty."); @@ -1261,7 +1336,7 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) { + if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) { log_error("--service and --type= may not be combined."); return -EINVAL; } @@ -1378,6 +1453,24 @@ int main(int argc, char **argv) { } break; + case MODE_RESOLVE_TLSA: + if (argc < optind + 1) { + log_error("Domain name required."); + r = -EINVAL; + goto finish; + + } + + r = 0; + while (optind < argc) { + int k; + + k = resolve_tlsa(bus, argv[optind++]); + if (k < 0) + r = k; + } + break; + case MODE_STATISTICS: if (argc > optind) { log_error("Too many arguments."); -- cgit v1.2.3-54-g00ecf From 236d312b8d0392f490aa7f09886942c17a06f12e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 16 Feb 2016 20:36:10 -0500 Subject: resolve: print TLSA packets in hexadecimal https://tools.ietf.org/html/rfc6698#section-2.2 says: > The certificate association data field MUST be represented as a string > of hexadecimal characters. Whitespace is allowed within the string of > hexadecimal characters --- man/systemd-resolve.xml | 2 +- src/resolve/resolved-dns-rr.c | 28 +++++++++------------------- 2 files changed, 10 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index 320663ce69..de3bbce6dd 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -357,7 +357,7 @@ d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproje :443 could be skipped) $ systemd-resolve --tlsa=tcp fedoraproject.org:443 -_443._tcp.fedoraproject.org IN TLSA 0 0 1 GUAL5bejH7czkXcAeJ0vCiRxwMnVBsDlBMBsFtfLF8A= +_443._tcp.fedoraproject.org IN TLSA 0 0 1 19400be5b7a31fb733917700789d2f0a2471c0c9d506c0e504c06c16d7cb17c0 -- Cert. usage: CA constraint -- Selector: Full Certificate -- Matching type: SHA-256 diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index d0a86ef206..e83416da07 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1116,40 +1116,30 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { case DNS_TYPE_TLSA: { const char *cert_usage, *selector, *matching_type; - char *ss; - int n; cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage); selector = tlsa_selector_to_string(rr->tlsa.selector); matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type); - r = asprintf(&s, "%s %u %u %u %n", - k, - rr->tlsa.cert_usage, - rr->tlsa.selector, - rr->tlsa.matching_type, - &n); - if (r < 0) - return NULL; - - r = base64_append(&s, n, - rr->tlsa.data, rr->tlsa.data_size, - 8, columns()); - if (r < 0) + t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); + if (!t) return NULL; - r = asprintf(&ss, "%s\n" + r = asprintf(&s, + "%s %u %u %u %s\n" " -- Cert. usage: %s\n" " -- Selector: %s\n" " -- Matching type: %s", - s, + k, + rr->tlsa.cert_usage, + rr->tlsa.selector, + rr->tlsa.matching_type, + t, cert_usage, selector, matching_type); if (r < 0) return NULL; - free(s); - s = ss; break; } -- cgit v1.2.3-54-g00ecf From e1caa6e09b9698d629dc6a7a166e12ea8752aedd Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 16 Feb 2016 20:55:23 -0500 Subject: resolve: also allow SSHFP payload to be exported --- src/resolve/resolved-dns-rr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index e83416da07..6a29a93a26 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1218,13 +1218,16 @@ ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) { case DNS_TYPE_MX: case DNS_TYPE_LOC: case DNS_TYPE_DS: - case DNS_TYPE_SSHFP: case DNS_TYPE_DNSKEY: case DNS_TYPE_RRSIG: case DNS_TYPE_NSEC: case DNS_TYPE_NSEC3: return -EINVAL; + case DNS_TYPE_SSHFP: + *out = rr->sshfp.fingerprint; + return rr->sshfp.fingerprint_size; + case DNS_TYPE_TLSA: *out = rr->tlsa.data; return rr->tlsa.data_size; -- cgit v1.2.3-54-g00ecf From dbacacaaeac47f792fb33ead7f8946689219ef2c Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 16 Feb 2016 23:51:43 +0600 Subject: alloc-util: cleanups This patch contains a set of little cleanups for alloc-util.h: 1. The malloc_multiply(), realloc_multiply() and memdup_multiply() functions check allocation related parameters on overflow. Let's move them to the separate size_multiply_overflow() function for simplicity, code duplication prevention and possible reuse in future. 2. use SIZE_MAX from stdlib instead of ((size_t) - 1) to be more clear. 3. The 'a'/'b' variables are renamed to 'size' and 'need' to be more clear.' --- src/basic/alloc-util.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index 679ba7f398..ceeee519b7 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -51,25 +51,29 @@ static inline void freep(void *p) { #define _cleanup_free_ _cleanup_(freep) -_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) +static inline bool size_multiply_overflow(size_t size, size_t need) { + return _unlikely_(need != 0 && size > (SIZE_MAX / need)); +} + +_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { + if (size_multiply_overflow(size, need)) return NULL; - return malloc(a * b); + return malloc(size * need); } -_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) +_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t size, size_t need) { + if (size_multiply_overflow(size, need)) return NULL; - return realloc(p, a * b); + return realloc(p, size * need); } -_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) +_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { + if (size_multiply_overflow(size, need)) return NULL; - return memdup(p, a * b); + return memdup(p, size * need); } void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); -- cgit v1.2.3-54-g00ecf From e306723ec4290f8cd0fa08caf12bdc28afda5ed9 Mon Sep 17 00:00:00 2001 From: Nathan McSween Date: Thu, 18 Feb 2016 23:34:30 +0000 Subject: Remove/add (un)needed includes --- src/basic/hostname-util.c | 1 - src/libsystemd-network/lldp-network.c | 2 +- src/machine/machine-dbus.c | 1 + src/network/networkd-netdev-tuntap.c | 1 + src/shared/machine-image.c | 1 + src/shared/machine-pool.c | 1 + src/udev/net/link-config.c | 1 - 7 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 7bb23448ed..57031b645c 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -17,7 +17,6 @@ along with systemd; If not, see . ***/ -#include #include #include #include diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 42058c4449..7c865b46cb 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -19,7 +19,7 @@ ***/ #include -#include +#include #include "fd-util.h" #include "lldp-internal.h" diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 71f20b3f07..c5bbf2fbde 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -20,6 +20,7 @@ #include #include #include +#include /* When we include libgen.h because we need dirname() we immediately * undefine basename() since libgen.h defines it as a macro to the POSIX diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index ab9a1b0426..cdf443862d 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "alloc-util.h" #include "fd-util.h" diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index ed8a29c575..d2f1c4a40c 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index e5674e4137..f080b849a4 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 15145fc5eb..c66504102f 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -18,7 +18,6 @@ ***/ #include -#include #include "sd-netlink.h" -- cgit v1.2.3-54-g00ecf From 3a43755733292fde399548248a5ba158d9df27ac Mon Sep 17 00:00:00 2001 From: Nathan McSween Date: Thu, 18 Feb 2016 23:35:22 +0000 Subject: Don't use internal struct member names --- src/network/networkd-ndisc.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index f2287be20a..3e8932e160 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "sd-ndisc.h" @@ -76,15 +77,15 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8); else { /* see RFC4291 section 2.5.1 */ - address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0]; - address->in_addr.in6.__in6_u.__u6_addr8[8] ^= 1 << 1; - address->in_addr.in6.__in6_u.__u6_addr8[9] = link->mac.ether_addr_octet[1]; - address->in_addr.in6.__in6_u.__u6_addr8[10] = link->mac.ether_addr_octet[2]; - address->in_addr.in6.__in6_u.__u6_addr8[11] = 0xff; - address->in_addr.in6.__in6_u.__u6_addr8[12] = 0xfe; - address->in_addr.in6.__in6_u.__u6_addr8[13] = link->mac.ether_addr_octet[3]; - address->in_addr.in6.__in6_u.__u6_addr8[14] = link->mac.ether_addr_octet[4]; - address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5]; + address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0]; + address->in_addr.in6.s6_addr[8] ^= 1 << 1; + address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1]; + address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2]; + address->in_addr.in6.s6_addr[11] = 0xff; + address->in_addr.in6.s6_addr[12] = 0xfe; + address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3]; + address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4]; + address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5]; } address->prefixlen = prefixlen; address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR; -- cgit v1.2.3-54-g00ecf From 82501b3fc40dae2660a86ab07462f33fe26347ad Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 18 Feb 2016 17:33:10 -0500 Subject: basic/strbuf: do not call bsearch with a null argument Das ist verboten! src/basic/strbuf.c:162:23: runtime error: null pointer passed as argument 2, which is declared to never be null --- src/basic/strbuf.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index 77220c0251..dac2881603 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -156,6 +156,10 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { return off; } + /* bsearch is not allowed on a NULL sequence */ + if (node->children_count == 0) + break; + /* lookup child node */ c = s[len - 1 - depth]; search.c = c; -- cgit v1.2.3-54-g00ecf From 06466a7f039240b4c75cd5920401a7699c263d6e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 18 Feb 2016 17:37:17 -0500 Subject: journal/catalog: fix memory leaks Various buffers were lost because finish_item() either consumed the buffer or allocated a new one (if an entry with the same key existed). The caller would simply forget the buffer in either case. Also add a check for the case when a valid identifier is followed by an empty body. We should not allow this. Also be more consistent in error handling and always print an error message. --- src/journal/catalog.c | 81 +++++++++++++++++++++++----------------------- src/journal/test-catalog.c | 2 ++ 2 files changed, 43 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/journal/catalog.c b/src/journal/catalog.c index 164a3a15f2..72c2da10f1 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -164,14 +164,14 @@ static int finish_item( Hashmap *h, sd_id128_t id, const char *language, - char *payload) { + char *payload, size_t payload_size) { _cleanup_free_ CatalogItem *i = NULL; - _cleanup_free_ char *combined = NULL, *prev = NULL; - int r; + _cleanup_free_ char *prev = NULL, *combined = NULL; assert(h); assert(payload); + assert(payload_size > 0); i = new0(CatalogItem, 1); if (!i) @@ -184,23 +184,25 @@ static int finish_item( } prev = hashmap_get(h, i); - - /* Already have such an item, combine them */ if (prev) { + /* Already have such an item, combine them */ combined = combine_entries(payload, prev); if (!combined) return log_oom(); - r = hashmap_update(h, i, combined); - if (r < 0) - return r; - combined = NULL; - /* A new item */ + if (hashmap_update(h, i, combined) < 0) + return log_oom(); + combined = NULL; } else { - r = hashmap_put(h, i, payload); - if (r < 0) - return r; + /* A new item */ + combined = memdup(payload, payload_size + 1); + if (!combined) + return log_oom(); + + if (hashmap_put(h, i, combined) < 0) + return log_oom(); i = NULL; + combined = NULL; } return 0; @@ -262,6 +264,7 @@ static int catalog_entry_lang(const char* filename, int line, int catalog_import_file(Hashmap *h, const char *path) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *payload = NULL; + size_t payload_size = 0, payload_allocated = 0; unsigned n = 0; sd_id128_t id; _cleanup_free_ char *deflang = NULL, *lang = NULL; @@ -283,8 +286,7 @@ int catalog_import_file(Hashmap *h, const char *path) { for (;;) { char line[LINE_MAX]; - size_t a, b, c; - char *t; + size_t line_len; if (!fgets(line, sizeof(line), f)) { if (feof(f)) @@ -323,17 +325,23 @@ int catalog_import_file(Hashmap *h, const char *path) { if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) { if (got_id) { - r = finish_item(h, id, lang ?: deflang, payload); + if (payload_size == 0) { + log_error("[%s:%u] No payload text.", path, n); + return -EINVAL; + } + + r = finish_item(h, id, lang ?: deflang, payload, payload_size); if (r < 0) return r; - payload = NULL; lang = mfree(lang); + payload_size = 0; } if (with_language) { - t = strstrip(line + 2 + 1 + 32 + 1); + char *t; + t = strstrip(line + 2 + 1 + 32 + 1); r = catalog_entry_lang(path, n, t, deflang, &lang); if (r < 0) return r; @@ -343,9 +351,6 @@ int catalog_import_file(Hashmap *h, const char *path) { empty_line = false; id = jd; - if (payload) - payload[0] = '\0'; - continue; } } @@ -356,34 +361,30 @@ int catalog_import_file(Hashmap *h, const char *path) { return -EINVAL; } - a = payload ? strlen(payload) : 0; - b = strlen(line); - - c = a + (empty_line ? 1 : 0) + b + 1 + 1; - t = realloc(payload, c); - if (!t) + line_len = strlen(line); + if (!GREEDY_REALLOC(payload, payload_allocated, + payload_size + (empty_line ? 1 : 0) + line_len + 1 + 1)) return log_oom(); - if (empty_line) { - t[a] = '\n'; - memcpy(t + a + 1, line, b); - t[a+b+1] = '\n'; - t[a+b+2] = 0; - } else { - memcpy(t + a, line, b); - t[a+b] = '\n'; - t[a+b+1] = 0; - } + if (empty_line) + payload[payload_size++] = '\n'; + memcpy(payload + payload_size, line, line_len); + payload_size += line_len; + payload[payload_size++] = '\n'; + payload[payload_size] = '\0'; - payload = t; empty_line = false; } if (got_id) { - r = finish_item(h, id, lang ?: deflang, payload); + if (payload_size == 0) { + log_error("[%s:%u] No payload text.", path, n); + return -EINVAL; + } + + r = finish_item(h, id, lang ?: deflang, payload, payload_size); if (r < 0) return r; - payload = NULL; } return 0; diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c index da6fcbca4d..898c876450 100644 --- a/src/journal/test-catalog.c +++ b/src/journal/test-catalog.c @@ -103,6 +103,8 @@ static void test_catalog_import_one(void) { assert_se(hashmap_size(h) == 1); HASHMAP_FOREACH(payload, h, j) { + printf("expect: %s\n", expect); + printf("actual: %s\n", payload); assert_se(streq(expect, payload)); } } -- cgit v1.2.3-54-g00ecf From d09139e1879960bd2ed81466d2f13d6cf35d0a5b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 18 Feb 2016 18:59:27 -0500 Subject: test-hashmap: fix undefined behaviour on string constants The test was failing at -O2+ with gcc 5.3 and 6.0. "val1" == "val1" and "val1" != "val1" are both valid. http://stackoverflow.com/questions/4843640/why-is-a-a-in-c --- src/test/test-hashmap-plain.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index 6bf33306a9..1bd5c02f87 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -323,26 +323,29 @@ static void test_hashmap_remove_value(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; char *r; - r = hashmap_remove_value(NULL, "key 1", (void*) "val 1"); + char val1[] = "val 1"; + char val2[] = "val 2"; + + r = hashmap_remove_value(NULL, "key 1", val1); assert_se(r == NULL); m = hashmap_new(&string_hash_ops); assert_se(m); - r = hashmap_remove_value(m, "key 1", (void*) "val 1"); + r = hashmap_remove_value(m, "key 1", val1); assert_se(r == NULL); - hashmap_put(m, "key 1", (void*) "val 1"); - hashmap_put(m, "key 2", (void*) "val 2"); + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); - r = hashmap_remove_value(m, "key 1", (void*) "val 1"); + r = hashmap_remove_value(m, "key 1", val1); assert_se(streq(r, "val 1")); r = hashmap_get(m, "key 2"); assert_se(streq(r, "val 2")); assert_se(!hashmap_get(m, "key 1")); - r = hashmap_remove_value(m, "key 2", (void*) "val 1"); + r = hashmap_remove_value(m, "key 2", val1); assert_se(r == NULL); r = hashmap_get(m, "key 2"); -- cgit v1.2.3-54-g00ecf From 240a7ba9d8eaf76e1f3fb7a5b8424ab6eaead59d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 16 Feb 2016 13:15:34 -0500 Subject: time-util: rewrite check in a way that does not confuse gcc gcc thinks that multiplier might be unitialized. Split out the inner loop to make the function easier to grok. --- src/basic/time-util.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 0b4f5ab5b9..130acaa9de 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -705,8 +705,7 @@ finish: return 0; } -int parse_time(const char *t, usec_t *usec, usec_t default_unit) { - +static char* extract_multiplier(char *p, usec_t *multiplier) { static const struct { const char *suffix; usec_t usec; @@ -740,7 +739,22 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { { "usec", 1ULL }, { "us", 1ULL }, }; + unsigned i; + + for (i = 0; i < ELEMENTSOF(table); i++) { + char *e; + e = startswith(p, table[i].suffix); + if (e) { + *multiplier = table[i].usec; + return e; + } + } + + return p; +} + +int parse_time(const char *t, usec_t *usec, usec_t default_unit) { const char *p, *s; usec_t r = 0; bool something = false; @@ -765,8 +779,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { for (;;) { long long l, z = 0; char *e; - unsigned i, n = 0; - usec_t multiplier, k; + unsigned n = 0; + usec_t multiplier = default_unit, k; p += strspn(p, WHITESPACE); @@ -779,10 +793,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { errno = 0; l = strtoll(p, &e, 10); - if (errno > 0) return -errno; - if (l < 0) return -ERANGE; @@ -806,18 +818,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { return -EINVAL; e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - multiplier = table[i].usec; - p = e + strlen(table[i].suffix); - break; - } - - if (i >= ELEMENTSOF(table)) { - multiplier = default_unit; - p = e; - } + p = extract_multiplier(e, &multiplier); something = true; -- cgit v1.2.3-54-g00ecf From b722348d050aa2754cd9f903e8c3ce810c616b06 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 18 Feb 2016 21:54:31 -0500 Subject: activate: fix -E option parsing Fixes #2658. --- src/activate/activate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/activate/activate.c b/src/activate/activate.c index 23244fdc62..d6e2d07ff2 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -385,7 +385,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hl:aEd", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0) switch(c) { case 'h': help(); -- cgit v1.2.3-54-g00ecf From 18665d1f67a9c93219b7007ad044f94eaaedecc1 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 19 Feb 2016 07:27:43 -0500 Subject: resolved: fix NULL dereference in debug stmt CID #1351544, #1351545. --- src/resolve/resolved-dns-cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 4b7672fbbf..fb957db9ef 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -402,7 +402,7 @@ static int dns_cache_put_positive( k = dns_cache_remove_by_rr(c, rr); log_debug("%s: %s", k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry", - dns_resource_key_to_string(i->key, key_str, sizeof key_str)); + dns_resource_key_to_string(rr->key, key_str, sizeof key_str)); return 0; } @@ -497,7 +497,7 @@ static int dns_cache_put_negative( if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) { log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s", - dns_resource_key_to_string(i->key, key_str, sizeof key_str)); + dns_resource_key_to_string(key, key_str, sizeof key_str)); return 0; } -- cgit v1.2.3-54-g00ecf From 79d629725240a3fc5a4684bd42aefc7d87197c5c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 19 Feb 2016 07:35:35 -0500 Subject: Use (void) to silenc coverity on proc title changes This is a cosmetic best-effort thing anyway. --- src/basic/process-util.c | 2 +- src/libsystemd/sd-resolve/sd-resolve.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 189ef9ab60..27663eee51 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -205,7 +205,7 @@ void rename_process(const char name[8]) { * "systemd"). If you pass a longer string it will be * truncated */ - prctl(PR_SET_NAME, name); + (void) prctl(PR_SET_NAME, name); if (program_invocation_name) strncpy(program_invocation_name, name, strlen(program_invocation_name)); diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index de17a6112e..d693b2c2b0 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -403,7 +403,7 @@ static void* thread_worker(void *p) { assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0); /* Assign a pretty name to this thread */ - prctl(PR_SET_NAME, (unsigned long) "sd-resolve"); + (void) prctl(PR_SET_NAME, (unsigned long) "sd-resolve"); while (!resolve->dead) { union { -- cgit v1.2.3-54-g00ecf From 5181ab917d6407cb57043e98955f0de1614366ea Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Fri, 19 Feb 2016 15:21:18 +0100 Subject: udev/path_id: correct segmentation fault due to missing NULL check Running "udevadm test-builtin path_id /sys/devices/platform/" results in a segmentation fault. The problem is that udev_device_get_subsystem(dev) might return NULL in a streq() call. Solve this problem by using streq_ptr() instead. --- src/udev/udev-builtin-path_id.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index b6ed45d8ba..6e9adc6e96 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -712,7 +712,7 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool * devices do not expose their buses and do not provide a unique * and predictable name that way. */ - if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport) + if (streq_ptr(udev_device_get_subsystem(dev), "block") && !supported_transport) path = mfree(path); if (path != NULL) { -- cgit v1.2.3-54-g00ecf From fb42603752444ad7a8b4e29a6e264cab7e219e9c Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Fri, 19 Feb 2016 16:36:27 -0800 Subject: journal: add void cast to fsync() calls --- src/journal/journal-file.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 994d1ec5d8..ccb689451e 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -104,7 +104,7 @@ static int journal_file_set_online(JournalFile *f) { case STATE_OFFLINE: f->header->state = STATE_ONLINE; - fsync(f->fd); + (void) fsync(f->fd); return 0; default: @@ -124,7 +124,7 @@ int journal_file_set_offline(JournalFile *f) { if (f->header->state != STATE_ONLINE) return 0; - fsync(f->fd); + (void) fsync(f->fd); if (mmap_cache_got_sigbus(f->mmap, f->fd)) return -EIO; @@ -134,7 +134,7 @@ int journal_file_set_offline(JournalFile *f) { if (mmap_cache_got_sigbus(f->mmap, f->fd)) return -EIO; - fsync(f->fd); + (void) fsync(f->fd); return 0; } @@ -263,7 +263,7 @@ static int journal_file_refresh_header(JournalFile *f) { r = journal_file_set_online(f); /* Sync the online state to disk */ - fsync(f->fd); + (void) fsync(f->fd); return r; } -- cgit v1.2.3-54-g00ecf From 69a3a6fd3d96101d42a01d0e7d33ae2ef613e54a Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Fri, 19 Feb 2016 16:51:41 -0800 Subject: journal: add void cast to journal_file_close() calls --- src/journal/journal-file.c | 2 +- src/journal/journald-server.c | 12 ++++++------ src/journal/sd-journal.c | 6 +++--- src/journal/test-journal-flush.c | 2 +- src/journal/test-journal-interleaving.c | 2 +- src/journal/test-journal-stream.c | 6 +++--- src/journal/test-journal-verify.c | 6 +++--- src/journal/test-journal.c | 10 +++++----- 8 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index ccb689451e..52110aa498 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -2898,7 +2898,7 @@ fail: if (f->fd >= 0 && mmap_cache_got_sigbus(f->mmap, f->fd)) r = -EIO; - journal_file_close(f); + (void) journal_file_close(f); return r; } diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index ee2db8d29f..5e120fdac0 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -259,7 +259,7 @@ static int open_journal( r = journal_file_enable_post_change_timer(f, s->event, POST_CHANGE_TIMER_INTERVAL_USEC); if (r < 0) { - journal_file_close(f); + (void) journal_file_close(f); return r; } @@ -302,7 +302,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { /* Too many open? Then let's close one */ f = ordered_hashmap_steal_first(s->user_journals); assert(f); - journal_file_close(f); + (void) journal_file_close(f); } r = open_journal(s, true, p, O_RDWR|O_CREAT, s->seal, &s->system_metrics, &f); @@ -313,7 +313,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f); if (r < 0) { - journal_file_close(f); + (void) journal_file_close(f); return s->system_journal; } @@ -1922,13 +1922,13 @@ void server_done(Server *s) { stdout_stream_free(s->stdout_streams); if (s->system_journal) - journal_file_close(s->system_journal); + (void) journal_file_close(s->system_journal); if (s->runtime_journal) - journal_file_close(s->runtime_journal); + (void) journal_file_close(s->runtime_journal); while ((f = ordered_hashmap_steal_first(s->user_journals))) - journal_file_close(f); + (void) journal_file_close(f); ordered_hashmap_free(s->user_journals); diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 5a2a28a8d4..9bc4215f2e 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1258,7 +1258,7 @@ static int add_any_file(sd_journal *j, const char *path) { r = ordered_hashmap_put(j->files, f->path, f); if (r < 0) { - journal_file_close(f); + (void) journal_file_close(f); goto fail; } @@ -1343,7 +1343,7 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { j->fields_file_lost = true; } - journal_file_close(f); + (void) journal_file_close(f); j->current_invalidate_counter ++; } @@ -1784,7 +1784,7 @@ _public_ void sd_journal_close(sd_journal *j) { sd_journal_flush_matches(j); while ((f = ordered_hashmap_steal_first(j->files))) - journal_file_close(f); + (void) journal_file_close(f); ordered_hashmap_free(j->files); diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c index 7bd9c40366..0c35d532c6 100644 --- a/src/journal/test-journal-flush.c +++ b/src/journal/test-journal-flush.c @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) { sd_journal_close(j); - journal_file_close(new_journal); + (void) journal_file_close(new_journal); unlink(fn); assert_se(rmdir(dn) == 0); diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 7f94990888..6c6238cc4b 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -57,7 +57,7 @@ static JournalFile *test_open(const char *name) { } static void test_close(JournalFile *f) { - journal_file_close (f); + (void) journal_file_close (f); } static void append_number(JournalFile *f, int n, uint64_t *seqnum) { diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index 4e6f8c0f7b..82543bb5f9 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -133,9 +133,9 @@ int main(int argc, char *argv[]) { free(q); } - journal_file_close(one); - journal_file_close(two); - journal_file_close(three); + (void) journal_file_close(one); + (void) journal_file_close(two); + (void) journal_file_close(three); assert_se(sd_journal_open_directory(&j, t, 0) >= 0); diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index a26c624f41..3fec18c480 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -60,7 +60,7 @@ static int raw_verify(const char *fn, const char *verification_key) { return r; r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false); - journal_file_close(f); + (void) journal_file_close(f); return r; } @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) { free(test); } - journal_file_close(f); + (void) journal_file_close(f); log_info("Verifying..."); @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) { format_timestamp(b, sizeof(b), to), format_timespan(c, sizeof(c), total > to ? total - to : 0, 0)); - journal_file_close(f); + (void) journal_file_close(f); if (verification_key) { log_info("Toggling bits..."); diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 0334b1cd1a..94d26a2573 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -107,7 +107,7 @@ static void test_non_empty(void) { journal_file_rotate(&f, true, true); journal_file_rotate(&f, true, true); - journal_file_close(f); + (void) journal_file_close(f); log_info("Done..."); @@ -158,10 +158,10 @@ static void test_empty(void) { assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } - journal_file_close(f1); - journal_file_close(f2); - journal_file_close(f3); - journal_file_close(f4); + (void) journal_file_close(f1); + (void) journal_file_close(f2); + (void) journal_file_close(f3); + (void) journal_file_close(f4); } int main(int argc, char *argv[]) { -- cgit v1.2.3-54-g00ecf From ac2e41f5103ce2c679089c4f8fb6be61d7caec07 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Fri, 12 Feb 2016 04:59:57 -0800 Subject: journal: asynchronous journal_file_set_offline() This adds a wait flag to journal_file_set_offline(), when false the offline is performed asynchronously in a separate thread. When wait is true, if an asynchronous offline is already in-progress it is restarted and waited for. Otherwise the offline is performed synchronously without the use of a thread. journal_file_set_online() cancels or waits for the asynchronous offline to complete if in-flight, depending on where in the offline process the thread happens to be. If the thread is in the fsync() phase, it is cancelled and waiting is unnecessary. Otherwise, the thread is joined before proceeding. A new offline_state member is added to JournalFile which is used via atomic operations for communicating between the offline thread and the journal_file_set_{offline,online}() functions. --- src/journal/journal-file.c | 213 +++++++++++++++++++++++++++++++++++++----- src/journal/journal-file.h | 15 ++- src/journal/journald-server.c | 4 +- 3 files changed, 208 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 52110aa498..96be339d5b 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -86,33 +87,127 @@ /* The mmap context to use for the header we pick as one above the last defined typed */ #define CONTEXT_HEADER _OBJECT_TYPE_MAX -static int journal_file_set_online(JournalFile *f) { +/* This may be called from a separate thread to prevent blocking the caller for the duration of fsync(). + * As a result we use atomic operations on f->offline_state for inter-thread communications with + * journal_file_set_offline() and journal_file_set_online(). */ +static void journal_file_set_offline_internal(JournalFile *f) { assert(f); + assert(f->fd >= 0); + assert(f->header); - if (!f->writable) - return -EPERM; + for (;;) { + switch (f->offline_state) { + case OFFLINE_CANCEL: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_CANCEL, OFFLINE_DONE)) + continue; + return; - if (!(f->fd >= 0 && f->header)) - return -EINVAL; + case OFFLINE_AGAIN_FROM_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_SYNCING, OFFLINE_SYNCING)) + continue; + break; + + case OFFLINE_AGAIN_FROM_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_OFFLINING, OFFLINE_SYNCING)) + continue; + break; + + case OFFLINE_SYNCING: + (void) fsync(f->fd); + + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_OFFLINING)) + continue; + + f->header->state = STATE_OFFLINE; + (void) fsync(f->fd); + break; + + case OFFLINE_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_OFFLINING, OFFLINE_DONE)) + continue; + /* fall through */ + + case OFFLINE_DONE: + return; + + case OFFLINE_JOINED: + log_debug("OFFLINE_JOINED unexpected offline state for journal_file_set_offline_internal()"); + return; + } + } +} + +static void * journal_file_set_offline_thread(void *arg) { + JournalFile *f = arg; + + journal_file_set_offline_internal(f); + + return NULL; +} + +static int journal_file_set_offline_thread_join(JournalFile *f) { + int r; + + assert(f); + + if (f->offline_state == OFFLINE_JOINED) + return 0; + + r = pthread_join(f->offline_thread, NULL); + if (r) + return -r; + + f->offline_state = OFFLINE_JOINED; if (mmap_cache_got_sigbus(f->mmap, f->fd)) return -EIO; - switch (f->header->state) { - case STATE_ONLINE: - return 0; + return 0; +} - case STATE_OFFLINE: - f->header->state = STATE_ONLINE; - (void) fsync(f->fd); - return 0; +/* Trigger a restart if the offline thread is mid-flight in a restartable state. */ +static bool journal_file_set_offline_try_restart(JournalFile *f) { + for (;;) { + switch (f->offline_state) { + case OFFLINE_AGAIN_FROM_SYNCING: + case OFFLINE_AGAIN_FROM_OFFLINING: + return true; + + case OFFLINE_CANCEL: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_CANCEL, OFFLINE_AGAIN_FROM_SYNCING)) + continue; + return true; + + case OFFLINE_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_AGAIN_FROM_SYNCING)) + continue; + return true; + + case OFFLINE_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_OFFLINING, OFFLINE_AGAIN_FROM_OFFLINING)) + continue; + return true; default: - return -EINVAL; + return false; + } } } -int journal_file_set_offline(JournalFile *f) { +/* Sets a journal offline. + * + * If wait is false then an offline is dispatched in a separate thread for a + * subsequent journal_file_set_offline() or journal_file_set_online() of the + * same journal to synchronize with. + * + * If wait is true, then either an existing offline thread will be restarted + * and joined, or if none exists the offline is simply performed in this + * context without involving another thread. + */ +int journal_file_set_offline(JournalFile *f, bool wait) { + bool restarted; + int r; + assert(f); if (!f->writable) @@ -124,19 +219,95 @@ int journal_file_set_offline(JournalFile *f) { if (f->header->state != STATE_ONLINE) return 0; - (void) fsync(f->fd); + /* Restart an in-flight offline thread and wait if needed, or join a lingering done one. */ + restarted = journal_file_set_offline_try_restart(f); + if ((restarted && wait) || !restarted) { + r = journal_file_set_offline_thread_join(f); + if (r < 0) + return r; + } - if (mmap_cache_got_sigbus(f->mmap, f->fd)) - return -EIO; + if (restarted) + return 0; + + /* Initiate a new offline. */ + f->offline_state = OFFLINE_SYNCING; + + if (wait) /* Without using a thread if waiting. */ + journal_file_set_offline_internal(f); + else { + r = pthread_create(&f->offline_thread, NULL, journal_file_set_offline_thread, f); + if (r > 0) + return -r; + } + + return 0; +} + +static int journal_file_set_online(JournalFile *f) { + bool joined = false; + + assert(f); + + if (!f->writable) + return -EPERM; + + if (!(f->fd >= 0 && f->header)) + return -EINVAL; - f->header->state = STATE_OFFLINE; + while (!joined) { + switch (f->offline_state) { + case OFFLINE_JOINED: + /* No offline thread, no need to wait. */ + joined = true; + break; + + case OFFLINE_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_CANCEL)) + continue; + /* Canceled syncing prior to offlining, no need to wait. */ + break; + + case OFFLINE_AGAIN_FROM_SYNCING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_SYNCING, OFFLINE_CANCEL)) + continue; + /* Canceled restart from syncing, no need to wait. */ + break; + + case OFFLINE_AGAIN_FROM_OFFLINING: + if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_OFFLINING, OFFLINE_CANCEL)) + continue; + /* Canceled restart from offlining, must wait for offlining to complete however. */ + + /* fall through to wait */ + default: { + int r; + + r = journal_file_set_offline_thread_join(f); + if (r < 0) + return r; + + joined = true; + break; + } + } + } if (mmap_cache_got_sigbus(f->mmap, f->fd)) return -EIO; - (void) fsync(f->fd); + switch (f->header->state) { + case STATE_ONLINE: + return 0; - return 0; + case STATE_OFFLINE: + f->header->state = STATE_ONLINE; + (void) fsync(f->fd); + return 0; + + default: + return -EINVAL; + } } JournalFile* journal_file_close(JournalFile *f) { @@ -159,7 +330,7 @@ JournalFile* journal_file_close(JournalFile *f) { sd_event_source_unref(f->post_change_timer); } - journal_file_set_offline(f); + journal_file_set_offline(f, true); if (f->mmap && f->fd >= 0) mmap_cache_close_fd(f->mmap, f->fd); diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 07b9561b8a..fad4f78bdc 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -63,6 +63,16 @@ typedef enum LocationType { LOCATION_SEEK } LocationType; +typedef enum OfflineState { + OFFLINE_JOINED, + OFFLINE_SYNCING, + OFFLINE_OFFLINING, + OFFLINE_CANCEL, + OFFLINE_AGAIN_FROM_SYNCING, + OFFLINE_AGAIN_FROM_OFFLINING, + OFFLINE_DONE +} OfflineState; + typedef struct JournalFile { int fd; @@ -105,6 +115,9 @@ typedef struct JournalFile { OrderedHashmap *chain_cache; + pthread_t offline_thread; + volatile OfflineState offline_state; + #if defined(HAVE_XZ) || defined(HAVE_LZ4) void *compress_buffer; size_t compress_buffer_size; @@ -139,7 +152,7 @@ int journal_file_open( JournalFile *template, JournalFile **ret); -int journal_file_set_offline(JournalFile *f); +int journal_file_set_offline(JournalFile *f, bool wait); JournalFile* journal_file_close(JournalFile *j); int journal_file_open_reliably( diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 5e120fdac0..ac992a8b54 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -372,13 +372,13 @@ void server_sync(Server *s) { int r; if (s->system_journal) { - r = journal_file_set_offline(s->system_journal); + r = journal_file_set_offline(s->system_journal, false); if (r < 0) log_warning_errno(r, "Failed to sync system journal, ignoring: %m"); } ORDERED_HASHMAP_FOREACH(f, s->user_journals, i) { - r = journal_file_set_offline(f); + r = journal_file_set_offline(f, false); if (r < 0) log_warning_errno(r, "Failed to sync user journal, ignoring: %m"); } -- cgit v1.2.3-54-g00ecf From b58c888f30947b29730768c48ad402a2c5b65be9 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Wed, 17 Feb 2016 17:37:10 -0800 Subject: journal: defer journal closes on rotate When we rotate journals, we must set offline and close the current one, but don't generally need to wait for this to complete. Instead, we'll initiate an asynchronous offline via journal_file_set_offline(oldfile, false), and add the file to a per-server set of deferred closes to be closed later when they won't block. There's one complication however; journal_file_open() via journal_file_verify_header() assumes that any writable journal in the online state is the product of an unclean shutdown or other form of corruption. Thus there's a need for journal_file_open() to be aware of deferred closes and synchronize with their completion when opening preexisting journals for writing. To facilitate this the deferred closes set is supplied to the journal_file_open() function where the deferred closes may be closed synchronously before verifying the header in such circumstances. --- src/journal-remote/journal-remote-write.c | 2 +- src/journal-remote/journal-remote.c | 2 +- src/journal/journal-file.c | 42 +++++++++++++++++++++++++++---- src/journal/journal-file.h | 6 ++++- src/journal/journald-server.c | 22 +++++++++++++--- src/journal/journald-server.h | 2 ++ src/journal/sd-journal.c | 2 +- src/journal/test-journal-flush.c | 2 +- src/journal/test-journal-interleaving.c | 8 +++--- src/journal/test-journal-stream.c | 6 ++--- src/journal/test-journal-verify.c | 6 ++--- src/journal/test-journal.c | 14 +++++------ 12 files changed, 84 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index 5fab74e5cc..7bba52566e 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -54,7 +54,7 @@ void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) { **********************************************************************/ static int do_rotate(JournalFile **f, bool compress, bool seal) { - int r = journal_file_rotate(f, compress, seal); + int r = journal_file_rotate(f, compress, seal, NULL); if (r < 0) { if (*f) log_error_errno(r, "Failed to rotate %s: %m", (*f)->path); diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 3ce6fe27b3..44f9a9b44f 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -203,7 +203,7 @@ static int open_output(Writer *w, const char* host) { O_RDWR|O_CREAT, 0640, arg_compress, arg_seal, &w->metrics, - w->mmap, + w->mmap, NULL, NULL, &w->journal); if (r < 0) log_error_errno(r, "Failed to open output journal %s: %m", diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 96be339d5b..f5e2952c99 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -39,6 +39,7 @@ #include "parse-util.h" #include "random-util.h" #include "sd-event.h" +#include "set.h" #include "string-util.h" #include "xattr-util.h" @@ -310,6 +311,18 @@ static int journal_file_set_online(JournalFile *f) { } } +bool journal_file_is_offlining(JournalFile *f) { + assert(f); + + __sync_synchronize(); + + if (f->offline_state == OFFLINE_DONE || + f->offline_state == OFFLINE_JOINED) + return false; + + return true; +} + JournalFile* journal_file_close(JournalFile *f) { assert(f); @@ -374,6 +387,15 @@ JournalFile* journal_file_close(JournalFile *f) { return NULL; } +void journal_file_close_set(Set *s) { + JournalFile *f; + + assert(s); + + while ((f = set_steal_first(s))) + (void) journal_file_close(f); +} + static int journal_file_init_header(JournalFile *f, JournalFile *template) { Header h = {}; ssize_t k; @@ -2881,6 +2903,7 @@ int journal_file_open( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret) { @@ -3000,6 +3023,9 @@ int journal_file_open( f->header = h; if (!newly_created) { + if (deferred_closes) + journal_file_close_set(deferred_closes); + r = journal_file_verify_header(f); if (r < 0) goto fail; @@ -3074,7 +3100,7 @@ fail: return r; } -int journal_file_rotate(JournalFile **f, bool compress, bool seal) { +int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred_closes) { _cleanup_free_ char *p = NULL; size_t l; JournalFile *old_file, *new_file = NULL; @@ -3114,8 +3140,13 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) { * we archive them */ old_file->defrag_on_close = true; - r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file); - journal_file_close(old_file); + r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, deferred_closes, old_file, &new_file); + + if (deferred_closes && + set_put(deferred_closes, old_file) >= 0) + (void) journal_file_set_offline(old_file, false); + else + (void) journal_file_close(old_file); *f = new_file; return r; @@ -3129,6 +3160,7 @@ int journal_file_open_reliably( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret) { @@ -3136,7 +3168,7 @@ int journal_file_open_reliably( size_t l; _cleanup_free_ char *p = NULL; - r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); + r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); if (!IN_SET(r, -EBADMSG, /* corrupted */ -ENODATA, /* truncated */ @@ -3177,7 +3209,7 @@ int journal_file_open_reliably( log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname); - return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); + return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); } int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) { diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index fad4f78bdc..9ad6013359 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -149,11 +149,14 @@ int journal_file_open( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret); int journal_file_set_offline(JournalFile *f, bool wait); +bool journal_file_is_offlining(JournalFile *f); JournalFile* journal_file_close(JournalFile *j); +void journal_file_close_set(Set *s); int journal_file_open_reliably( const char *fname, @@ -163,6 +166,7 @@ int journal_file_open_reliably( bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, + Set *deferred_closes, JournalFile *template, JournalFile **ret); @@ -236,7 +240,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 void journal_file_dump(JournalFile *f); void journal_file_print_header(JournalFile *f); -int journal_file_rotate(JournalFile **f, bool compress, bool seal); +int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred_closes); void journal_file_post_change(JournalFile *f); int journal_file_enable_post_change_timer(JournalFile *f, sd_event *e, usec_t t); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index ac992a8b54..d5937bd013 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -251,9 +251,9 @@ static int open_journal( assert(ret); if (reliably) - r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f); + r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f); else - r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f); + r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f); if (r < 0) return r; @@ -333,7 +333,7 @@ static int do_rotate( if (!*f) return -EINVAL; - r = journal_file_rotate(f, s->compress, seal); + r = journal_file_rotate(f, s->compress, seal, s->deferred_closes); if (r < 0) if (*f) log_error_errno(r, "Failed to rotate %s: %m", (*f)->path); @@ -364,6 +364,13 @@ void server_rotate(Server *s) { /* Old file has been closed and deallocated */ ordered_hashmap_remove(s->user_journals, k); } + + /* Perform any deferred closes which aren't still offlining. */ + SET_FOREACH(f, s->deferred_closes, i) + if (!journal_file_is_offlining(f)) { + (void) set_remove(s->deferred_closes, f); + (void) journal_file_close(f); + } } void server_sync(Server *s) { @@ -1765,6 +1772,10 @@ int server_init(Server *s) { if (!s->mmap) return log_oom(); + s->deferred_closes = set_new(NULL); + if (!s->deferred_closes) + return log_oom(); + r = sd_event_default(&s->event); if (r < 0) return log_error_errno(r, "Failed to create event loop: %m"); @@ -1918,6 +1929,11 @@ void server_done(Server *s) { JournalFile *f; assert(s); + if (s->deferred_closes) { + journal_file_close_set(s->deferred_closes); + set_free(s->deferred_closes); + } + while (s->stdout_streams) stdout_stream_free(s->stdout_streams); diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index b9551dda1b..e025a4cf90 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -130,6 +130,8 @@ struct Server { MMapCache *mmap; + Set *deferred_closes; + struct udev *udev; uint64_t *kernel_seqnum; diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 9bc4215f2e..6ff1c67f5f 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1248,7 +1248,7 @@ static int add_any_file(sd_journal *j, const char *path) { goto fail; } - r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); + r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f); if (r < 0) { log_debug_errno(r, "Failed to open journal file %s: %m", path); goto fail; diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c index 0c35d532c6..93dc0e0d81 100644 --- a/src/journal/test-journal-flush.c +++ b/src/journal/test-journal-flush.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { assert_se(mkdtemp(dn)); fn = strappend(dn, "/test.journal"); - r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal); + r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, NULL, &new_journal); assert_se(r >= 0); r = sd_journal_open(&j, 0); diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 6c6238cc4b..f887f43f0d 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -52,7 +52,7 @@ noreturn static void log_assert_errno(const char *text, int eno, const char *fil static JournalFile *test_open(const char *name) { JournalFile *f; - assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f)); + assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &f)); return f; } @@ -217,7 +217,7 @@ static void test_sequence_numbers(void) { assert_se(chdir(t) >= 0); assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644, - true, false, NULL, NULL, NULL, &one) == 0); + true, false, NULL, NULL, NULL, NULL, &one) == 0); append_number(one, 1, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); @@ -234,7 +234,7 @@ static void test_sequence_numbers(void) { memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t)); assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644, - true, false, NULL, NULL, one, &two) == 0); + true, false, NULL, NULL, NULL, one, &two) == 0); assert_se(two->header->state == STATE_ONLINE); assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id)); @@ -265,7 +265,7 @@ static void test_sequence_numbers(void) { seqnum = 0; assert_se(journal_file_open("two.journal", O_RDWR, 0, - true, false, NULL, NULL, NULL, &two) == 0); + true, false, NULL, NULL, NULL, NULL, &two) == 0); assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id)); diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index 82543bb5f9..839ea5a9a5 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -92,9 +92,9 @@ int main(int argc, char *argv[]) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &one) == 0); - assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &two) == 0); - assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &three) == 0); + assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &one) == 0); + assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &two) == 0); + assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &three) == 0); for (i = 0; i < N_ENTRIES; i++) { char *p, *q; diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index 3fec18c480..6b4643cd25 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -55,7 +55,7 @@ static int raw_verify(const char *fn, const char *verification_key) { JournalFile *f; int r; - r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f); + r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f); if (r < 0) return r; @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) { log_info("Generating..."); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); for (n = 0; n < N_ENTRIES; n++) { struct iovec iovec; @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) { log_info("Verifying..."); - assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); /* journal_file_print_header(f); */ journal_file_dump(f); diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 94d26a2573..ea685af782 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -42,7 +42,7 @@ static void test_non_empty(void) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f) == 0); dual_timestamp_get(&ts); @@ -104,8 +104,8 @@ static void test_non_empty(void) { assert_se(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0); - journal_file_rotate(&f, true, true); - journal_file_rotate(&f, true, true); + journal_file_rotate(&f, true, true, NULL); + journal_file_rotate(&f, true, true, NULL); (void) journal_file_close(f); @@ -131,13 +131,13 @@ static void test_empty(void) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, &f1) == 0); + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, NULL, &f1) == 0); - assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f2) == 0); + assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &f2) == 0); - assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, &f3) == 0); + assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, NULL, &f3) == 0); - assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f4) == 0); + assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f4) == 0); journal_file_print_header(f1); puts(""); -- cgit v1.2.3-54-g00ecf From 0ea929d52f45cb99a381f40988a5278412899e0d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Sat, 20 Feb 2016 08:54:57 +0100 Subject: systemd-resolved: fix typo on log message --- src/resolve/resolved-llmnr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index ef12abfbb5..8b1d71a3eb 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -286,7 +286,7 @@ static int on_llmnr_stream_packet(DnsStream *s) { scope = manager_find_scope(s->manager, s->read_packet); if (!scope) { - log_warning("Got LLMNR TCP packet on unknown scope. Ignroing."); + log_warning("Got LLMNR TCP packet on unknown scope. Ignoring."); return 0; } -- cgit v1.2.3-54-g00ecf From 07dcb085893a2fe212b7e158028725876d2ab98f Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Sat, 20 Feb 2016 18:03:31 +0530 Subject: networkd: tunnel fix tunnel address this fixes 2655 --- src/network/networkd-netdev-tunnel.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 46ff2974f4..7aaa041ba3 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -54,7 +54,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin assert(link); assert(m); assert(t); - assert(t->family == AF_INET || t->family != -1); + assert(IN_SET(t->family, AF_INET, AF_UNSPEC)); r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); if (r < 0) @@ -87,7 +87,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink assert(link); assert(m); assert(t); - assert(t->family == AF_INET || t->family != -1); + assert(IN_SET(t->family, AF_INET, AF_UNSPEC)); r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); if (r < 0) @@ -124,7 +124,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink t = GRETAP(netdev); assert(t); - assert(t->family == AF_INET || t->family != -1); + assert(IN_SET(t->family, AF_INET, AF_UNSPEC)); assert(link); assert(m); @@ -497,7 +497,7 @@ static void ipip_init(NetDev *n) { assert(t); t->pmtudisc = true; - t->family = -1; + t->family = AF_UNSPEC; } static void sit_init(NetDev *n) { @@ -507,7 +507,7 @@ static void sit_init(NetDev *n) { assert(t); t->pmtudisc = true; - t->family = -1; + t->family = AF_UNSPEC; } static void vti_init(NetDev *n) { @@ -538,7 +538,7 @@ static void gre_init(NetDev *n) { assert(t); t->pmtudisc = true; - t->family = -1; + t->family = AF_UNSPEC; } static void ip6gre_init(NetDev *n) { -- cgit v1.2.3-54-g00ecf From 56e3d0cf5d44054e79b815068d3fa09f51dc8ba2 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 20 Feb 2016 16:28:42 -0500 Subject: test-siphash24: add a test for concatenating very short buffers coverity seems to think that our siphash code can read past the end of a short buffer. Add a test which adds very short buffers with different combinations of length to the hash. Hashing is done twice, once with zeros following "data", and once with some other bytes following "data". The two results are then compared to verify that the result does not depend on bytes past the specified data length. (This test passes.) --- src/test/test-siphash24.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c index caae911f30..b74b7ad2dd 100644 --- a/src/test/test-siphash24.c +++ b/src/test/test-siphash24.c @@ -22,9 +22,9 @@ #define ITERATIONS 10000000ULL -static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { +static void do_test(const uint8_t *in, size_t len, const uint8_t *key) { struct siphash state = {}; - uint64_t out = 0; + uint64_t out; unsigned i, j; out = siphash24(in, len, key); @@ -60,7 +60,46 @@ static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { assert_se(out == 0xa129ca6149be45e5); } } - return 0; +} + +static void test_short_hashes(void) { + const uint8_t one[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + const uint8_t key[16] = { 0x22, 0x24, 0x41, 0x22, 0x55, 0x77, 0x88, 0x07, + 0x23, 0x09, 0x23, 0x14, 0x0c, 0x33, 0x0e, 0x0f}; + uint8_t two[sizeof one] = {}; + + struct siphash state1 = {}, state2 = {}; + unsigned i, j; + + siphash24_init(&state1, key); + siphash24_init(&state2, key); + + /* hashing 1, 2, 3, 4, 5, ..., 16 bytes, with the byte after the buffer different */ + for (i = 1; i <= sizeof one; i++) { + siphash24_compress(one, i, &state1); + + two[i-1] = one[i-1]; + siphash24_compress(two, i, &state2); + + assert_se(memcmp(&state1, &state2, sizeof state1) == 0); + } + + /* hashing n and 1, n and 2, n and 3, ..., n-1 and 1, n-2 and 2, ... */ + for (i = sizeof one; i > 0; i--) { + zero(two); + + for (j = 1; j <= sizeof one; j++) { + siphash24_compress(one, i, &state1); + siphash24_compress(one, j, &state1); + + siphash24_compress(one, i, &state2); + two[j-1] = one[j-1]; + siphash24_compress(two, j, &state2); + + assert_se(memcmp(&state1, &state2, sizeof state1) == 0); + } + } } /* see https://131002.net/siphash/siphash.pdf, Appendix A */ @@ -80,4 +119,6 @@ int main(int argc, char *argv[]) { do_test(in_buf + 2, sizeof(in), key); memcpy(in_buf + 4, in, sizeof(in)); do_test(in_buf + 4, sizeof(in), key); + + test_short_hashes(); } -- cgit v1.2.3-54-g00ecf From c7d264ff9835ede8fae2f9edf8431fff8da19872 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 18:56:37 +0100 Subject: sd-lldp: drop state field There's really no point in maintaining a state, the state machine is trivial, and we actually never look at the state anyway, we just keep updating it. --- src/libsystemd-network/sd-lldp.c | 61 ++-------------------------------------- 1 file changed, 3 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 885ca62425..97fa5b23f8 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -33,18 +33,6 @@ #include "siphash24.h" #include "string-util.h" -typedef enum LLDPAgentRXState { - LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4, - LLDP_AGENT_RX_DELETE_AGED_INFO, - LLDP_AGENT_RX_LLDP_INITIALIZE, - LLDP_AGENT_RX_WAIT_FOR_FRAME, - LLDP_AGENT_RX_RX_FRAME, - LLDP_AGENT_RX_DELETE_INFO, - LLDP_AGENT_RX_UPDATE_INFO, - _LLDP_AGENT_RX_STATE_MAX, - _LLDP_AGENT_RX_INVALID = -1, -} LLDPAgentRXState; - /* Section 10.5.2.2 Reception counters */ struct lldp_agent_statistics { uint64_t stats_ageouts_total; @@ -65,7 +53,6 @@ struct sd_lldp { void *userdata; - LLDPAgentRXState rx_state; lldp_agent_statistics statistics; }; @@ -103,8 +90,6 @@ static const struct hash_ops chassis_id_hash_ops = { }; static void lldp_mib_delete_objects(sd_lldp *lldp); -static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state); -static void lldp_run_state_machine(sd_lldp *ll); static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { int r; @@ -113,18 +98,15 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { assert(tlv); /* Remove expired packets */ - if (prioq_size(lldp->by_expiry) > 0) { - - lldp_set_state(lldp, LLDP_AGENT_RX_DELETE_INFO); - + if (prioq_size(lldp->by_expiry) > 0) lldp_mib_delete_objects(lldp); - } r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv); if (r < 0) goto out; - lldp_set_state(lldp, LLDP_AGENT_RX_UPDATE_INFO); + if (lldp->cb) + lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); log_lldp("Packet added. MIB size: %d , PQ size: %d", hashmap_size(lldp->neighbour_mib), @@ -136,8 +118,6 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { if (r < 0) log_lldp("Receive frame failed: %s", strerror(-r)); - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); - return 0; } @@ -162,8 +142,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { goto out; } - lldp_set_state(lldp, LLDP_AGENT_RX_RX_FRAME); - p = tlv->pdu; p += sizeof(struct ether_header); @@ -350,8 +328,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { return lldp_receive_frame(lldp, tlv); out: - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); - if (malformed) { lldp->statistics.stats_frames_discarded_total ++; lldp->statistics.stats_frames_in_errors_total ++; @@ -374,29 +350,6 @@ static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) { return 0; } -static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) { - - assert(lldp); - assert(state < _LLDP_AGENT_RX_STATE_MAX); - - lldp->rx_state = state; - - lldp_run_state_machine(lldp); -} - -static void lldp_run_state_machine(sd_lldp *lldp) { - if (!lldp->cb) - return; - - switch (lldp->rx_state) { - case LLDP_AGENT_RX_UPDATE_INFO: - lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); - break; - default: - break; - } -} - /* 10.5.5.2.1 mibDeleteObjects () * The mibDeleteObjects () procedure deletes all information in the LLDP remote * systems MIB associated with the MSAP identifier if an LLDPDU is received with @@ -597,21 +550,15 @@ int sd_lldp_start(sd_lldp *lldp) { lldp->port->status = LLDP_PORT_STATUS_ENABLED; - lldp_set_state(lldp, LLDP_AGENT_RX_LLDP_INITIALIZE); - r = lldp_port_start(lldp->port); if (r < 0) { log_lldp("Failed to start Port : %s , %s", lldp->port->ifname, strerror(-r)); - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL); - return r; } - lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); - return 0; } @@ -715,8 +662,6 @@ int sd_lldp_new(int ifindex, if (r < 0) return r; - lldp->rx_state = LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL; - *ret = lldp; lldp = NULL; -- cgit v1.2.3-54-g00ecf From ccf86354354a378b314f66465bbb31f51b91864c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 18:58:51 +0100 Subject: libsystemd-network: don't abbreviate "callback" as "cb" needlessly This isn't an excercise in creating APIs that are hard to understand, hence let's call a callback a callback. --- src/libsystemd-network/dhcp-internal.h | 4 ++-- src/libsystemd-network/dhcp-option.c | 4 ++-- src/libsystemd-network/sd-dhcp-client.c | 4 ++-- src/libsystemd-network/sd-dhcp6-client.c | 4 ++-- src/libsystemd-network/sd-ipv4acd.c | 4 ++-- src/libsystemd-network/sd-ipv4ll.c | 4 ++-- src/libsystemd-network/sd-lldp.c | 10 +++++----- src/libsystemd-network/test-lldp.c | 2 +- src/systemd/sd-dhcp-client.h | 4 ++-- src/systemd/sd-dhcp6-client.h | 4 ++-- src/systemd/sd-ipv4acd.h | 4 ++-- src/systemd/sd-ipv4ll.h | 4 ++-- src/systemd/sd-lldp.h | 4 ++-- 13 files changed, 28 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index a3b842cda3..4662b0d847 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -42,10 +42,10 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload, uint8_t code, size_t optlen, const void *optval); -typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, +typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len, const void *option, void *userdata); -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message); +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message); int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type, uint16_t arp_type, size_t optlen, diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index b0ea7576bf..531b80eb08 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -135,7 +135,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, } static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, - uint8_t *message_type, char **error_message, dhcp_option_cb_t cb, + uint8_t *message_type, char **error_message, dhcp_option_callback_t cb, void *userdata) { uint8_t code, len; const uint8_t *option; @@ -221,7 +221,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo return 0; } -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) { +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) { _cleanup_free_ char *error_message = NULL; uint8_t overload = 0; uint8_t message_type = 0; diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 62099dd3f4..af9f3e45e5 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -101,7 +101,7 @@ struct sd_dhcp_client { sd_event_source *timeout_t1; sd_event_source *timeout_t2; sd_event_source *timeout_expire; - sd_dhcp_client_cb_t cb; + sd_dhcp_client_callback_t cb; void *userdata; sd_dhcp_lease *lease; usec_t start_delay; @@ -121,7 +121,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd, uint32_t revents, void *userdata); static void client_stop(sd_dhcp_client *client, int error); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, void *userdata) { assert_return(client, -EINVAL); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 7d56d4cc60..8622e7952b 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -64,7 +64,7 @@ struct sd_dhcp6_client { uint8_t retransmit_count; sd_event_source *timeout_resend; sd_event_source *timeout_resend_expire; - sd_dhcp6_client_cb_t cb; + sd_dhcp6_client_callback_t cb; void *userdata; struct duid duid; size_t duid_len; @@ -111,7 +111,7 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); static int client_start(sd_dhcp6_client *client, enum DHCP6State state); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) { +int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) { assert_return(client, -EINVAL); client->cb = cb; diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index f7880a891c..d0aa0e6e33 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -92,7 +92,7 @@ struct sd_ipv4acd { struct ether_addr mac_addr; sd_event *event; int event_priority; - sd_ipv4acd_cb_t cb; + sd_ipv4acd_callback_t cb; void* userdata; }; @@ -447,7 +447,7 @@ int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) { return 0; } -int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) { +int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) { assert_return(ll, -EINVAL); ll->cb = cb; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index db6cf22aaa..31ba6a6348 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -52,7 +52,7 @@ struct sd_ipv4ll { /* External */ be32_t claimed_address; - sd_ipv4ll_cb_t cb; + sd_ipv4ll_callback_t cb; void* userdata; }; @@ -172,7 +172,7 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) { return 0; } -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) { +int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) { assert_return(ll, -EINVAL); ll->cb = cb; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 97fa5b23f8..3dfb08cd46 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -49,7 +49,7 @@ struct sd_lldp { Prioq *by_expiry; Hashmap *neighbour_mib; - sd_lldp_cb_t cb; + sd_lldp_callback_t callback; void *userdata; @@ -105,8 +105,8 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { if (r < 0) goto out; - if (lldp->cb) - lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); + if (lldp->callback) + lldp->callback(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); log_lldp("Packet added. MIB size: %d , PQ size: %d", hashmap_size(lldp->neighbour_mib), @@ -607,10 +607,10 @@ int sd_lldp_detach_event(sd_lldp *lldp) { return 0; } -int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) { +int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { assert_return(lldp, -EINVAL); - lldp->cb = cb; + lldp->callback = cb; lldp->userdata = userdata; return 0; diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index b8490073dd..ed923d5cb3 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -256,7 +256,7 @@ static void lldp_handler (sd_lldp *lldp, int event, void *userdata) { lldp_handler_calls++; } -static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) { +static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) { int r; r = sd_lldp_new(42, "dummy", &mac_addr, lldp); diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 2b865a80e1..659fa17563 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -84,9 +84,9 @@ enum { typedef struct sd_dhcp_client sd_dhcp_client; -typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, +typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, void *userdata); int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 9608060830..a72b229e0a 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -76,10 +76,10 @@ enum { typedef struct sd_dhcp6_client sd_dhcp6_client; -typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event, +typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata); int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_cb_t cb, void *userdata); + sd_dhcp6_client_callback_t cb, void *userdata); int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index 3a2219c82c..3f86de3381 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -37,12 +37,12 @@ enum { }; typedef struct sd_ipv4acd sd_ipv4acd; -typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata); +typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata); int sd_ipv4acd_detach_event(sd_ipv4acd *ll); int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority); int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address); -int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata); +int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 67c566fe0d..de4b1b8d6c 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -36,12 +36,12 @@ enum { }; typedef struct sd_ipv4ll sd_ipv4ll; -typedef void (*sd_ipv4ll_cb_t)(sd_ipv4ll *ll, int event, void *userdata); +typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata); int sd_ipv4ll_detach_event(sd_ipv4ll *ll); int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority); int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata); +int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index ea952ef187..dd8548e3d3 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -43,7 +43,7 @@ enum { typedef struct sd_lldp sd_lldp; typedef struct sd_lldp_packet sd_lldp_packet; -typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata); +typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, int event, void *userdata); int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret); sd_lldp* sd_lldp_unref(sd_lldp *lldp); @@ -54,7 +54,7 @@ int sd_lldp_stop(sd_lldp *lldp); int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority); int sd_lldp_detach_event(sd_lldp *lldp); -int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata); +int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); int sd_lldp_save(sd_lldp *lldp, const char *file); int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -- cgit v1.2.3-54-g00ecf From 2139d247bd2909be5a1991b96aaf305136131244 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 19:05:35 +0100 Subject: sd-lldp: drop keeping of statistics We don't expose them, and they are only of questionnable use. --- src/libsystemd-network/sd-lldp.c | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 3dfb08cd46..2663e235f3 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -33,16 +33,6 @@ #include "siphash24.h" #include "string-util.h" -/* Section 10.5.2.2 Reception counters */ -struct lldp_agent_statistics { - uint64_t stats_ageouts_total; - uint64_t stats_frames_discarded_total; - uint64_t stats_frames_in_errors_total; - uint64_t stats_frames_in_total; - uint64_t stats_tlvs_discarded_total; - uint64_t stats_tlvs_unrecognized_total; -}; - struct sd_lldp { lldp_port *port; @@ -52,8 +42,6 @@ struct sd_lldp { sd_lldp_callback_t callback; void *userdata; - - lldp_agent_statistics statistics; }; static void chassis_id_hash_func(const void *p, struct siphash *state) { @@ -112,8 +100,6 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { hashmap_size(lldp->neighbour_mib), prioq_size(lldp->by_expiry)); - lldp->statistics.stats_frames_in_total ++; - out: if (r < 0) log_lldp("Receive frame failed: %s", strerror(-r)); @@ -124,7 +110,7 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { /* 10.3.2 LLDPDU validation: rxProcessFrame() */ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { bool system_description = false, system_name = false, chassis_id = false; - bool malformed = false, port_id = false, ttl = false, end = false; + bool port_id = false, ttl = false, end = false; uint16_t type, len, i, l, t; lldp_port *port; uint8_t *p, *q; @@ -156,7 +142,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (len != 0) { log_lldp("TLV type end must be length 0 (not %d). Dropping.", len); - malformed = true; goto out; } @@ -166,7 +151,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { } else if (type >=_LLDP_TYPE_MAX) { log_lldp("TLV type: %d not recognized. Dropping.", type); - malformed = true; goto out; } @@ -181,7 +165,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (i != type) { log_lldp("TLV missing or out of order. Dropping."); - malformed = true; goto out; } } @@ -192,14 +175,12 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (len < 2) { log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len); - malformed = true; goto out; } if (chassis_id) { log_lldp("Duplicate Chassis ID TLV found. Dropping."); - malformed = true; goto out; } @@ -207,7 +188,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) { log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q); - malformed = true; goto out; } @@ -220,14 +200,12 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (len < 2) { log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len); - malformed = true; goto out; } if (port_id) { log_lldp("Duplicate Port ID TLV found. Dropping."); - malformed = true; goto out; } @@ -235,7 +213,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) { log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q); - malformed = true; goto out; } @@ -248,14 +225,12 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if(len != 2) { log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len); - malformed = true; goto out; } if (ttl) { log_lldp("Duplicate TTL TLV found. Dropping."); - malformed = true; goto out; } @@ -267,13 +242,11 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { /* According to RFC 1035 the length of a FQDN is limited to 255 characters */ if (len > 255) { log_lldp("Received invalid system name length: %d. Dropping.", len); - malformed = true; goto out; } if (system_name) { log_lldp("Duplicate system name found. Dropping."); - malformed = true; goto out; } @@ -285,13 +258,11 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { /* 0 <= n <= 255 octets */ if (len > 255) { log_lldp("Received invalid system description length: %d. Dropping.", len); - malformed = true; goto out; } if (system_description) { log_lldp("Duplicate system description found. Dropping."); - malformed = true; goto out; } @@ -302,7 +273,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (len == 0) { log_lldp("TLV type: %d length 0 received. Dropping.", type); - malformed = true; goto out; } break; @@ -312,7 +282,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if(!chassis_id || !port_id || !ttl || !end) { log_lldp("One or more mandatory TLV missing. Dropping."); - malformed = true; goto out; } @@ -321,17 +290,12 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (r < 0) { log_lldp("Failed to parse the TLV. Dropping."); - malformed = true; goto out; } return lldp_receive_frame(lldp, tlv); out: - if (malformed) { - lldp->statistics.stats_frames_discarded_total ++; - lldp->statistics.stats_frames_in_errors_total ++; - } sd_lldp_packet_unref(tlv); @@ -376,8 +340,6 @@ static void lldp_mib_delete_objects(sd_lldp *lldp) { break; lldp_neighbour_port_remove_and_free(p); - - lldp->statistics.stats_ageouts_total ++; } } -- cgit v1.2.3-54-g00ecf From 032b27f53452b224ce233381f9e5631998f80ea8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 19:26:40 +0100 Subject: sd-lldp: drop "port" object Let's just keep the few parts we actually need of it in the main sd_lldp object, so that we can simplify things quite a bit. While we are at it, remove ifname and mac fields which we make no use of whatsoever. --- Makefile.am | 2 - src/libsystemd-network/lldp-port.c | 116 ------------------------------------- src/libsystemd-network/lldp-port.h | 69 ---------------------- src/libsystemd-network/sd-lldp.c | 100 +++++++++++++++++--------------- src/libsystemd-network/test-lldp.c | 2 +- src/network/networkd-link.c | 5 +- src/systemd/sd-lldp.h | 4 +- 7 files changed, 58 insertions(+), 240 deletions(-) delete mode 100644 src/libsystemd-network/lldp-port.c delete mode 100644 src/libsystemd-network/lldp-port.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 03341fcd28..06ca3532b4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3303,8 +3303,6 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/lldp-tlv.c \ src/libsystemd-network/lldp-network.h \ src/libsystemd-network/lldp-network.c \ - src/libsystemd-network/lldp-port.h \ - src/libsystemd-network/lldp-port.c \ src/libsystemd-network/lldp-internal.h \ src/libsystemd-network/lldp-internal.c \ src/libsystemd-network/sd-lldp.c diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c deleted file mode 100644 index c86f62a6c2..0000000000 --- a/src/libsystemd-network/lldp-port.c +++ /dev/null @@ -1,116 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - 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 . -***/ - -#include "alloc-util.h" -#include "async.h" -#include "lldp-internal.h" -#include "lldp-network.h" -#include "lldp-port.h" - -int lldp_port_start(lldp_port *p) { - int r; - - assert_return(p, -EINVAL); - - r = lldp_network_bind_raw_socket(p->ifindex); - if (r < 0) - return r; - - p->rawfd = r; - - r = sd_event_add_io(p->event, &p->lldp_port_rx, - p->rawfd, EPOLLIN, lldp_receive_packet, p); - if (r < 0) { - log_debug_errno(r, "Failed to allocate event source: %m"); - goto fail; - } - - r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority); - if (r < 0) { - log_debug_errno(r, "Failed to set event priority: %m"); - goto fail; - } - - r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx"); - if (r < 0) { - log_debug_errno(r, "Failed to set event name: %m"); - goto fail; - } - - return 0; - -fail: - lldp_port_stop(p); - - return r; -} - -int lldp_port_stop(lldp_port *p) { - - assert_return(p, -EINVAL); - - p->rawfd = asynchronous_close(p->rawfd); - p->lldp_port_rx = sd_event_source_unref(p->lldp_port_rx); - - return 0; -} - -void lldp_port_free(lldp_port *p) { - if (!p) - return; - - lldp_port_stop(p); - - free(p->ifname); - free(p); -} - -int lldp_port_new(int ifindex, - const char *ifname, - const struct ether_addr *addr, - void *userdata, - lldp_port **ret) { - _cleanup_free_ lldp_port *p = NULL; - - assert_return(ifindex, -EINVAL); - assert_return(ifname, -EINVAL); - assert_return(addr, -EINVAL); - - p = new0(lldp_port, 1); - if (!p) - return -ENOMEM; - - p->rawfd = -1; - p->ifindex = ifindex; - - p->ifname = strdup(ifname); - if (!p->ifname) - return -ENOMEM; - - memcpy(&p->mac, addr, ETH_ALEN); - - p->userdata = userdata; - - *ret = p; - - p = NULL; - - return 0; -} diff --git a/src/libsystemd-network/lldp-port.h b/src/libsystemd-network/lldp-port.h deleted file mode 100644 index 96092f8df9..0000000000 --- a/src/libsystemd-network/lldp-port.h +++ /dev/null @@ -1,69 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - 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 . -***/ - -#pragma once - -#include - -#include "sd-event.h" -#include "sd-lldp.h" - -#include "util.h" - -typedef struct lldp_port lldp_port; - -typedef enum LLDPPortStatus { - LLDP_PORT_STATUS_NONE, - LLDP_PORT_STATUS_ENABLED, - LLDP_PORT_STATUS_DISABLED, - _LLDP_PORT_STATUS_MAX, - _LLDP_PORT_STATUS_INVALID = -1, -} LLDPPortStatus; - -struct lldp_port { - LLDPPortStatus status; - - int ifindex; - char *ifname; - - struct ether_addr mac; - - int rawfd; - - sd_event *event; - sd_event_source *lldp_port_rx; - - int event_priority; - - void *userdata; -}; - -int lldp_port_new(int ifindex, - const char *ifname, - const struct ether_addr *addr, - void *userdata, - lldp_port **ret); -void lldp_port_free(lldp_port *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_port*, lldp_port_free); -#define _cleanup_lldp_port_free_ _cleanup_(lldp_port_freep) - -int lldp_port_start(lldp_port *p); -int lldp_port_stop(lldp_port *p); diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 2663e235f3..34117cc205 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -27,20 +27,24 @@ #include "fileio.h" #include "hashmap.h" #include "lldp-internal.h" -#include "lldp-port.h" +#include "lldp-network.h" #include "lldp-tlv.h" #include "prioq.h" #include "siphash24.h" #include "string-util.h" struct sd_lldp { - lldp_port *port; + int ifindex; + int fd; + + sd_event *event; + int64_t event_priority; + sd_event_source *event_source; Prioq *by_expiry; Hashmap *neighbour_mib; sd_lldp_callback_t callback; - void *userdata; }; @@ -112,7 +116,6 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { bool system_description = false, system_name = false, chassis_id = false; bool port_id = false, ttl = false, end = false; uint16_t type, len, i, l, t; - lldp_port *port; uint8_t *p, *q; sd_lldp *lldp; int r; @@ -120,13 +123,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { assert(tlv); assert(length > 0); - port = (lldp_port *) tlv->userdata; - lldp = (sd_lldp *) port->userdata; - - if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) { - log_lldp("Port: %s is disabled. Dropping.", lldp->port->ifname); - goto out; - } + lldp = tlv->userdata; p = tlv->pdu; p += sizeof(struct ether_header); @@ -508,54 +505,67 @@ int sd_lldp_start(sd_lldp *lldp) { int r; assert_return(lldp, -EINVAL); - assert_return(lldp->port, -EINVAL); - lldp->port->status = LLDP_PORT_STATUS_ENABLED; + if (lldp->fd >= 0) + return 0; - r = lldp_port_start(lldp->port); - if (r < 0) { - log_lldp("Failed to start Port : %s , %s", - lldp->port->ifname, - strerror(-r)); + assert(!lldp->event_source); - return r; + lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex); + if (lldp->fd < 0) + return lldp->fd; + + if (lldp->event) { + r = sd_event_add_io(lldp->event, &lldp->event_source, lldp->fd, EPOLLIN, lldp_receive_packet, lldp); + if (r < 0) + goto fail; + + r = sd_event_source_set_priority(lldp->event_source, lldp->event_priority); + if (r < 0) + goto fail; + + (void) sd_event_source_set_description(lldp->event_source, "lldp"); } - return 0; + return 1; + +fail: + lldp->event_source = sd_event_source_unref(lldp->event_source); + lldp->fd = safe_close(lldp->fd); + + return r; } int sd_lldp_stop(sd_lldp *lldp) { - int r; - assert_return(lldp, -EINVAL); - assert_return(lldp->port, -EINVAL); - lldp->port->status = LLDP_PORT_STATUS_DISABLED; + if (lldp->fd < 0) + return 0; - r = lldp_port_stop(lldp->port); - if (r < 0) - return r; + lldp->event_source = sd_event_source_unref(lldp->event_source); + lldp->fd = safe_close(lldp->fd); lldp_mib_objects_flush(lldp); - return 0; + return 1; } -int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) { +int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { int r; assert_return(lldp, -EINVAL); - assert_return(!lldp->port->event, -EBUSY); + assert_return(lldp->fd < 0, -EBUSY); + assert_return(!lldp->event, -EBUSY); if (event) - lldp->port->event = sd_event_ref(event); + lldp->event = sd_event_ref(event); else { - r = sd_event_default(&lldp->port->event); + r = sd_event_default(&lldp->event); if (r < 0) return r; } - lldp->port->event_priority = priority; + lldp->event_priority = priority; return 0; } @@ -563,8 +573,9 @@ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) { int sd_lldp_detach_event(sd_lldp *lldp) { assert_return(lldp, -EINVAL); + assert_return(lldp->fd < 0, -EBUSY); - lldp->port->event = sd_event_unref(lldp->port->event); + lldp->event = sd_event_unref(lldp->event); return 0; } @@ -586,41 +597,36 @@ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { /* Drop all packets */ lldp_mib_objects_flush(lldp); - lldp_port_free(lldp->port); - hashmap_free(lldp->neighbour_mib); prioq_free(lldp->by_expiry); + sd_event_source_unref(lldp->event_source); + sd_event_unref(lldp->event); + safe_close(lldp->fd); + free(lldp); return NULL; } -int sd_lldp_new(int ifindex, - const char *ifname, - const struct ether_addr *mac, - sd_lldp **ret) { +int sd_lldp_new(int ifindex, sd_lldp **ret) { _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; int r; assert_return(ret, -EINVAL); assert_return(ifindex > 0, -EINVAL); - assert_return(ifname, -EINVAL); - assert_return(mac, -EINVAL); lldp = new0(sd_lldp, 1); if (!lldp) return -ENOMEM; - r = lldp_port_new(ifindex, ifname, mac, lldp, &lldp->port); - if (r < 0) - return r; + lldp->fd = -1; + lldp->ifindex = ifindex; lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops); if (!lldp->neighbour_mib) return -ENOMEM; - r = prioq_ensure_allocated(&lldp->by_expiry, - ttl_expiry_item_prioq_compare_func); + r = prioq_ensure_allocated(&lldp->by_expiry, ttl_expiry_item_prioq_compare_func); if (r < 0) return r; diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index ed923d5cb3..7b8dd0ad88 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -259,7 +259,7 @@ static void lldp_handler (sd_lldp *lldp, int event, void *userdata) { static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) { int r; - r = sd_lldp_new(42, "dummy", &mac_addr, lldp); + r = sd_lldp_new(42, lldp); if (r) return r; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 692c0bf63d..1711436b48 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2109,7 +2109,7 @@ static int link_configure(Link *link) { } if (link_lldp_enabled(link)) { - r = sd_lldp_new(link->ifindex, link->ifname, &link->mac, &link->lldp); + r = sd_lldp_new(link->ifindex, &link->lldp); if (r < 0) return r; @@ -2117,8 +2117,7 @@ static int link_configure(Link *link) { if (r < 0) return r; - r = sd_lldp_set_callback(link->lldp, - lldp_handler, link); + r = sd_lldp_set_callback(link->lldp, lldp_handler, link); if (r < 0) return r; } diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index dd8548e3d3..4c896e7fc0 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -45,13 +45,13 @@ typedef struct sd_lldp_packet sd_lldp_packet; typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, int event, void *userdata); -int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret); +int sd_lldp_new(int ifindex, sd_lldp **ret); sd_lldp* sd_lldp_unref(sd_lldp *lldp); int sd_lldp_start(sd_lldp *lldp); int sd_lldp_stop(sd_lldp *lldp); -int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority); +int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority); int sd_lldp_detach_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); -- cgit v1.2.3-54-g00ecf From 32d2064523461b3761b51ad9c38f098c9ac2dbc9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 19:33:36 +0100 Subject: libsystemd-network: sd-event uses 64bit priorities, expose them in the APIs as such --- src/libsystemd-network/sd-dhcp-client.c | 3 +-- src/libsystemd-network/sd-dhcp-server.c | 3 +-- src/libsystemd-network/sd-dhcp6-client.c | 2 +- src/libsystemd-network/sd-ipv4acd.c | 2 +- src/libsystemd-network/sd-ipv4ll.c | 2 +- src/libsystemd-network/sd-ndisc.c | 2 +- src/libsystemd/sd-netlink/sd-netlink.c | 2 +- src/libsystemd/sd-resolve/sd-resolve.c | 2 +- src/systemd/sd-dhcp-client.h | 2 +- src/systemd/sd-dhcp-server.h | 2 +- src/systemd/sd-dhcp6-client.h | 3 +-- src/systemd/sd-ipv4acd.h | 2 +- src/systemd/sd-ipv4ll.h | 2 +- src/systemd/sd-ndisc.h | 2 +- src/systemd/sd-netlink.h | 2 +- src/systemd/sd-resolve.h | 2 +- 16 files changed, 16 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index af9f3e45e5..d484c37a73 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1691,8 +1691,7 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) { return 0; } -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, - int priority) { +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) { int r; assert_return(client, -EINVAL); diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 54ff1a3f28..1c408aaaac 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -208,8 +208,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { return 0; } -int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, - int priority) { +int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) { int r; assert_return(server, -EINVAL); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 8622e7952b..af4709d788 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -1204,7 +1204,7 @@ error: return r; } -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) { +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) { int r; assert_return(client, -EINVAL); diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index d0aa0e6e33..8a26cb8770 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -428,7 +428,7 @@ int sd_ipv4acd_detach_event(sd_ipv4acd *ll) { return 0; } -int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) { +int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) { int r; assert_return(ll, -EINVAL); diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 31ba6a6348..aca393aa5e 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -160,7 +160,7 @@ int sd_ipv4ll_detach_event(sd_ipv4ll *ll) { return sd_ipv4acd_detach_event(ll->acd); } -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) { +int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) { int r; assert_return(ll, -EINVAL); diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index bae6a49fe6..fb4ef55673 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -166,7 +166,7 @@ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { } -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) { +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { int r; assert_return(nd, -EINVAL); diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 4833815b43..f5c2b33f46 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -774,7 +774,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) { return 1; } -int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) { +int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) { int r; assert_return(rtnl, -EINVAL); diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index d693b2c2b0..910e75441f 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -1191,7 +1191,7 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd return 1; } -_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) { +_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) { int r; assert_return(resolve, -EINVAL); diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 659fa17563..ef45370505 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -113,7 +113,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); int sd_dhcp_client_new(sd_dhcp_client **ret); -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority); +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority); int sd_dhcp_client_detach_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 8658197e80..fcef083ce6 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -37,7 +37,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex); sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server); sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server); -int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority); +int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int64_t priority); int sd_dhcp_server_detach_event(sd_dhcp_server *client); sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index a72b229e0a..1bedc941aa 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -97,8 +97,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret); int sd_dhcp6_client_stop(sd_dhcp6_client *client); int sd_dhcp6_client_start(sd_dhcp6_client *client); int sd_dhcp6_client_is_running(sd_dhcp6_client *client); -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, - int priority); +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority); int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index 3f86de3381..9e3e14a30c 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -40,7 +40,7 @@ typedef struct sd_ipv4acd sd_ipv4acd; typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata); int sd_ipv4acd_detach_event(sd_ipv4acd *ll); -int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority); +int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority); int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address); int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index de4b1b8d6c..6fa38a2243 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -39,7 +39,7 @@ typedef struct sd_ipv4ll sd_ipv4ll; typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata); int sd_ipv4ll_detach_event(sd_ipv4ll *ll); -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority); +int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority); int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 762947531d..29bcbe8e3e 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -52,7 +52,7 @@ int sd_ndisc_set_callback(sd_ndisc *nd, int sd_ndisc_set_index(sd_ndisc *nd, int interface_index); int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority); +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); int sd_ndisc_detach_event(sd_ndisc *nd); sd_event *sd_ndisc_get_event(sd_ndisc *nd); diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index b4798d2476..71bcd24014 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -64,7 +64,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout); int sd_netlink_add_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata); int sd_netlink_remove_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata); -int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int priority); +int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority); int sd_netlink_detach_event(sd_netlink *nl); int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data); diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 903b917f70..1c792dab39 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -79,7 +79,7 @@ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec); int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid); -int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int priority); +int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int64_t priority); int sd_resolve_detach_event(sd_resolve *resolve); sd_event *sd_resolve_get_event(sd_resolve *resolve); -- cgit v1.2.3-54-g00ecf From bd8650e9b8862fd42deb7e1c0b64e5bd63f2daf0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 19:36:47 +0100 Subject: test-lldp: fix error checking expressions --- src/libsystemd-network/test-lldp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 7b8dd0ad88..768211a315 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -260,19 +260,19 @@ static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void * int r; r = sd_lldp_new(42, lldp); - if (r) + if (r < 0) return r; r = sd_lldp_attach_event(*lldp, e, 0); - if (r) + if (r < 0) return r; r = sd_lldp_set_callback(*lldp, cb, cb_data); - if (r) + if (r < 0) return r; r = sd_lldp_start(*lldp); - if (r) + if (r < 0) return r; return 0; @@ -282,11 +282,11 @@ static int stop_lldp(sd_lldp *lldp) { int r; r = sd_lldp_stop(lldp); - if (r) + if (r < 0) return r; r = sd_lldp_detach_event(lldp); - if (r) + if (r < 0) return r; sd_lldp_unref(lldp); -- cgit v1.2.3-54-g00ecf From 43a6a52efe2005a49714f423331432cd833ec4df Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 19:46:28 +0100 Subject: sd-lldp: move ETHERTYPE_LLDP to missing.h After all, most ETHERTYPE variables are defined in the system headers, hence define these where we defined all other fill-ins for system headers. --- src/basic/missing.h | 5 +++++ src/libsystemd-network/lldp.h | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/missing.h b/src/basic/missing.h index f3d32362bd..44684e2dc8 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -1168,4 +1169,8 @@ static inline key_serial_t request_key(const char *type, const char *description #define char16_t uint16_t #endif +#ifndef ETHERTYPE_LLDP +#define ETHERTYPE_LLDP 0x88cc +#endif + #endif diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index d2c7164633..f881f490b4 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -22,8 +22,6 @@ #define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } -#define ETHERTYPE_LLDP 0x88cc - /* IEEE 802.3AB Clause 9: TLV Types */ typedef enum LLDPTypes { LLDP_TYPE_END = 0, -- cgit v1.2.3-54-g00ecf From 358977458b1253f5fc1a9e81ccf0056d50b8e1b4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 19:47:25 +0100 Subject: sd-lldp: simplify lldp_network_bind_raw_socket() a bit Let's constify the filter program, drop a few includes and structure definitions. --- src/libsystemd-network/lldp-network.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 7c865b46cb..c81ac6b893 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -22,62 +22,56 @@ #include #include "fd-util.h" -#include "lldp-internal.h" #include "lldp-network.h" -#include "lldp-tlv.h" #include "socket-util.h" int lldp_network_bind_raw_socket(int ifindex) { - typedef struct LLDPFrame { - struct ethhdr hdr; - uint8_t tlvs[0]; - } LLDPFrame; - struct sock_filter filter[] = { - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest)), /* A <- 4 bytes of destination MAC */ + static const struct sock_filter filter[] = { + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_proto)), /* A <- protocol */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */ }; - struct sock_fprog fprog = { + static const struct sock_fprog fprog = { .len = ELEMENTSOF(filter), - .filter = filter + .filter = (struct sock_filter*) filter, }; - _cleanup_close_ int s = -1; - union sockaddr_union saddrll = { .ll.sll_family = AF_PACKET, .ll.sll_ifindex = ifindex, }; + _cleanup_close_ int fd = -1; + int r; assert(ifindex > 0); - s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (s < 0) + fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (fd < 0) return -errno; - r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); + r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); if (r < 0) return -errno; - r = bind(s, &saddrll.sa, sizeof(saddrll.ll)); + r = bind(fd, &saddrll.sa, sizeof(saddrll.ll)); if (r < 0) return -errno; - r = s; - s = -1; + r = fd; + fd = -1; return r; } -- cgit v1.2.3-54-g00ecf From 0ef6f4542584873e10d5c942105ad0ffc53d6108 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 20:05:15 +0100 Subject: tree-wide: place #pragma once at the same place everywhere Usually, we place the #pragma once before the copyright blurb in header files, but in a few cases we didn't. Move those around, so that we do the same thing everywhere. --- src/analyze/analyze-verify.h | 4 ++-- src/basic/btrfs-util.h | 4 ++-- src/basic/gunicode.h | 4 ++-- src/basic/login-util.h | 4 ++-- src/basic/sigbus.h | 4 ++-- src/journal-remote/journal-remote-parse.h | 4 ++-- src/journal-remote/journal-remote-write.h | 5 ++--- src/journal-remote/journal-remote.h | 5 ++--- src/journal-remote/microhttpd-util.h | 4 ++-- src/libsystemd-network/dhcp-server-internal.h | 4 ++-- src/libsystemd-network/lldp-internal.h | 4 ++-- src/libsystemd-network/lldp-network.c | 1 - src/libsystemd-network/lldp-network.h | 4 ++-- src/libsystemd-network/lldp-tlv.h | 4 ++-- src/libsystemd-network/lldp.h | 4 ++-- src/libsystemd/sd-device/device-internal.h | 4 ++-- src/libsystemd/sd-hwdb/hwdb-internal.h | 3 ++- src/libudev/libudev-device-internal.h | 4 ++-- src/network/networkd-netdev-bridge.h | 4 ++-- src/network/networkd-netdev-dummy.h | 4 ++-- src/network/networkd-netdev-ipvlan.h | 4 ++-- src/network/networkd-netdev-macvlan.h | 4 ++-- src/network/networkd-netdev-tunnel.h | 4 ++-- src/network/networkd-netdev-tuntap.h | 4 ++-- src/network/networkd-netdev-veth.h | 4 ++-- src/network/networkd-netdev-vlan.h | 4 ++-- src/network/networkd-netdev-vxlan.h | 4 ++-- src/network/networkd-netdev.h | 4 ++-- src/network/networkd-wait-online.h | 4 ++-- src/network/networkd.h | 4 ++-- src/resolve/dns-type.h | 4 ++-- src/shared/dns-domain.h | 5 ++--- src/shared/gpt.h | 4 ++-- src/shared/install-printf.h | 4 ++-- src/shared/sleep-config.h | 4 ++-- src/udev/mtd_probe/mtd_probe.h | 4 ++-- src/udev/net/ethtool-util.h | 4 ++-- src/udev/net/link-config.h | 4 ++-- src/udev/scsi_id/scsi.h | 4 ++-- src/udev/scsi_id/scsi_id.h | 4 ++-- src/udev/udev.h | 4 ++-- src/udev/udevadm-util.h | 4 ++-- 42 files changed, 82 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h index 54adad93e1..27c253a562 100644 --- a/src/analyze/analyze-verify.h +++ b/src/analyze/analyze-verify.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "path-lookup.h" diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 37802c2565..1d852d502c 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include #include diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h index b03aa43160..5975bc8fc9 100644 --- a/src/basic/gunicode.h +++ b/src/basic/gunicode.h @@ -1,11 +1,11 @@ +#pragma once + /* gunicode.h - Unicode manipulation functions * * Copyright (C) 1999, 2000 Tom Tromey * Copyright 2000, 2005 Red Hat, Inc. */ -#pragma once - #include #include #include diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 89a337d7c1..b01ee25c88 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h index cce9eb201b..980243d9ce 100644 --- a/src/basic/sigbus.h +++ b/src/basic/sigbus.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - void sigbus_install(void); void sigbus_reset(void); diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 0b8b6af736..1740a21f92 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" #include "journal-remote-write.h" diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h index 6b645a353c..53ba45fc04 100644 --- a/src/journal-remote/journal-remote-write.h +++ b/src/journal-remote/journal-remote-write.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - - #include "journal-file.h" typedef struct RemoteServer RemoteServer; diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h index 6466a1c101..30ad7df996 100644 --- a/src/journal-remote/journal-remote.h +++ b/src/journal-remote/journal-remote.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - - #include "sd-event.h" #include "hashmap.h" diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index 70c4d29c0f..ea160f212b 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index bf123f1439..adb557167a 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-dhcp-server.h" #include "sd-event.h" diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 15b4a11b15..9122879e7e 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" #include "list.h" diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index c81ac6b893..10729e77b2 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -53,7 +53,6 @@ int lldp_network_bind_raw_socket(int ifindex) { }; _cleanup_close_ int fd = -1; - int r; assert(ifindex > 0); diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h index dcf31faa95..c4cf8c79f1 100644 --- a/src/libsystemd-network/lldp-network.h +++ b/src/libsystemd-network/lldp-network.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" int lldp_network_bind_raw_socket(int ifindex); diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index 8e7706c612..1ddca2882f 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "sd-lldp.h" diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index f881f490b4..88bef687eb 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } /* IEEE 802.3AB Clause 9: TLV Types */ diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index b96441de56..ab222e27de 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "hashmap.h" #include "set.h" diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h index 13fddfc8ad..8ffb5e5c74 100644 --- a/src/libsystemd/sd-hwdb/hwdb-internal.h +++ b/src/libsystemd/sd-hwdb/hwdb-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -16,7 +18,6 @@ You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ -#pragma once #include "sparse-endian.h" #include "util.h" diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h index 40d59201cf..0e9af8ec09 100644 --- a/src/libudev/libudev-device-internal.h +++ b/src/libudev/libudev-device-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "libudev.h" #include "sd-device.h" diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index b2bf7e15f1..27f26f7870 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Bridge Bridge; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h index 29f75a149b..42da62ebe4 100644 --- a/src/network/networkd-netdev-dummy.h +++ b/src/network/networkd-netdev-dummy.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Dummy Dummy; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h index 5b85ef2150..4bd0b67866 100644 --- a/src/network/networkd-netdev-ipvlan.h +++ b/src/network/networkd-netdev-ipvlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct IPVlan IPVlan; #include "missing.h" diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h index 8b42684de6..622ef9ef53 100644 --- a/src/network/networkd-netdev-macvlan.h +++ b/src/network/networkd-netdev-macvlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct MacVlan MacVlan; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index ea1d9a79e7..0d41f80a3c 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Tunnel Tunnel; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h index b970b0ce3b..cbb7ee05a6 100644 --- a/src/network/networkd-netdev-tuntap.h +++ b/src/network/networkd-netdev-tuntap.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct TunTap TunTap; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h index f7fdf906ab..ae5785783c 100644 --- a/src/network/networkd-netdev-veth.h +++ b/src/network/networkd-netdev-veth.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Veth Veth; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h index 8701c4b785..1de6a1cc36 100644 --- a/src/network/networkd-netdev-vlan.h +++ b/src/network/networkd-netdev-vlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct VLan VLan; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index 459ce53f5e..a4bb44635a 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct VxLan VxLan; #include "in-addr-util.h" diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 3eacee824b..7ea825fcb4 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "list.h" typedef struct NetDev NetDev; diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h index 421c2bdf44..f91995c306 100644 --- a/src/network/networkd-wait-online.h +++ b/src/network/networkd-wait-online.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" #include "sd-netlink.h" #include "sd-network.h" diff --git a/src/network/networkd.h b/src/network/networkd.h index 7ee922621a..6bdd8302a0 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "sd-bus.h" diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index db9666b970..7b79d29d7e 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "macro.h" /* DNS record types, taken from diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 2de3642cb3..af780f0b8b 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - - #include #include #include diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 52ab29ed5f..55b41bbcd8 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "sd-id128.h" diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index acf519f4f7..8a570fc265 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "install.h" int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret); diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h index 51f4621844..ad10039ff4 100644 --- a/src/shared/sleep-config.h +++ b/src/shared/sleep-config.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - int parse_sleep_config(const char *verb, char ***modes, char ***states); int can_sleep(const char *verb); diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h index caea5c2693..68e4954537 100644 --- a/src/udev/mtd_probe/mtd_probe.h +++ b/src/udev/mtd_probe/mtd_probe.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2010 - Maxim Levitsky * @@ -17,8 +19,6 @@ * Boston, MA 02110-1301 USA */ -#pragma once - #include #include "macro.h" diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h index 2e6e1d7150..7716516e76 100644 --- a/src/udev/net/ethtool-util.h +++ b/src/udev/net/ethtool-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include /* we can't use DUPLEX_ prefix, as it diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index f525fe2116..9df5529d05 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "libudev.h" #include "condition.h" diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h index 3bf1a94200..a27a84a40a 100644 --- a/src/udev/scsi_id/scsi.h +++ b/src/udev/scsi_id/scsi.h @@ -1,3 +1,5 @@ +#pragma once + /* * scsi.h * @@ -10,8 +12,6 @@ * Free Software Foundation version 2 of the License. */ -#pragma once - #include struct scsi_ioctl_command { diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h index 141b116a88..5c2e1c28ee 100644 --- a/src/udev/scsi_id/scsi_id.h +++ b/src/udev/scsi_id/scsi_id.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) IBM Corp. 2003 * @@ -15,8 +17,6 @@ * along with this program. If not, see . */ -#pragma once - #define MAX_PATH_LEN 512 /* diff --git a/src/udev/udev.h b/src/udev/udev.h index 1f9c8120c0..068713327d 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2003 Greg Kroah-Hartman * Copyright (C) 2003-2010 Kay Sievers @@ -16,8 +18,6 @@ * along with this program. If not, see . */ -#pragma once - #include #include diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h index 37e4fe8369..dc712b0d93 100644 --- a/src/udev/udevadm-util.h +++ b/src/udev/udevadm-util.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2014 Zbigniew Jędrzejewski-Szmek * @@ -15,8 +17,6 @@ * along with this program. If not, see . */ -#pragma once - #include "udev.h" struct udev_device *find_device(struct udev *udev, -- cgit v1.2.3-54-g00ecf From 7cde237777bb079787d436af253305bb08f0b066 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Feb 2016 22:45:22 +0100 Subject: sd-lldp: fix how we create the LLDP listening socket Specifiy the ethernet family, and make sure we se the O_CLOEXEC and O_NONBLOCK bits how we should for all fds. --- src/libsystemd-network/lldp-network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 10729e77b2..f031760351 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -57,7 +57,7 @@ int lldp_network_bind_raw_socket(int ifindex) { assert(ifindex > 0); - fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP)); if (fd < 0) return -errno; -- cgit v1.2.3-54-g00ecf From 1c4a6088ed13c449db16191890b20d20574e6ac0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Feb 2016 22:47:34 +0100 Subject: sd-netlink: fix ifi_iftype type The iftype is an unsigned short, and not just an unsigned. --- src/libsystemd/sd-netlink/rtnl-message.c | 2 +- src/network/networkctl.c | 8 ++++---- src/systemd/sd-netlink.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 090552f576..255526bf32 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -616,7 +616,7 @@ int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) { return 0; } -int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) { +int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) { struct ifinfomsg *ifi; assert_return(m, -EINVAL); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 60724fce80..185bdaf293 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -58,7 +58,7 @@ static void pager_open_if_enabled(void) { pager_open(false); } -static int link_get_type_string(int iftype, sd_device *d, char **ret) { +static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) { const char *t; char *p; @@ -106,7 +106,7 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) { typedef struct LinkInfo { const char *name; int ifindex; - unsigned iftype; + unsigned short iftype; } LinkInfo; static int link_info_compare(const void *a, const void *b) { @@ -123,7 +123,7 @@ static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { for (i = m; i; i = sd_netlink_message_next(i)) { const char *name; - unsigned iftype; + unsigned short iftype; uint16_t type; int ifindex; @@ -515,7 +515,7 @@ static int link_status_one( _cleanup_strv_free_ char **carrier_bound_to = NULL; _cleanup_strv_free_ char **carrier_bound_by = NULL; struct ether_addr e; - unsigned iftype; + unsigned short iftype; int r, ifindex; bool have_mac; uint32_t mtu; diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 71bcd24014..af7a797567 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -131,7 +131,7 @@ int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type); int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family); int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex); int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags); -int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type); +int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type); int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen); -- cgit v1.2.3-54-g00ecf From b710e6b68de13244f37fa5b05f894fcff81df4c6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Feb 2016 22:49:02 +0100 Subject: networkd: enable LLDP only on ethernet --- src/network/networkd-link.c | 21 ++++++++++++++------- src/network/networkd-link.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1711436b48..5f91f4c9c2 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -89,9 +89,14 @@ bool link_ipv6ll_enabled(Link *link) { } bool link_lldp_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; + if (link->iftype != ARPHRD_ETHER) + return false; + if (!link->network) return false; @@ -300,6 +305,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { uint16_t type; const char *ifname; int r, ifindex; + unsigned short iftype; assert(manager); assert(message); @@ -317,6 +323,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { else if (ifindex <= 0) return -EINVAL; + r = sd_rtnl_message_link_get_type(message, &iftype); + if (r < 0) + return r; + r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname); if (r < 0) return r; @@ -330,6 +340,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { link->state = LINK_STATE_PENDING; link->rtnl_extended_attrs = true; link->ifindex = ifindex; + link->iftype = iftype; link->ifname = strdup(ifname); if (!link->ifname) return -ENOMEM; @@ -338,22 +349,18 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { if (r < 0) log_link_debug(link, "MAC address not found for new device, continuing without"); - r = asprintf(&link->state_file, "/run/systemd/netif/links/%d", - link->ifindex); + r = asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex); if (r < 0) return -ENOMEM; - r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", - link->ifindex); + r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex); if (r < 0) return -ENOMEM; - r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", - link->ifindex); + r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex); if (r < 0) return -ENOMEM; - r = hashmap_ensure_allocated(&manager->links, NULL); if (r < 0) return r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 0e6a7b6f21..4b4ae712b6 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -65,6 +65,7 @@ struct Link { int ifindex; char *ifname; + unsigned short iftype; char *state_file; struct ether_addr mac; struct in6_addr ipv6ll_address; -- cgit v1.2.3-54-g00ecf From 36c7d7097b2967f6d8b799f94f5eab92f66c5462 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Feb 2016 22:49:48 +0100 Subject: networkd: fix logging of error codes --- src/network/networkd-link.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5f91f4c9c2..e63af3afdb 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -513,31 +513,31 @@ static int link_stop_clients(Link *link) { if (link->dhcp_client) { k = sd_dhcp_client_stop(link->dhcp_client); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m"); + r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m"); } if (link->ipv4ll) { k = sd_ipv4ll_stop(link->ipv4ll); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m"); + r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m"); } if (link->dhcp6_client) { k = sd_dhcp6_client_stop(link->dhcp6_client); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m"); + r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m"); } if (link->ndisc_router_discovery) { k = sd_ndisc_stop(link->ndisc_router_discovery); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m"); + r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } if (link->lldp) { k = sd_lldp_stop(link->lldp); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop LLDP: %m"); + r = log_link_warning_errno(link, k, "Could not stop LLDP: %m"); } return r; -- cgit v1.2.3-54-g00ecf From 1b4cd0cf11feb7d41f2eff17f86fa55b31bb6841 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Feb 2016 22:51:23 +0100 Subject: core: exclude .slice units from "systemctl isolate" Fixes: #1969 --- src/core/scope.c | 3 +-- src/core/slice.c | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/scope.c b/src/core/scope.c index c5d0ecef04..361695c3f9 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -50,8 +50,7 @@ static void scope_init(Unit *u) { assert(u->load_state == UNIT_STUB); s->timeout_stop_usec = u->manager->default_timeout_stop_usec; - - UNIT(s)->ignore_on_isolate = true; + u->ignore_on_isolate = true; } static void scope_done(Unit *u) { diff --git a/src/core/slice.c b/src/core/slice.c index d65364c6f4..667f61bde5 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -34,6 +34,13 @@ static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = { [SLICE_ACTIVE] = UNIT_ACTIVE }; +static void slice_init(Unit *u) { + assert(u); + assert(u->load_state == UNIT_STUB); + + u->ignore_on_isolate = true; +} + static void slice_set_state(Slice *t, SliceState state) { SliceState old_state; assert(t); @@ -305,6 +312,7 @@ const UnitVTable slice_vtable = { .no_instances = true, .can_transient = true, + .init = slice_init, .load = slice_load, .coldplug = slice_coldplug, -- cgit v1.2.3-54-g00ecf From a2daa2f075828630059bc28ceb40e29aef815e47 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 20 Feb 2016 19:10:38 -0500 Subject: time-util: check for overflow in conversion from ts to nsec_t CID #1320855. --- src/basic/time-util.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 130acaa9de..9bfd8f4f7a 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -139,8 +139,7 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us usec_t timespec_load(const struct timespec *ts) { assert(ts); - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) + if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) return USEC_INFINITY; if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) @@ -154,13 +153,13 @@ usec_t timespec_load(const struct timespec *ts) { static nsec_t timespec_load_nsec(const struct timespec *ts) { assert(ts); - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) + if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) return NSEC_INFINITY; - return - (nsec_t) ts->tv_sec * NSEC_PER_SEC + - (nsec_t) ts->tv_nsec; + if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC) + return NSEC_INFINITY; + + return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec; } struct timespec *timespec_store(struct timespec *ts, usec_t u) { -- cgit v1.2.3-54-g00ecf From bccfe92e4600632c6ef65ae8eda6ac7782a6aebf Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 20 Feb 2016 19:16:01 -0500 Subject: sd-device: use (void) before set_iterate calls set_iterate sets the output argument to NULL on error, and the return value is not used in this case. CID #1306804-09. --- src/libsystemd/sd-device/sd-device.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 9633e46ce0..fdd8c05e9c 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -1397,7 +1397,7 @@ _public_ const char *sd_device_get_tag_first(sd_device *device) { device->tags_iterator_generation = device->tags_generation; device->tags_iterator = ITERATOR_FIRST; - set_iterate(device->tags, &device->tags_iterator, &v); + (void) set_iterate(device->tags, &device->tags_iterator, &v); return v; } @@ -1411,7 +1411,7 @@ _public_ const char *sd_device_get_tag_next(sd_device *device) { if (device->tags_iterator_generation != device->tags_generation) return NULL; - set_iterate(device->tags, &device->tags_iterator, &v); + (void) set_iterate(device->tags, &device->tags_iterator, &v); return v; } @@ -1425,7 +1425,7 @@ _public_ const char *sd_device_get_devlink_first(sd_device *device) { device->devlinks_iterator_generation = device->devlinks_generation; device->devlinks_iterator = ITERATOR_FIRST; - set_iterate(device->devlinks, &device->devlinks_iterator, &v); + (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v); return v; } @@ -1439,7 +1439,7 @@ _public_ const char *sd_device_get_devlink_next(sd_device *device) { if (device->devlinks_iterator_generation != device->devlinks_generation) return NULL; - set_iterate(device->devlinks, &device->devlinks_iterator, &v); + (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v); return v; } @@ -1606,7 +1606,7 @@ _public_ const char *sd_device_get_sysattr_first(sd_device *device) { device->sysattrs_iterator = ITERATOR_FIRST; - set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); + (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); return v; } @@ -1618,7 +1618,7 @@ _public_ const char *sd_device_get_sysattr_next(sd_device *device) { if (!device->sysattrs_read) return NULL; - set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); + (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v); return v; } -- cgit v1.2.3-54-g00ecf From 4fd6af76c43e235d036dc55fbe1bf0c151b4e7dd Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 20 Feb 2016 20:09:34 -0500 Subject: udev-rules: log_oom() on memory error and abort processing of event CID #1313566. Also, change the return value to void, because it is ignored anyway. --- src/udev/udev-rules.c | 26 ++++++++++++++------------ src/udev/udev.h | 6 +++--- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index c06ace09cf..02efc08d2f 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -1010,8 +1010,8 @@ static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) { return 0; } -static int add_rule(struct udev_rules *rules, char *line, - const char *filename, unsigned int filename_off, unsigned int lineno) { +static void add_rule(struct udev_rules *rules, char *line, + const char *filename, unsigned int filename_off, unsigned int lineno) { char *linepos; const char *attr; struct rule_tmp rule_tmp = { @@ -1547,10 +1547,9 @@ static int add_rule(struct udev_rules *rules, char *line, if (sort_token(rules, &rule_tmp) != 0) goto invalid; - return 0; + return; invalid: log_error("invalid rule '%s:%u'", filename, lineno); - return -1; } static int parse_file(struct udev_rules *rules, const char *filename) { @@ -1849,18 +1848,18 @@ enum escape_type { ESCAPE_REPLACE, }; -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) { +void 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) { struct token *cur; struct token *rule; enum escape_type esc = ESCAPE_UNSET; bool can_set_name; if (rules->tokens == NULL) - return -1; + return; can_set_name = ((!streq(udev_device_get_action(event->dev), "remove")) && (major(udev_device_get_devnum(event->dev)) > 0 || @@ -2434,7 +2433,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); break; } - free_and_strdup(&event->name, name_str); + if (free_and_strdup(&event->name, name_str) < 0) { + log_oom(); + return; + } log_debug("NAME '%s' %s:%u", event->name, rules_str(rules, rule->rule.filename_off), @@ -2546,7 +2548,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, cur = &rules->tokens[cur->key.rule_goto]; continue; case TK_END: - return 0; + return; case TK_M_PARENTS_MIN: case TK_M_PARENTS_MAX: diff --git a/src/udev/udev.h b/src/udev/udev.h index 1f9c8120c0..655880346b 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -71,9 +71,9 @@ struct udev_rules; struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names); 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); +void 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); int udev_rules_apply_static_dev_perms(struct udev_rules *rules); /* udev-event.c */ -- cgit v1.2.3-54-g00ecf From 99f16bb8d9adf12fbfd2fbc7018fa02ce2c97187 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 20 Feb 2016 20:40:41 -0500 Subject: udev-rules: modernize syntax a bit --- src/udev/udev-rules.c | 173 ++++++++++++++++---------------------------------- 1 file changed, 54 insertions(+), 119 deletions(-) (limited to 'src') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 02efc08d2f..abfedfb613 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -1058,55 +1058,43 @@ static void add_rule(struct udev_rules *rules, char *line, goto invalid; } rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL); - continue; - } - if (streq(key, "DEVPATH")) { + } else if (streq(key, "DEVPATH")) { if (op > OP_MATCH_MAX) { log_error("invalid DEVPATH operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL); - continue; - } - if (streq(key, "KERNEL")) { + } else if (streq(key, "KERNEL")) { if (op > OP_MATCH_MAX) { log_error("invalid KERNEL operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL); - continue; - } - if (streq(key, "SUBSYSTEM")) { + } else if (streq(key, "SUBSYSTEM")) { if (op > OP_MATCH_MAX) { log_error("invalid SUBSYSTEM operation"); goto invalid; } /* bus, class, subsystem events should all be the same */ - if (streq(value, "subsystem") || - streq(value, "bus") || - streq(value, "class")) { - if (streq(value, "bus") || streq(value, "class")) - log_error("'%s' must be specified as 'subsystem' " - "please fix it in %s:%u", value, filename, lineno); + if (STR_IN_SET(value, "subsystem", "bus", "class")) { + if (!streq(value, "subsystem")) + log_error("'%s' must be specified as 'subsystem'; please fix it in %s:%u", + value, filename, lineno); rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); } else rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); - continue; - } - if (streq(key, "DRIVER")) { + } else if (streq(key, "DRIVER")) { if (op > OP_MATCH_MAX) { log_error("invalid DRIVER operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL); - continue; - } - if (startswith(key, "ATTR{")) { + } else if (startswith(key, "ATTR{")) { attr = get_key_attribute(rules->udev, key + strlen("ATTR")); if (attr == NULL) { log_error("error parsing ATTR attribute"); @@ -1120,10 +1108,8 @@ static void add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); else rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); - continue; - } - if (startswith(key, "SYSCTL{")) { + } else if (startswith(key, "SYSCTL{")) { attr = get_key_attribute(rules->udev, key + strlen("SYSCTL")); if (attr == NULL) { log_error("error parsing SYSCTL attribute"); @@ -1137,10 +1123,8 @@ static void add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); else rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); - continue; - } - if (startswith(key, "SECLABEL{")) { + } else if (startswith(key, "SECLABEL{")) { attr = get_key_attribute(rules->udev, key + strlen("SECLABEL")); if (!attr) { log_error("error parsing SECLABEL attribute"); @@ -1152,37 +1136,29 @@ static void add_rule(struct udev_rules *rules, char *line, } rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); - continue; - } - if (streq(key, "KERNELS")) { + } else if (streq(key, "KERNELS")) { if (op > OP_MATCH_MAX) { log_error("invalid KERNELS operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL); - continue; - } - if (streq(key, "SUBSYSTEMS")) { + } else if (streq(key, "SUBSYSTEMS")) { if (op > OP_MATCH_MAX) { log_error("invalid SUBSYSTEMS operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL); - continue; - } - if (streq(key, "DRIVERS")) { + } else if (streq(key, "DRIVERS")) { if (op > OP_MATCH_MAX) { log_error("invalid DRIVERS operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL); - continue; - } - if (startswith(key, "ATTRS{")) { + } else if (startswith(key, "ATTRS{")) { if (op > OP_MATCH_MAX) { log_error("invalid ATTRS operation"); goto invalid; @@ -1199,19 +1175,15 @@ static void add_rule(struct udev_rules *rules, char *line, log_error("do not reference parent sysfs directories directly, " "it may break with a future kernel, please fix it in %s:%u", filename, lineno); rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr); - continue; - } - if (streq(key, "TAGS")) { + } else if (streq(key, "TAGS")) { if (op > OP_MATCH_MAX) { log_error("invalid TAGS operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL); - continue; - } - if (startswith(key, "ENV{")) { + } else if (startswith(key, "ENV{")) { attr = get_key_attribute(rules->udev, key + strlen("ENV")); if (attr == NULL) { log_error("error parsing ENV attribute"); @@ -1225,60 +1197,46 @@ static void add_rule(struct udev_rules *rules, char *line, if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0) goto invalid; } else { - static const char *blacklist[] = { - "ACTION", - "SUBSYSTEM", - "DEVTYPE", - "MAJOR", - "MINOR", - "DRIVER", - "IFINDEX", - "DEVNAME", - "DEVLINKS", - "DEVPATH", - "TAGS", - }; - unsigned int i; - - for (i = 0; i < ELEMENTSOF(blacklist); i++) { - if (!streq(attr, blacklist[i])) - continue; + if (STR_IN_SET(attr, + "ACTION", + "SUBSYSTEM", + "DEVTYPE", + "MAJOR", + "MINOR", + "DRIVER", + "IFINDEX", + "DEVNAME", + "DEVLINKS", + "DEVPATH", + "TAGS")) { log_error("invalid ENV attribute, '%s' can not be set %s:%u", attr, filename, lineno); goto invalid; } if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0) goto invalid; } - continue; - } - if (streq(key, "TAG")) { + } else if (streq(key, "TAG")) { if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); else rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); - continue; - } - if (streq(key, "PROGRAM")) { + } else if (streq(key, "PROGRAM")) { if (op == OP_REMOVE) { log_error("invalid PROGRAM operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); - continue; - } - if (streq(key, "RESULT")) { + } else if (streq(key, "RESULT")) { if (op > OP_MATCH_MAX) { log_error("invalid RESULT operation"); goto invalid; } rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL); - continue; - } - if (startswith(key, "IMPORT")) { + } else if (startswith(key, "IMPORT")) { attr = get_key_attribute(rules->udev, key + strlen("IMPORT")); if (attr == NULL) { log_error("IMPORT{} type missing, ignoring IMPORT %s:%u", filename, lineno); @@ -1319,10 +1277,8 @@ static void add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); } else log_error("IMPORT{} unknown type, ignoring IMPORT %s:%u", filename, lineno); - continue; - } - if (startswith(key, "TEST")) { + } else if (startswith(key, "TEST")) { mode_t mode = 0; if (op > OP_MATCH_MAX) { @@ -1333,13 +1289,10 @@ static void add_rule(struct udev_rules *rules, char *line, if (attr != NULL) { mode = strtol(attr, NULL, 8); rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode); - } else { + } else rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL); - } - continue; - } - if (startswith(key, "RUN")) { + } else if (startswith(key, "RUN")) { attr = get_key_attribute(rules->udev, key + strlen("RUN")); if (attr == NULL) attr = "program"; @@ -1356,35 +1309,27 @@ static void add_rule(struct udev_rules *rules, char *line, else log_error("RUN{builtin}: '%s' unknown %s:%u", value, filename, lineno); } else if (streq(attr, "program")) { - enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX; + const enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX; rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); - } else { + } else log_error("RUN{} unknown type, ignoring RUN %s:%u", filename, lineno); - } - - continue; - } - if (streq(key, "LABEL")) { + } else if (streq(key, "LABEL")) { if (op == OP_REMOVE) { log_error("invalid LABEL operation"); goto invalid; } rule_tmp.rule.rule.label_off = rules_add_string(rules, value); - continue; - } - if (streq(key, "GOTO")) { + } else if (streq(key, "GOTO")) { if (op == OP_REMOVE) { log_error("invalid GOTO operation"); goto invalid; } rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); - continue; - } - if (startswith(key, "NAME")) { + } else if (startswith(key, "NAME")) { if (op == OP_REMOVE) { log_error("invalid NAME operation"); goto invalid; @@ -1405,10 +1350,8 @@ static void add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); } rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "SYMLINK")) { + } else if (streq(key, "SYMLINK")) { if (op == OP_REMOVE) { log_error("invalid SYMLINK operation"); goto invalid; @@ -1418,10 +1361,8 @@ static void add_rule(struct udev_rules *rules, char *line, else rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "OWNER")) { + } else if (streq(key, "OWNER")) { uid_t uid; char *endptr; @@ -1440,10 +1381,8 @@ static void add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "GROUP")) { + } else if (streq(key, "GROUP")) { gid_t gid; char *endptr; @@ -1462,10 +1401,8 @@ static void add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "MODE")) { + } else if (streq(key, "MODE")) { mode_t mode; char *endptr; @@ -1480,10 +1417,8 @@ static void add_rule(struct udev_rules *rules, char *line, else rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); rule_tmp.rule.rule.can_set_name = true; - continue; - } - if (streq(key, "OPTIONS")) { + } else if (streq(key, "OPTIONS")) { const char *pos; if (op == OP_REMOVE) { @@ -1531,11 +1466,10 @@ static void add_rule(struct udev_rules *rules, char *line, rule_tmp.rule.rule.has_static_node = true; } - continue; + } else { + log_error("unknown key '%s' in %s:%u", key, filename, lineno); + goto invalid; } - - log_error("unknown key '%s' in %s:%u", key, filename, lineno); - goto invalid; } /* add rule token */ @@ -2427,10 +2361,11 @@ void udev_rules_apply_to_event(struct udev_rules *rules, log_debug("%i character(s) replaced", count); } if (major(udev_device_get_devnum(event->dev)) && - (!streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/")))) { - log_error("NAME=\"%s\" ignored, kernel device nodes " - "can not be renamed; please fix it in %s:%u\n", name, - rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + !streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/"))) { + log_error("NAME=\"%s\" ignored, kernel device nodes cannot be renamed; please fix it in %s:%u\n", + name, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); break; } if (free_and_strdup(&event->name, name_str) < 0) { -- cgit v1.2.3-54-g00ecf From f4850a1d9593fd0f226e507c353ebdd46c069070 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 20 Feb 2016 23:00:45 -0500 Subject: udev-rules: rewrite function to avoid clobbering arguments If the attribute wasn't found, the last filename looked at was returned in the input/output argument. This just seems bad style. The return value was ignored, so change function to return void. --- src/udev/udev-rules.c | 49 ++++++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index abfedfb613..689da7451c 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -36,6 +36,7 @@ #include "glob-util.h" #include "path-util.h" #include "stat-util.h" +#include "stdio-util.h" #include "strbuf.h" #include "string-util.h" #include "strv.h" @@ -686,41 +687,31 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi return 0; } -static int attr_subst_subdir(char *attr, size_t len) { - bool found = false; +static void attr_subst_subdir(char *attr, size_t len) { + const char *pos, *tail, *path; + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *dent; - if (strstr(attr, "/*/")) { - char *pos; - char dirname[UTIL_PATH_SIZE]; - const char *tail; - DIR *dir; + pos = strstr(attr, "/*/"); + if (!pos) + return; - strscpy(dirname, sizeof(dirname), attr); - pos = strstr(dirname, "/*/"); - if (pos == NULL) - return -1; - pos[0] = '\0'; - tail = &pos[2]; - dir = opendir(dirname); - if (dir != NULL) { - struct dirent *dent; + tail = pos + 2; + path = strndupa(attr, pos - attr + 1); /* include slash at end */ + dir = opendir(path); + if (dir == NULL) + return; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - struct stat stats; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) + if (dent->d_name[0] != '.') { + char n[strlen(dent->d_name) + 1 + strlen(tail) + 1]; - if (dent->d_name[0] == '.') - continue; - strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL); - if (stat(attr, &stats) == 0) { - found = true; - break; - } + strscpyl(n, sizeof n, dent->d_name, "/", tail, NULL); + if (faccessat(dirfd(dir), n, F_OK, 0)) { + strscpyl(attr, len, path, n, NULL); + break; } - closedir(dir); } - } - - return found; } static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value) { -- cgit v1.2.3-54-g00ecf From 19a8e656a96d63c0b0047a84db980dd57ba51df2 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 21 Feb 2016 00:26:32 -0500 Subject: udev-rules: make error messages about rules more uniform Also downgrade non-fatal warnings to log_warning. Previously rule_add_key() would check the output array and log a cryptic error and return -1. Most of the time the return value was ignored. This does not seems right, because the buffer can overflow with enough rules. It would also check if we have enough space for the *next* rule, even if there might be not next rule, i.e. off-by-one. Replace this with a check that we have enough space for a next rule before we start parsing. Normally using macros to alter flow is not allowed, but in this case I think it is worth it, because it allows lots of boilerplate code to be removed and hides repeated boring parameters, making function logic much easier to follow. --- src/udev/udev-rules.c | 353 +++++++++++++++++++++----------------------------- 1 file changed, 150 insertions(+), 203 deletions(-) (limited to 'src') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 689da7451c..5c39c9b874 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -822,12 +822,13 @@ static const char *get_key_attribute(struct udev *udev, char *str) { return NULL; } -static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, - enum operation_type op, - const char *value, const void *data) { - struct token *token = &rule_tmp->token[rule_tmp->token_cur]; +static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, + enum operation_type op, + const char *value, const void *data) { + struct token *token = rule_tmp->token + rule_tmp->token_cur; const char *attr = NULL; + assert(rule_tmp->token_cur < ELEMENTSOF(rule_tmp->token)); memzero(token, sizeof(struct token)); switch (type) { @@ -910,8 +911,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_M_MAX: case TK_END: case TK_UNSET: - log_error("wrong type %u", type); - return -1; + assert_not_reached("wrong type"); } if (value != NULL && type < TK_M_MAX) { @@ -960,11 +960,6 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, token->key.type = type; token->key.op = op; rule_tmp->token_cur++; - if (rule_tmp->token_cur >= ELEMENTSOF(rule_tmp->token)) { - log_error("temporary rule array too small"); - return -1; - } - return 0; } static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) { @@ -1001,6 +996,11 @@ static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) { return 0; } +#define LOG_RULE_ERROR(fmt, ...) log_error("Invalid rule %s:%u: " fmt, filename, lineno, ##__VA_ARGS__) +#define LOG_RULE_WARNING(fmt, ...) log_warning("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__) +#define LOG_RULE_DEBUG(fmt, ...) log_debug("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__) +#define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; } + static void add_rule(struct udev_rules *rules, char *line, const char *filename, unsigned int filename_off, unsigned int lineno) { char *linepos; @@ -1043,58 +1043,54 @@ static void add_rule(struct udev_rules *rules, char *line, break; } + if (rule_tmp.token_cur >= ELEMENTSOF(rule_tmp.token)) + LOG_AND_RETURN("temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur); + if (streq(key, "ACTION")) { - if (op > OP_MATCH_MAX) { - log_error("invalid ACTION operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL); } else if (streq(key, "DEVPATH")) { - if (op > OP_MATCH_MAX) { - log_error("invalid DEVPATH operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL); } else if (streq(key, "KERNEL")) { - if (op > OP_MATCH_MAX) { - log_error("invalid KERNEL operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL); } else if (streq(key, "SUBSYSTEM")) { - if (op > OP_MATCH_MAX) { - log_error("invalid SUBSYSTEM operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + /* bus, class, subsystem events should all be the same */ if (STR_IN_SET(value, "subsystem", "bus", "class")) { if (!streq(value, "subsystem")) - log_error("'%s' must be specified as 'subsystem'; please fix it in %s:%u", - value, filename, lineno); + LOG_RULE_WARNING("'%s' must be specified as 'subsystem'; please fix", value); + rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL); } else rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL); } else if (streq(key, "DRIVER")) { - if (op > OP_MATCH_MAX) { - log_error("invalid DRIVER operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL); } else if (startswith(key, "ATTR{")) { attr = get_key_attribute(rules->udev, key + strlen("ATTR")); - if (attr == NULL) { - log_error("error parsing ATTR attribute"); - goto invalid; - } - if (op == OP_REMOVE) { - log_error("invalid ATTR operation"); - goto invalid; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ATTR"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "ATTR"); + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); else @@ -1102,14 +1098,12 @@ static void add_rule(struct udev_rules *rules, char *line, } else 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 (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ATTR"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "ATTR"); + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); else @@ -1117,77 +1111,63 @@ static void add_rule(struct udev_rules *rules, char *line, } else if (startswith(key, "SECLABEL{")) { attr = get_key_attribute(rules->udev, key + strlen("SECLABEL")); - if (!attr) { - log_error("error parsing SECLABEL attribute"); - goto invalid; - } - if (op == OP_REMOVE) { - log_error("invalid SECLABEL operation"); - goto invalid; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "SECLABEL"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "SECLABEL"); rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); } else if (streq(key, "KERNELS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid KERNELS operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL); } else if (streq(key, "SUBSYSTEMS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid SUBSYSTEMS operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL); } else if (streq(key, "DRIVERS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid DRIVERS operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL); } else if (startswith(key, "ATTRS{")) { - if (op > OP_MATCH_MAX) { - log_error("invalid ATTRS operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", "ATTRS"); + attr = get_key_attribute(rules->udev, key + strlen("ATTRS")); - if (attr == NULL) { - log_error("error parsing ATTRS attribute"); - goto invalid; - } + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ATTRS"); + if (startswith(attr, "device/")) - log_error("the 'device' link may not be available in a future kernel, " - "please fix it in %s:%u", filename, lineno); - else if (strstr(attr, "../") != NULL) - log_error("do not reference parent sysfs directories directly, " - "it may break with a future kernel, please fix it in %s:%u", filename, lineno); + LOG_RULE_WARNING("'device' link may not be available in future kernels; please fix"); + if (strstr(attr, "../") != NULL) + LOG_RULE_WARNING("direct reference to parent sysfs directory, may break in future kernels; please fix"); rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr); } else if (streq(key, "TAGS")) { - if (op > OP_MATCH_MAX) { - log_error("invalid TAGS operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL); } else if (startswith(key, "ENV{")) { attr = get_key_attribute(rules->udev, key + strlen("ENV")); - if (attr == NULL) { - log_error("error parsing ENV attribute"); - goto invalid; - } - if (op == OP_REMOVE) { - log_error("invalid ENV operation"); - goto invalid; - } - if (op < OP_MATCH_MAX) { - if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0) - goto invalid; - } else { + if (attr == NULL) + LOG_AND_RETURN("error parsing %s attribute", "ENV"); + + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "ENV"); + + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr); + else { if (STR_IN_SET(attr, "ACTION", "SUBSYSTEM", @@ -1199,12 +1179,10 @@ static void add_rule(struct udev_rules *rules, char *line, "DEVNAME", "DEVLINKS", "DEVPATH", - "TAGS")) { - log_error("invalid ENV attribute, '%s' can not be set %s:%u", attr, filename, lineno); - goto invalid; - } - if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0) - goto invalid; + "TAGS")) + LOG_AND_RETURN("invalid ENV attribute, '%s' cannot be set", attr); + + rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr); } } else if (streq(key, "TAG")) { @@ -1214,68 +1192,62 @@ static void add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); } else if (streq(key, "PROGRAM")) { - if (op == OP_REMOVE) { - log_error("invalid PROGRAM operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); } else if (streq(key, "RESULT")) { - if (op > OP_MATCH_MAX) { - log_error("invalid RESULT operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL); } else if (startswith(key, "IMPORT")) { attr = get_key_attribute(rules->udev, key + strlen("IMPORT")); if (attr == NULL) { - log_error("IMPORT{} type missing, ignoring IMPORT %s:%u", filename, lineno); + LOG_RULE_WARNING("ignoring IMPORT{} with missing type"); continue; } - if (op == OP_REMOVE) { - log_error("invalid IMPORT operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "IMPORT"); + if (streq(attr, "program")) { /* find known built-in command */ if (value[0] != '/') { - enum udev_builtin_cmd cmd; + const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - cmd = udev_builtin_lookup(value); if (cmd < UDEV_BUILTIN_MAX) { - log_debug("IMPORT found builtin '%s', replacing %s:%u", - value, filename, lineno); + LOG_RULE_DEBUG("IMPORT found builtin '%s', replacing", value); rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); continue; } } rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); } else if (streq(attr, "builtin")) { - enum udev_builtin_cmd cmd = udev_builtin_lookup(value); + const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); - if (cmd < UDEV_BUILTIN_MAX) - rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + if (cmd >= UDEV_BUILTIN_MAX) + LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown", value); else - log_error("IMPORT{builtin}: '%s' unknown %s:%u", value, filename, lineno); - } else if (streq(attr, "file")) { + rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd); + } else if (streq(attr, "file")) rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL); - } else if (streq(attr, "db")) { + else if (streq(attr, "db")) rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL); - } else if (streq(attr, "cmdline")) { + else if (streq(attr, "cmdline")) rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL); - } else if (streq(attr, "parent")) { + else if (streq(attr, "parent")) rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL); - } else - log_error("IMPORT{} unknown type, ignoring IMPORT %s:%u", filename, lineno); + else + LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "IMPORT", attr); } else if (startswith(key, "TEST")) { mode_t mode = 0; - if (op > OP_MATCH_MAX) { - log_error("invalid TEST operation"); - goto invalid; - } + if (op > OP_MATCH_MAX) + LOG_AND_RETURN("invalid %s operation", "TEST"); + attr = get_key_attribute(rules->udev, key + strlen("TEST")); if (attr != NULL) { mode = strtol(attr, NULL, 8); @@ -1287,55 +1259,48 @@ static void add_rule(struct udev_rules *rules, char *line, attr = get_key_attribute(rules->udev, key + strlen("RUN")); if (attr == NULL) attr = "program"; - if (op == OP_REMOVE) { - log_error("invalid RUN operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", "RUN"); if (streq(attr, "builtin")) { - enum udev_builtin_cmd cmd = udev_builtin_lookup(value); + const enum udev_builtin_cmd cmd = udev_builtin_lookup(value); if (cmd < UDEV_BUILTIN_MAX) rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd); else - log_error("RUN{builtin}: '%s' unknown %s:%u", value, filename, lineno); + LOG_RULE_ERROR("RUN{builtin}: '%s' unknown", value); } else if (streq(attr, "program")) { const enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX; rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd); } else - log_error("RUN{} unknown type, ignoring RUN %s:%u", filename, lineno); + LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "RUN", attr); } else if (streq(key, "LABEL")) { - if (op == OP_REMOVE) { - log_error("invalid LABEL operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + rule_tmp.rule.rule.label_off = rules_add_string(rules, value); } else if (streq(key, "GOTO")) { - if (op == OP_REMOVE) { - log_error("invalid GOTO operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); } else if (startswith(key, "NAME")) { - if (op == OP_REMOVE) { - log_error("invalid NAME operation"); - goto invalid; - } - if (op < OP_MATCH_MAX) { + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); - } else { + else { if (streq(value, "%k")) { - log_error("NAME=\"%%k\" is ignored, because it breaks kernel supplied names, " - "please remove it from %s:%u\n", filename, lineno); + LOG_RULE_WARNING("NAME=\"%%k\" is ignored, because it breaks kernel supplied names; please remove"); continue; } - if (value[0] == '\0') { - log_debug("NAME=\"\" is ignored, because udev will not delete any device nodes, " - "please remove it from %s:%u\n", filename, lineno); + if (isempty(value)) { + LOG_RULE_DEBUG("NAME=\"\" is ignored, because udev will not delete any device nodes; please remove"); continue; } rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); @@ -1343,10 +1308,9 @@ static void add_rule(struct udev_rules *rules, char *line, rule_tmp.rule.rule.can_set_name = true; } else if (streq(key, "SYMLINK")) { - if (op == OP_REMOVE) { - log_error("invalid SYMLINK operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); else @@ -1357,15 +1321,13 @@ static void add_rule(struct udev_rules *rules, char *line, uid_t uid; char *endptr; - if (op == OP_REMOVE) { - log_error("invalid OWNER operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); uid = strtoul(value, &endptr, 10); - if (endptr[0] == '\0') { + if (endptr[0] == '\0') rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); - } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { + else if (rules->resolve_names > 0 && strchr("$%", value[0]) == NULL) { uid = add_uid(rules, value); rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); } else if (rules->resolve_names >= 0) @@ -1377,15 +1339,13 @@ static void add_rule(struct udev_rules *rules, char *line, gid_t gid; char *endptr; - if (op == OP_REMOVE) { - log_error("invalid GROUP operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); gid = strtoul(value, &endptr, 10); - if (endptr[0] == '\0') { + if (endptr[0] == '\0') rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); - } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { + else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { gid = add_gid(rules, value); rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); } else if (rules->resolve_names >= 0) @@ -1397,10 +1357,8 @@ static void add_rule(struct udev_rules *rules, char *line, mode_t mode; char *endptr; - if (op == OP_REMOVE) { - log_error("invalid MODE operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); mode = strtol(value, &endptr, 8); if (endptr[0] == '\0') @@ -1412,21 +1370,19 @@ static void add_rule(struct udev_rules *rules, char *line, } else if (streq(key, "OPTIONS")) { const char *pos; - if (op == OP_REMOVE) { - log_error("invalid OPTIONS operation"); - goto invalid; - } + if (op == OP_REMOVE) + LOG_AND_RETURN("invalid %s operation", key); pos = strstr(value, "link_priority="); if (pos != NULL) { - int prio = atoi(&pos[strlen("link_priority=")]); + int prio = atoi(pos + strlen("link_priority=")); rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio); } pos = strstr(value, "string_escape="); if (pos != NULL) { - pos = &pos[strlen("string_escape=")]; + pos += strlen("string_escape="); if (startswith(pos, "none")) rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); else if (startswith(pos, "replace")) @@ -1453,28 +1409,19 @@ static void add_rule(struct udev_rules *rules, char *line, pos = strstr(value, "static_node="); if (pos != NULL) { - rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL); + pos += strlen("static_node="); + rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL); rule_tmp.rule.rule.has_static_node = true; } - } else { - log_error("unknown key '%s' in %s:%u", key, filename, lineno); - goto invalid; - } + } else + LOG_AND_RETURN("unknown key '%s'", key); } - /* add rule token */ + /* add rule token and sort tokens */ rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur; - if (add_token(rules, &rule_tmp.rule) != 0) - goto invalid; - - /* add tokens to list, sorted by type */ - if (sort_token(rules, &rule_tmp) != 0) - goto invalid; - - return; -invalid: - log_error("invalid rule '%s:%u'", filename, lineno); + if (add_token(rules, &rule_tmp.rule) != 0 || sort_token(rules, &rule_tmp) != 0) + LOG_RULE_ERROR("failed to add rule token"); } static int parse_file(struct udev_rules *rules, const char *filename) { -- cgit v1.2.3-54-g00ecf From fdd21be6f5f0360c4627bcf5a7957e69ad08be74 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 21 Feb 2016 10:04:36 -0500 Subject: udev-rules: use _cleanup_ for fclose --- src/udev/udev-rules.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 5c39c9b874..8470456d4c 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -33,6 +33,7 @@ #include "conf-files.h" #include "escape.h" #include "fd-util.h" +#include "fs-util.h" #include "glob-util.h" #include "path-util.h" #include "stat-util.h" @@ -2039,7 +2040,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules, break; } case TK_M_IMPORT_CMDLINE: { - FILE *f; + _cleanup_fclose_ FILE *f = NULL; bool imported = false; f = fopen("/proc/cmdline", "re"); @@ -2052,12 +2053,12 @@ void udev_rules_apply_to_event(struct udev_rules *rules, pos = strstr(cmdline, key); if (pos != NULL) { + imported = true; pos += strlen(key); - if (pos[0] == '\0' || isspace(pos[0])) { + if (pos[0] == '\0' || isspace(pos[0])) /* we import simple flags as 'FLAG=1' */ udev_device_add_property(event->dev, key, "1"); - imported = true; - } else if (pos[0] == '=') { + else if (pos[0] == '=') { const char *value; pos++; @@ -2066,11 +2067,9 @@ void udev_rules_apply_to_event(struct udev_rules *rules, pos++; pos[0] = '\0'; udev_device_add_property(event->dev, key, value); - imported = true; } } } - fclose(f); } if (!imported && cur->key.op != OP_NOMATCH) goto nomatch; @@ -2366,7 +2365,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules, const char *key_name = rules_str(rules, cur->key.attr_off); char attr[UTIL_PATH_SIZE]; char value[UTIL_NAME_SIZE]; - FILE *f; + _cleanup_fclose_ FILE *f = NULL; if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0) strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL); @@ -2377,13 +2376,10 @@ void udev_rules_apply_to_event(struct udev_rules *rules, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); f = fopen(attr, "we"); - if (f != NULL) { - if (fprintf(f, "%s", value) <= 0) - log_error_errno(errno, "error writing ATTR{%s}: %m", attr); - fclose(f); - } else { + if (f == NULL) log_error_errno(errno, "error opening ATTR{%s} for writing: %m", attr); - } + else if (fprintf(f, "%s", value) <= 0) + log_error_errno(errno, "error writing ATTR{%s}: %m", attr); break; } case TK_A_SYSCTL: { @@ -2449,7 +2445,7 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) { char **t; FILE *f = NULL; _cleanup_free_ char *path = NULL; - int r = 0; + int r; if (rules->tokens == NULL) return 0; @@ -2520,8 +2516,6 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) { if (r < 0 && errno != EEXIST) return log_error_errno(errno, "failed to create symlink %s -> %s: %m", tag_symlink, device_node); - else - r = 0; } } @@ -2573,12 +2567,11 @@ finish: fflush(f); fchmod(fileno(f), 0644); if (ferror(f) || rename(path, "/run/udev/static_node-tags") < 0) { - r = -errno; - unlink("/run/udev/static_node-tags"); - unlink(path); + unlink_noerrno("/run/udev/static_node-tags"); + unlink_noerrno(path); + return -errno; } - fclose(f); } - return r; + return 0; } -- cgit v1.2.3-54-g00ecf From 34437b4f9c9c51b0a6f93788bdb9a105b8e46b66 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 17:58:52 +0100 Subject: sd-lldp: rework sd-lldp API This reworks the sd-lldp substantially, simplifying things on one hand, and extending the logic a bit on the other. Specifically: - Besides the sd_lldp object only one other object is maintained now, sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for maintainging info about peers in the database. Separation between packet, TLV and chassis data is not maintained anymore. This should be a major simplification. - The sd-lldp API has been extended so that a couple of per-neighbor fields may be queried directly, without iterating through the object. Other fields that may appear multiple times, OTOH have to be iterated through. - The maximum number of entries in the neighbor database is now configurable during runtime. - The generation of callbacks from sd_lldp objects is more restricted: callbacks are only invoked when actual data changed. - The TTL information is now hooked with a timer event, so that removals from the neighbor database due to TTLs now result in a callback event. - Querying LLDP neighbor database will now return a strictly ordered array, to guarantee stability. - A "capabilities" mask may now be configured, that selects what type of LLDP neighbor data is collected. This may be used to restrict collection of LLDP info about routers instead of all neighbors. This is now exposed via networkd's LLDP= setting. - sd-lldp's API to serialize the collected data to text files has been removed. Instead, there's now an API to extract the raw binary data from LLDP neighbor objects, as well as one to convert this raw binary data back to an LLDP neighbor object. networkd will save this raw binary data to /run now, and the client side can simply parse the information. - support for parsing the more exotic TLVs has been removed, since we are not using that. Instead there are now APIs to extract the raw data from TLVs. Given how easy it is to parse the TLVs clients should do so now directly instead of relying on our APIs for that. - A lot of the APIs that parse out LLDP strings have been simplified so that they actually return strings, instead of char arrays with a length. To deal with possibly dangerous characters the strings are escaped if needed. - APIs to extract and format the chassis and port IDs as strings has been added. - lldp.h has been simplified a lot. The enums are anonymous now, since they were never used as enums, but simply as constants. Most definitions we don't actually use ourselves have eben removed. --- Makefile.am | 9 +- man/systemd.network.xml | 8 +- src/libsystemd-network/lldp-internal.c | 360 -------------- src/libsystemd-network/lldp-internal.h | 74 +-- src/libsystemd-network/lldp-neighbor.c | 792 +++++++++++++++++++++++++++++++ src/libsystemd-network/lldp-neighbor.h | 106 +++++ src/libsystemd-network/lldp-tlv.c | 638 ------------------------- src/libsystemd-network/lldp-tlv.h | 94 ---- src/libsystemd-network/lldp.h | 78 ++- src/libsystemd-network/sd-lldp.c | 731 ++++++++++------------------ src/libsystemd-network/test-lldp.c | 320 +++---------- src/libsystemd/sd-network/sd-network.c | 27 +- src/network/networkctl.c | 293 ++++-------- src/network/networkd-link.c | 124 +++-- src/network/networkd-network-gperf.gperf | 2 +- src/network/networkd-network.c | 10 + src/network/networkd-network.h | 14 +- src/systemd/sd-lldp.h | 76 +-- src/systemd/sd-network.h | 2 - 19 files changed, 1491 insertions(+), 2267 deletions(-) delete mode 100644 src/libsystemd-network/lldp-internal.c create mode 100644 src/libsystemd-network/lldp-neighbor.c create mode 100644 src/libsystemd-network/lldp-neighbor.h delete mode 100644 src/libsystemd-network/lldp-tlv.c delete mode 100644 src/libsystemd-network/lldp-tlv.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 06ca3532b4..70fcedf0da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3299,12 +3299,10 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/dhcp-identifier.h \ src/libsystemd-network/dhcp-identifier.c \ src/libsystemd-network/lldp.h \ - src/libsystemd-network/lldp-tlv.h \ - src/libsystemd-network/lldp-tlv.c \ src/libsystemd-network/lldp-network.h \ src/libsystemd-network/lldp-network.c \ - src/libsystemd-network/lldp-internal.h \ - src/libsystemd-network/lldp-internal.c \ + src/libsystemd-network/lldp-neighbor.h \ + src/libsystemd-network/lldp-neighbor.c \ src/libsystemd-network/sd-lldp.c libsystemd_network_la_LIBADD = \ @@ -3387,9 +3385,6 @@ test_dhcp6_client_LDADD = \ libshared.la test_lldp_SOURCES = \ - src/libsystemd-network/lldp.h \ - src/libsystemd-network/lldp-tlv.h \ - src/libsystemd-network/lldp-tlv.c \ src/libsystemd-network/test-lldp.c test_lldp_LDADD = \ diff --git a/man/systemd.network.xml b/man/systemd.network.xml index adfe1ac9b3..2de2a550db 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -335,7 +335,13 @@ LLDP= - A boolean. When true, enables LLDP link receive support. + Controls support for LLDP reception. Accepts a boolean or the special value + routers-only. When true, incoming LLDP packets are accepted and a database of all LLDP + neighbors maintained. If routers-only is set only LLDP data of various types of routers + is collected and LLDP data about other types of devices ignored (such as stations, telephones and + others). If false, LLDP reception is disabled. Defaults to false. Use + networkctl1 to query the + collected neighbor data. diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c deleted file mode 100644 index c8740ce5f0..0000000000 --- a/src/libsystemd-network/lldp-internal.c +++ /dev/null @@ -1,360 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - 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 . -***/ - -#include "sd-lldp.h" - -#include "alloc-util.h" -#include "lldp-internal.h" - -/* We store maximum 1K chassis entries */ -#define LLDP_MIB_MAX_CHASSIS 1024 - -/* Maximum Ports can be attached to any chassis */ -#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32 - -/* 10.5.5.2.2 mibUpdateObjects () - * The mibUpdateObjects () procedure updates the MIB objects corresponding to - * the TLVs contained in the received LLDPDU for the LLDP remote system - * indicated by the LLDP remote systems update process defined in 10.3.5 */ - -int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - /* Update the packet if we already have */ - LIST_FOREACH(port, p, c->ports) { - - if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) { - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - sd_lldp_packet_unref(p->packet); - p->packet = tlv; - - prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); - - return 0; - } - } - - return -1; -} - -int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p, *q; - uint8_t *data; - uint16_t length; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - LIST_FOREACH_SAFE(port, p, q, c->ports) { - - /* Find the port */ - if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) { - lldp_neighbour_port_remove_and_free(p); - break; - } - } - - return 0; -} - -int lldp_mib_add_objects(Prioq *by_expiry, - Hashmap *neighbour_mib, - tlv_packet *tlv) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - lldp_chassis_id chassis_id; - bool new_chassis = false; - uint8_t subtype, *data; - uint16_t ttl, length; - int r; - - assert_return(by_expiry, -EINVAL); - assert_return(neighbour_mib, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length); - if (r < 0) - goto drop; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - goto drop; - - /* Make hash key */ - chassis_id.type = subtype; - chassis_id.length = length; - chassis_id.data = data; - - /* Try to find the Chassis */ - c = hashmap_get(neighbour_mib, &chassis_id); - if (!c) { - - /* Don't create chassis if ttl 0 is received . Silently drop it */ - if (ttl == 0) { - log_lldp("TTL value 0 received. Skiping Chassis creation."); - goto drop; - } - - /* Admission Control: Can we store this packet ? */ - if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) { - - log_lldp("Exceeding number of chassie: %d. Dropping ...", - hashmap_size(neighbour_mib)); - goto drop; - } - - r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c); - if (r < 0) - goto drop; - - new_chassis = true; - - r = hashmap_put(neighbour_mib, &c->chassis_id, c); - if (r < 0) - goto drop; - - } else { - - /* When the TTL field is set to zero, the receiving LLDP agent is notified all - * system information associated with the LLDP agent/port is to be deleted */ - if (ttl == 0) { - log_lldp("TTL value 0 received . Deleting associated Port ..."); - - lldp_mib_remove_objects(c, tlv); - - c = NULL; - goto drop; - } - - /* if we already have this port just update it */ - r = lldp_mib_update_objects(c, tlv); - if (r >= 0) { - c = NULL; - return r; - } - - /* Admission Control: Can this port attached to the existing chassis ? */ - if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) { - log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref); - - c = NULL; - goto drop; - } - } - - /* This is a new port */ - r = lldp_neighbour_port_new(c, tlv, &p); - if (r < 0) - goto drop; - - r = prioq_put(c->by_expiry, p, &p->prioq_idx); - if (r < 0) - goto drop; - - /* Attach new port to chassis */ - LIST_PREPEND(port, c->ports, p); - c->n_ref ++; - - p = NULL; - c = NULL; - - return 0; - - drop: - sd_lldp_packet_unref(tlv); - - if (new_chassis) - hashmap_remove(neighbour_mib, &c->chassis_id); - - return r; -} - -void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) { - lldp_chassis *c; - - assert(p); - assert(p->c); - - c = p->c; - - prioq_remove(c->by_expiry, p, &p->prioq_idx); - - LIST_REMOVE(port, c->ports, p); - lldp_neighbour_port_free(p); - - /* Drop the Chassis if no port is attached */ - c->n_ref --; - if (c->n_ref <= 1) { - hashmap_remove(c->neighbour_mib, &c->chassis_id); - lldp_chassis_free(c); - } -} - -void lldp_neighbour_port_free(lldp_neighbour_port *p) { - - if(!p) - return; - - sd_lldp_packet_unref(p->packet); - - free(p->data); - free(p); -} - -int lldp_neighbour_port_new(lldp_chassis *c, - tlv_packet *tlv, - lldp_neighbour_port **ret) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p = new0(lldp_neighbour_port, 1); - if (!p) - return -ENOMEM; - - p->c = c; - p->type = type; - p->length = length; - p->packet = tlv; - p->prioq_idx = PRIOQ_IDX_NULL; - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - p->data = memdup(data, length); - if (!p->data) - return -ENOMEM; - - *ret = p; - p = NULL; - - return 0; -} - -void lldp_chassis_free(lldp_chassis *c) { - - if (!c) - return; - - if (c->n_ref > 1) - return; - - free(c->chassis_id.data); - free(c); -} - -int lldp_chassis_new(tlv_packet *tlv, - Prioq *by_expiry, - Hashmap *neighbour_mib, - lldp_chassis **ret) { - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - uint16_t length; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - c = new0(lldp_chassis, 1); - if (!c) - return -ENOMEM; - - c->n_ref = 1; - c->chassis_id.type = type; - c->chassis_id.length = length; - - c->chassis_id.data = memdup(data, length); - if (!c->chassis_id.data) - return -ENOMEM; - - LIST_HEAD_INIT(c->ports); - - c->by_expiry = by_expiry; - c->neighbour_mib = neighbour_mib; - - *ret = c; - c = NULL; - - return 0; -} - -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL; - tlv_packet *p; - uint16_t length; - int r; - - assert(fd); - assert(userdata); - - r = tlv_packet_new(&packet); - if (r < 0) - return r; - - length = read(fd, &packet->pdu, sizeof(packet->pdu)); - - /* Silently drop the packet */ - if ((size_t) length > ETHER_MAX_LEN) - return 0; - - packet->userdata = userdata; - - p = packet; - packet = NULL; - - return lldp_handle_packet(p, (uint16_t) length); -} diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 9122879e7e..279975b5c2 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -21,71 +21,31 @@ ***/ #include "sd-event.h" +#include "sd-lldp.h" -#include "list.h" -#include "lldp-tlv.h" +#include "hashmap.h" #include "log.h" #include "prioq.h" -typedef struct lldp_neighbour_port lldp_neighbour_port; -typedef struct lldp_chassis lldp_chassis; -typedef struct lldp_chassis_id lldp_chassis_id; -typedef struct lldp_agent_statistics lldp_agent_statistics; +struct sd_lldp { + int ifindex; + int fd; -struct lldp_neighbour_port { - uint8_t type; - uint8_t *data; + sd_event *event; + int64_t event_priority; + sd_event_source *io_event_source; + sd_event_source *timer_event_source; - uint16_t length; - usec_t until; + Prioq *neighbor_by_expiry; + Hashmap *neighbor_by_id; - unsigned prioq_idx; + uint64_t neighbors_max; - lldp_chassis *c; - tlv_packet *packet; + sd_lldp_callback_t callback; + void *userdata; - LIST_FIELDS(lldp_neighbour_port, port); + uint16_t capability_mask; }; -int lldp_neighbour_port_new(lldp_chassis *c, tlv_packet *tlv, lldp_neighbour_port **ret); -void lldp_neighbour_port_free(lldp_neighbour_port *p); -void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_neighbour_port *, lldp_neighbour_port_free); -#define _cleanup_lldp_neighbour_port_free_ _cleanup_(lldp_neighbour_port_freep) - -struct lldp_chassis_id { - uint8_t type; - uint16_t length; - - uint8_t *data; -}; - -struct lldp_chassis { - unsigned n_ref; - - lldp_chassis_id chassis_id; - - Prioq *by_expiry; - Hashmap *neighbour_mib; - - LIST_HEAD(lldp_neighbour_port, ports); -}; - -int lldp_chassis_new(tlv_packet *tlv, - Prioq *by_expiry, - Hashmap *neighbour_mib, - lldp_chassis **ret); - -void lldp_chassis_free(lldp_chassis *c); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_chassis *, lldp_chassis_free); -#define _cleanup_lldp_chassis_free_ _cleanup_(lldp_chassis_freep) - -int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv); -int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv); -int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv); - -int lldp_handle_packet(tlv_packet *m, uint16_t length); -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata); -#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) +#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) +#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c new file mode 100644 index 0000000000..c61941cd70 --- /dev/null +++ b/src/libsystemd-network/lldp-neighbor.c @@ -0,0 +1,792 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "ether-addr-util.h" +#include "hexdecoct.h" +#include "in-addr-util.h" +#include "lldp-internal.h" +#include "lldp-neighbor.h" +#include "lldp.h" +#include "unaligned.h" + +static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) { + const LLDPNeighborID *id = p; + + siphash24_compress(id->chassis_id, id->chassis_id_size, state); + siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state); + siphash24_compress(id->port_id, id->port_id_size, state); + siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state); +} + +static int lldp_neighbor_id_compare_func(const void *a, const void *b) { + const LLDPNeighborID *x = a, *y = b; + int r; + + r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size)); + if (r != 0) + return r; + + if (x->chassis_id_size < y->chassis_id_size) + return -1; + + if (x->chassis_id_size > y->chassis_id_size) + return 1; + + r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size)); + if (r != 0) + return r; + + if (x->port_id_size < y->port_id_size) + return -1; + if (x->port_id_size > y->port_id_size) + return 1; + + return 0; +} + +const struct hash_ops lldp_neighbor_id_hash_ops = { + .hash = lldp_neighbor_id_hash_func, + .compare = lldp_neighbor_id_compare_func +}; + +int lldp_neighbor_prioq_compare_func(const void *a, const void *b) { + const sd_lldp_neighbor *x = a, *y = b; + + if (x->until < y->until) + return -1; + + if (x->until > y->until) + return 1; + + return 0; +} + +_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) { + if (!n) + return NULL; + + assert(n->n_ref > 0 || n->lldp); + n->n_ref++; + + return n; +} + +static void lldp_neighbor_free(sd_lldp_neighbor *n) { + assert(n); + + free(n->id.port_id); + free(n->id.chassis_id); + free(n->port_description); + free(n->system_name); + free(n->system_description); + free(n->chassis_id_as_string); + free(n->port_id_as_string); + free(n); +} + +_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) { + + /* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from + * the sd_lldp object. */ + + if (!n) + return NULL; + + assert(n->n_ref > 0); + n->n_ref--; + + if (n->n_ref <= 0 && !n->lldp) + lldp_neighbor_free(n); + + return NULL; +} + +sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) { + + /* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */ + + if (!n) + return NULL; + + if (!n->lldp) + return NULL; + + assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n); + assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0); + + n->lldp = NULL; + + if (n->n_ref <= 0) + lldp_neighbor_free(n); + + return NULL; +} + +sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) { + sd_lldp_neighbor *n; + + n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size); + if (!n) + return NULL; + + n->raw_size = raw_size; + n->n_ref = 1; + + return n; +} + +static int parse_string(char **s, const void *q, size_t n) { + const char *p = q; + char *k; + + assert(s); + assert(p || n == 0); + + if (*s) { + log_lldp("Found duplicate string, ignoring field."); + return 0; + } + + /* Strip trailing NULs, just to be nice */ + while (n > 0 && p[n-1] == 0) + n--; + + if (n <= 0) /* Ignore empty strings */ + return 0; + + /* Look for inner NULs */ + if (memchr(p, 0, n)) { + log_lldp("Found inner NUL in string, ignoring field."); + return 0; + } + + /* Let's escape weird chars, for security reasons */ + k = cescape_length(p, n); + if (!k) + return -ENOMEM; + + free(*s); + *s = k; + + return 1; +} + +int lldp_neighbor_parse(sd_lldp_neighbor *n) { + struct ether_header h; + const uint8_t *p; + size_t left; + int r; + + assert(n); + + if (n->raw_size < sizeof(struct ether_header)) { + log_lldp("Recieved truncated packet, ignoring."); + return -EBADMSG; + } + + memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h)); + + if (h.ether_type != htobe16(ETHERTYPE_LLDP)) { + log_lldp("Received packet with wrong type, ignoring."); + return -EBADMSG; + } + + if (h.ether_dhost[0] != 0x01 || + h.ether_dhost[1] != 0x80 || + h.ether_dhost[2] != 0xc2 || + h.ether_dhost[3] != 0x00 || + h.ether_dhost[4] != 0x00 || + !IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) { + log_lldp("Received packet with wrong destination address, ignoring."); + return -EBADMSG; + } + + memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr)); + memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr)); + + p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header); + left = n->raw_size - sizeof(struct ether_header); + + for (;;) { + uint8_t type; + uint16_t length; + + if (left < 2) { + log_lldp("TLV lacks header, ignoring."); + return -EBADMSG; + } + + type = p[0] >> 1; + length = p[1] + (((uint16_t) (p[0] & 1)) << 8); + p += 2, left -= 2; + + if (left < length) { + log_lldp("TLV truncated, ignoring datagram."); + return -EBADMSG; + } + + switch (type) { + + case LLDP_TYPE_END: + if (length != 0) { + log_lldp("End marker TLV not zero-sized, ignoring datagram."); + return -EBADMSG; + } + if (left != 0) { + log_lldp("Trailing garbage in datagram, ignoring datagram."); + return -EBADMSG; + } + + goto end_marker; + + case LLDP_TYPE_CHASSIS_ID: + if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */ + log_lldp("Chassis ID field size out of range, ignoring datagram."); + return -EBADMSG; + } + if (n->id.chassis_id) { + log_lldp("Duplicate chassis ID field, ignoring datagram."); + return -EBADMSG; + } + + n->id.chassis_id = memdup(p, length); + if (!n->id.chassis_id) + return -ENOMEM; + + n->id.chassis_id_size = length; + break; + + case LLDP_TYPE_PORT_ID: + if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */ + log_lldp("Port ID field size out of range, ignoring datagram."); + return -EBADMSG; + } + if (n->id.port_id) { + log_lldp("Duplicate port ID field, ignoring datagram."); + return -EBADMSG; + } + + n->id.port_id = memdup(p, length); + if (!n->id.port_id) + return -ENOMEM; + + n->id.port_id_size = length; + break; + + case LLDP_TYPE_TTL: + if (length != 2) { + log_lldp("TTL field has wrong size, ignoring datagram."); + return -EBADMSG; + } + + if (n->has_ttl) { + log_lldp("Duplicate TTL field, ignoring datagram."); + return -EBADMSG; + } + + n->ttl = unaligned_read_be16(p); + n->has_ttl = true; + break; + + case LLDP_TYPE_PORT_DESCRIPTION: + r = parse_string(&n->port_description, p, length); + if (r < 0) + return r; + break; + + case LLDP_TYPE_SYSTEM_NAME: + r = parse_string(&n->system_name, p, length); + if (r < 0) + return r; + break; + + case LLDP_TYPE_SYSTEM_DESCRIPTION: + r = parse_string(&n->system_description, p, length); + if (r < 0) + return r; + break; + + case LLDP_TYPE_SYSTEM_CAPABILITIES: + if (length != 4) + log_lldp("System capabilities field has wrong size, ignoring."); + else { + n->system_capabilities = unaligned_read_be16(p); + n->enabled_capabilities = unaligned_read_be16(p + 2); + n->has_capabilities = true; + } + + break; + + case LLDP_TYPE_PRIVATE: + if (length < 4) + log_lldp("Found private TLV that is too short, ignoring."); + + break; + } + + + p += length, left -= length; + } + +end_marker: + if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) { + log_lldp("One or more mandatory TLV missing in datagram. Ignoring."); + return -EBADMSG; + + } + + n->rindex = sizeof(struct ether_header); + + return 0; +} + +void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) { + assert(n); + + if (n->ttl > 0) + n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC); + else + n->until = 0; + + if (n->lldp) + prioq_reshuffle(n->lldp->neighbor_by_expiry, n, &n->prioq_idx); +} + +bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) { + if (a == b) + return true; + + if (!a || !b) + return false; + + if (a->raw_size != b->raw_size) + return false; + + return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0; +} + +_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) { + assert_return(n, -EINVAL); + assert_return(address, -EINVAL); + + *address = n->source_address; + return 0; +} + +_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) { + assert_return(n, -EINVAL); + assert_return(address, -EINVAL); + + *address = n->destination_address; + return 0; +} + +_public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + *ret = LLDP_NEIGHBOR_RAW(n); + *size = n->raw_size; + + return 0; +} + +_public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + assert(n->id.chassis_id_size > 0); + + *type = *(uint8_t*) n->id.chassis_id; + *ret = (uint8_t*) n->id.chassis_id + 1; + *size = n->id.chassis_id_size - 1; + + return 0; +} + +static int format_mac_address(const void *data, size_t sz, char **ret) { + struct ether_addr a; + char *k; + + assert(data || sz <= 0); + + if (sz != 7) + return 0; + + memcpy(&a, (uint8_t*) data + 1, sizeof(a)); + + k = new(char, ETHER_ADDR_TO_STRING_MAX); + if (!k) + return -ENOMEM; + + *ret = ether_addr_to_string(&a, k); + return 1; +} + +static int format_network_address(const void *data, size_t sz, char **ret) { + union in_addr_union a; + int family; + + if (sz == 6 && ((uint8_t*) data)[1] == 1) { + memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in)); + family = AF_INET; + } else if (sz == 18 && ((uint8_t*) data)[1] == 2) { + memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6)); + family = AF_INET6; + } else + return 0; + + return in_addr_to_string(family, &a, ret); +} + +_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) { + char *k; + int r; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (n->chassis_id_as_string) { + *ret = n->chassis_id_as_string; + return 0; + } + + assert(n->id.chassis_id_size > 0); + + switch (*(uint8_t*) n->id.chassis_id) { + + case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: + case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1); + if (!k) + return -ENOMEM; + + goto done; + + case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + + case LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: + r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + } + + /* Generic fallback */ + k = hexmem(n->id.chassis_id, n->id.chassis_id_size); + if (!k) + return -ENOMEM; + +done: + *ret = n->chassis_id_as_string = k; + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + assert(n->id.port_id_size > 0); + + *type = *(uint8_t*) n->id.port_id; + *ret = (uint8_t*) n->id.port_id + 1; + *size = n->id.port_id_size - 1; + + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) { + char *k; + int r; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (n->port_id_as_string) { + *ret = n->port_id_as_string; + return 0; + } + + assert(n->id.port_id_size > 0); + + switch (*(uint8_t*) n->id.port_id) { + + case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1); + if (!k) + return -ENOMEM; + + goto done; + + case LLDP_PORT_SUBTYPE_MAC_ADDRESS: + r = format_mac_address(n->id.port_id, n->id.port_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + + case LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: + r = format_network_address(n->id.port_id, n->id.port_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + } + + /* Generic fallback */ + k = hexmem(n->id.port_id, n->id.port_id_size); + if (!k) + return -ENOMEM; + +done: + *ret = n->port_id_as_string = k; + return 0; +} + +_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = n->ttl; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->system_name) + return -ENODATA; + + *ret = n->system_name; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->system_description) + return -ENODATA; + + *ret = n->system_description; + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->port_description) + return -ENODATA; + + *ret = n->port_description; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->has_capabilities) + return -ENODATA; + + *ret = n->system_capabilities; + return 0; +} + +_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->has_capabilities) + return -ENODATA; + + *ret = n->enabled_capabilities; + return 0; +} + +int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + int r; + + assert_return(ret, -EINVAL); + assert_return(raw || raw_size <= 0, -EINVAL); + + n = lldp_neighbor_new(raw_size); + if (!n) + return -ENOMEM; + + memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size); + r = lldp_neighbor_parse(n); + if (r < 0) + return r; + + *ret = n; + n = 0; + + return r; +} + +_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) { + assert_return(n, -EINVAL); + + assert(n->raw_size >= sizeof(struct ether_header)); + n->rindex = sizeof(struct ether_header); + + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { + size_t length; + + assert_return(n, -EINVAL); + + if (n->rindex == n->raw_size) /* EOF */ + return -ESPIPE; + + if (n->rindex + 2 > n->raw_size) /* Truncated message */ + return -EBADMSG; + + length = LLDP_NEIGHBOR_LENGTH(n); + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + n->rindex += 2 + length; + return n->rindex < n->raw_size; +} + +_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + + if (n->rindex == n->raw_size) /* EOF */ + return -ESPIPE; + + if (n->rindex + 2 > n->raw_size) + return -EBADMSG; + + *type = LLDP_NEIGHBOR_TYPE(n); + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) { + uint8_t k; + int r; + + assert_return(n, -EINVAL); + + r = sd_lldp_neighbor_tlv_get_type(n, &k); + if (r < 0) + return r; + + return type == k; +} + +_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype) { + const uint8_t *d; + size_t length; + int r; + + assert_return(n, -EINVAL); + assert_return(oui, -EINVAL); + assert_return(subtype, -EINVAL); + + r = sd_lldp_neighbor_tlv_is_type(n, LLDP_TYPE_PRIVATE); + if (r < 0) + return r; + if (r == 0) + return -ENXIO; + + length = LLDP_NEIGHBOR_LENGTH(n); + if (length < 4) + return -EBADMSG; + + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + d = LLDP_NEIGHBOR_DATA(n); + memcpy(oui, d, 3); + *subtype = d[3]; + + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype) { + uint8_t k[3], st; + int r; + + r = sd_lldp_neighbor_tlv_get_oui(n, k, &st); + if (r == -ENXIO) + return 0; + if (r < 0) + return r; + + return memcmp(k, oui, 3) == 0 && st == subtype; +} + +_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { + size_t length; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + /* Note that this returns the full TLV, including the TLV header */ + + if (n->rindex + 2 > n->raw_size) + return -EBADMSG; + + length = LLDP_NEIGHBOR_LENGTH(n); + + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + *ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; + *size = length + 2; + + return 0; +} diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h new file mode 100644 index 0000000000..f203bfa604 --- /dev/null +++ b/src/libsystemd-network/lldp-neighbor.h @@ -0,0 +1,106 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#include +#include + +#include "sd-lldp.h" + +#include "hash-funcs.h" +#include "lldp-internal.h" +#include "time-util.h" + +typedef struct LLDPNeighborID { + /* The spec calls this an "MSAP identifier" */ + void *chassis_id; + size_t chassis_id_size; + + void *port_id; + size_t port_id_size; +} LLDPNeighborID; + +struct sd_lldp_neighbor { + /* Neighbor objects stay around as long as they are linked into an "sd_lldp" object or n_ref > 0. */ + sd_lldp *lldp; + unsigned n_ref; + + usec_t until; + unsigned prioq_idx; + + struct ether_addr source_address; + struct ether_addr destination_address; + + LLDPNeighborID id; + + /* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */ + size_t raw_size; + + /* The current read index for the iterative TLV interface */ + size_t rindex; + + /* And a couple of fields parsed out. */ + bool has_ttl:1; + bool has_capabilities:1; + bool has_port_vlan_id:1; + + uint16_t ttl; + + uint16_t system_capabilities; + uint16_t enabled_capabilities; + + char *port_description; + char *system_name; + char *system_description; + + uint16_t port_vlan_id; + + char *chassis_id_as_string; + char *port_id_as_string; +}; + +static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) { + return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor)); +} + +static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) { + return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1; +} + +static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) { + uint8_t *p; + + p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; + return p[1] + (((size_t) (p[0] & 1)) << 8); +} + +static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) { + return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2; +} + +extern const struct hash_ops lldp_neighbor_id_hash_ops; +int lldp_neighbor_prioq_compare_func(const void *a, const void *b); + +sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n); +sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size); +int lldp_neighbor_parse(sd_lldp_neighbor *n); +void lldp_neighbor_start_ttl(sd_lldp_neighbor *n); +bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b); diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c deleted file mode 100644 index 9170b50691..0000000000 --- a/src/libsystemd-network/lldp-tlv.c +++ /dev/null @@ -1,638 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - 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 . -***/ - -#include -#include - -#include "alloc-util.h" -#include "lldp-tlv.h" -#include "macro.h" - -int tlv_section_new(tlv_section **ret) { - tlv_section *s; - - s = new0(tlv_section, 1); - if (!s) - return -ENOMEM; - - *ret = s; - - return 0; -} - -void tlv_section_free(tlv_section *m) { - - if (!m) - return; - - free(m); -} - -int tlv_packet_new(tlv_packet **ret) { - tlv_packet *m; - - m = new0(tlv_packet, 1); - if (!m) - return -ENOMEM; - - LIST_HEAD_INIT(m->sections); - m->n_ref = 1; - - *ret = m; - - return 0; -} - -tlv_packet *sd_lldp_packet_ref(tlv_packet *m) { - - if (!m) - return NULL; - - assert(m->n_ref > 0); - m->n_ref++; - - return m; -} - -tlv_packet *sd_lldp_packet_unref(tlv_packet *m) { - tlv_section *s, *n; - - if (!m) - return NULL; - - assert(m->n_ref > 0); - m->n_ref--; - - if (m->n_ref > 0) - return m; - - LIST_FOREACH_SAFE(section, s, n, m->sections) - tlv_section_free(s); - - free(m); - return NULL; -} - -int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) { - uint8_t *p; - - assert_return(m, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_length, -EINVAL); - - if (m->length + data_length > ETHER_MAX_LEN) - return -ENOMEM; - - p = m->pdu + m->length; - memcpy(p, data, data_length); - m->length += data_length; - - return 0; -} - -int tlv_packet_append_u8(tlv_packet *m, uint8_t data) { - - assert_return(m, -EINVAL); - - return tlv_packet_append_bytes(m, &data, sizeof(uint8_t)); -} - -int tlv_packet_append_u16(tlv_packet *m, uint16_t data) { - uint16_t type; - - assert_return(m, -EINVAL); - - type = htons(data); - - return tlv_packet_append_bytes(m, &type, sizeof(uint16_t)); -} - -int tlv_packet_append_u32(tlv_packet *m, uint32_t data) { - uint32_t type; - - assert_return(m, -EINVAL); - - type = htonl(data); - - return tlv_packet_append_bytes(m, &type, sizeof(uint32_t)); -} - -int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) { - - assert_return(m, -EINVAL); - - return tlv_packet_append_bytes(m, data, size); -} - -int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) { - - assert_return(m, -EINVAL); - - m->container_pos = m->pdu + m->length; - - return tlv_packet_append_u16(m, type << 9); -} - -int lldp_tlv_packet_close_container(tlv_packet *m) { - uint16_t type; - - assert_return(m, -EINVAL); - assert_return(m->container_pos, -EINVAL); - - memcpy(&type, m->container_pos, sizeof(uint16_t)); - - type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff); - memcpy(m->container_pos, &type, sizeof(uint16_t)); - - return 0; -} - -static inline int tlv_packet_read_internal(tlv_section *m, void **data) { - - assert_return(m->read_pos, -EINVAL); - - *data = m->read_pos; - - return 0; -} - -int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(data, val, sizeof(uint8_t)); - - m->container->read_pos ++; - - return 0; -} - -int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) { - uint16_t t; - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(&t, val, sizeof(uint16_t)); - *data = ntohs(t); - - m->container->read_pos += 2; - - return 0; -} - -int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) { - uint32_t t; - void *val; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(&t, val, sizeof(uint32_t)); - *data = ntohl(t); - - m->container->read_pos += 4; - - return r; -} - -int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - *data = (char *) val; - *data_length = m->container->data + m->container->length - m->container->read_pos; - - m->container->read_pos += *data_length; - - return 0; -} - -int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - *data = (uint8_t *) val; - *data_length = m->container->data + m->container->length - m->container->read_pos; - - m->container->read_pos += *data_length; - - return 0; -} - -/* parse raw TLV packet */ -int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { - tlv_section *section, *tail; - uint16_t t, l; - uint8_t *p; - int r; - - assert_return(m, -EINVAL); - assert_return(size, -EINVAL); - - p = m->pdu; - - /* extract Ethernet header */ - memcpy(&m->mac, p, ETH_ALEN); - p += sizeof(struct ether_header); - - for (l = 0; l <= size; ) { - r = tlv_section_new(§ion); - if (r < 0) - return r; - - memcpy(&t, p, sizeof(uint16_t)); - - section->type = ntohs(t) >> 9; - section->length = ntohs(t) & 0x01ff; - - if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) { - tlv_section_free(section); - break; - } - - p += 2; - - if (section->type == LLDP_TYPE_PRIVATE && - section->length >= LLDP_OUI_LEN + 1) { - section->oui = p; - p += LLDP_OUI_LEN; - section->subtype = *p++; - - section->length -= LLDP_OUI_LEN + 1; - l += LLDP_OUI_LEN + 1; - } - - section->data = p; - - LIST_FIND_TAIL(section, m->sections, tail); - LIST_INSERT_AFTER(section, m->sections, tail, section); - - p += section->length; - l += (section->length + 2); - } - - return 0; -} - -int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { - tlv_section *s; - - assert_return(m, -EINVAL); - assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL); - - LIST_FOREACH(section, s, m->sections) - if (s->type == type) - break; - if (!s) - return -1; - - m->container = s; - - m->container->read_pos = s->data; - if (!m->container->read_pos) { - m->container = NULL; - return -1; - } - - return 0; -} - -int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) { - tlv_section *s; - - assert_return(m, -EINVAL); - assert_return(oui, -EINVAL); - - LIST_FOREACH(section, s, m->sections) { - if (s->type == LLDP_TYPE_PRIVATE && - s->oui && - s->subtype == subtype && - !memcmp(s->oui, oui, LLDP_OUI_LEN)) - break; - } - - if (!s) - return -1; - - m->container = s; - - m->container->read_pos = s->data; - if (!m->container->read_pos) { - m->container = NULL; - return -1; - } - - return 0; -} - -int lldp_tlv_packet_exit_container(tlv_packet *m) { - assert_return(m, -EINVAL); - - m->container = 0; - - return 0; -} - -static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, type); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, value); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) { - char *s; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, type); - if (r < 0) - return r; - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (char *) s; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { - uint8_t subtype; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out; - - switch (subtype) { - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_port_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { - uint8_t subtype; - char *s; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out; - - switch (subtype) { - case LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (uint8_t *) s; - - break; - case LLDP_PORT_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) { - return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl); -} - -int sd_lldp_packet_read_system_name(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length); -} - -int sd_lldp_packet_read_system_description(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length); -} - -int sd_lldp_packet_read_port_description(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length); -} - -int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { - return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data); -} - -int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, id); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, flags); - if (r >= 0) - r = tlv_packet_read_u16(tlv, id); - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) { - int r, r2; - uint8_t len = 0; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, vlan_id); - if (r >= 0) - r = tlv_packet_read_u8(tlv, &len); - if (r >= 0) - r = tlv_packet_read_string(tlv, name, length); - - if (r >= 0 && len < *length) - *length = len; - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, id); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, status); - if (r >= 0) - r = tlv_packet_read_u32(tlv, id); - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) { - assert_return(tlv, -EINVAL); - assert_return(dest, -EINVAL); - - /* 802.1AB-2009, Table 7-1 */ - if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE; - else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE; - else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE; - else - return -EINVAL; - - return 0; -} diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h deleted file mode 100644 index 1ddca2882f..0000000000 --- a/src/libsystemd-network/lldp-tlv.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - 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 . -***/ - -#include - -#include "sd-lldp.h" - -#include "list.h" -#include "lldp.h" -#include "util.h" - -typedef struct sd_lldp_packet tlv_packet; -typedef struct sd_lldp_section tlv_section; - -#define LLDP_OUI_LEN 3 - -struct sd_lldp_section { - uint16_t type; - uint16_t length; - uint8_t *oui; - uint8_t subtype; - - uint8_t *read_pos; - uint8_t *data; - - LIST_FIELDS(tlv_section, section); -}; - -#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } -#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } -#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 } - -int tlv_section_new(tlv_section **ret); -void tlv_section_free(tlv_section *ret); - -struct sd_lldp_packet { - unsigned n_ref; - - uint16_t type; - uint16_t length; - usec_t ts; - - uint8_t *container_pos; - uint8_t pdu[ETHER_MAX_LEN]; - - void *userdata; - - struct ether_addr mac; - tlv_section *container; - - LIST_HEAD(tlv_section, sections); -}; - -int tlv_packet_new(tlv_packet **ret); - -int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); -int lldp_tlv_packet_close_container(tlv_packet *m); - -int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length); -int tlv_packet_append_u8(tlv_packet *m, uint8_t data); -int tlv_packet_append_u16(tlv_packet *m, uint16_t data); -int tlv_packet_append_u32(tlv_packet *m, uint32_t data); -int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size); - -int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type); -int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype); -int lldp_tlv_packet_exit_container(tlv_packet *m); - -int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length); -int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length); -int tlv_packet_read_u8(tlv_packet *m, uint8_t *data); -int tlv_packet_read_u16(tlv_packet *m, uint16_t *data); -int tlv_packet_read_u32(tlv_packet *m, uint32_t *data); - -int tlv_packet_parse_pdu(tlv_packet *t, uint16_t size); diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index 88bef687eb..d61ecabcfc 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -23,7 +23,7 @@ #define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } /* IEEE 802.3AB Clause 9: TLV Types */ -typedef enum LLDPTypes { +enum { LLDP_TYPE_END = 0, LLDP_TYPE_CHASSIS_ID = 1, LLDP_TYPE_PORT_ID = 2, @@ -34,12 +34,10 @@ typedef enum LLDPTypes { LLDP_TYPE_SYSTEM_CAPABILITIES = 7, LLDP_TYPE_MGMT_ADDRESS = 8, LLDP_TYPE_PRIVATE = 127, - _LLDP_TYPE_MAX, - _LLDP_TYPE_INVALID = -1, -} LLDPTypes; +}; /* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ -typedef enum LLDPChassisSubtypes { +enum { LLDP_CHASSIS_SUBTYPE_RESERVED = 0, LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, @@ -48,25 +46,21 @@ typedef enum LLDPChassisSubtypes { LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, - _LLDP_CHASSIS_SUBTYPE_MAX, - _LLDP_CHASSIS_SUBTYPE_INVALID = -1, -} LLDPChassisSubtypes; +}; /* IEEE 802.3AB Clause 9.5.3: Port subtype */ -typedef enum LLDPPortSubtypes { +enum { LLDP_PORT_SUBTYPE_RESERVED = 0, LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, - LLDP_PORT_SUBTYPE_NETWORK = 4, + LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, - _LLDP_PORT_SUBTYPE_MAX, - _LLDP_PORT_SUBTYPE_INVALID = -1 -} LLDPPortSubtypes; +}; -typedef enum LLDPSystemCapabilities { +enum { LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, @@ -78,47 +72,31 @@ typedef enum LLDPSystemCapabilities { LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, - _LLDP_SYSTEM_CAPABILITIES_MAX, - _LLDP_SYSTEM_CAPABILITIES_INVALID = -1, -} LLDPSystemCapabilities; +}; + +#define _LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) -typedef enum LLDPMedSubtype { - LLDP_MED_SUBTYPE_RESERVED = 0, - LLDP_MED_SUBTYPE_CAPABILITIES = 1, - LLDP_MED_SUBTYPE_NETWORK_POLICY = 2, - LLDP_MED_SUBTYPE_LOCATION_ID = 3, - LLDP_MED_SUBTYPE_EXTENDED_PVMDI = 4, - LLDP_MED_SUBTYPE_INV_HWREV = 5, - LLDP_MED_SUBTYPE_INV_FWREV = 6, - LLDP_MED_SUBTYPE_INV_SWREV = 7, - LLDP_MED_SUBTYPE_INV_SERIAL = 8, - LLDP_MED_SUBTYPE_INV_MANUFACTURER = 9, - LLDP_MED_SUBTYPE_INV_MODELNAME = 10, - LLDP_MED_SUBTYPE_INV_ASSETID = 11, - _LLDP_MED_SUBTYPE_MAX, - _LLDP_MED_SUBTYPE_INVALID = -1, -} LLDPMedSubtype; +#define _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \ + ((uint16_t) \ + (LLDP_SYSTEM_CAPABILITIES_REPEATER| \ + LLDP_SYSTEM_CAPABILITIES_BRIDGE| \ + LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \ + LLDP_SYSTEM_CAPABILITIES_ROUTER| \ + LLDP_SYSTEM_CAPABILITIES_DOCSIS| \ + LLDP_SYSTEM_CAPABILITIES_CVLAN| \ + LLDP_SYSTEM_CAPABILITIES_SVLAN| \ + LLDP_SYSTEM_CAPABILITIES_TPMR)) -typedef enum LLDPMedCapability { - LLDP_MED_CAPABILITY_CAPAPILITIES = 1 << 0, - LLDP_MED_CAPABILITY_NETWORK_POLICY = 1 << 1, - LLDP_MED_CAPABILITY_LOCATION_ID = 1 << 2, - LLDP_MED_CAPABILITY_EXTENDED_PSE = 1 << 3, - LLDP_MED_CAPABILITY_EXTENDED_PD = 1 << 4, - LLDP_MED_CAPABILITY_INVENTORY = 1 << 5, - LLDP_MED_CAPABILITY_MAX, - LLDP_MED_CAPABILITY_INVALID = -1, -} LLDPMedCapability; #define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } #define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } enum { - LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1, - LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2, - LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3, - LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4, - LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5, - LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6, - LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7, + LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, + LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, + LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, + LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, + LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, + LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, + LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, }; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 34117cc205..65cfa4e184 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -1,21 +1,21 @@ /*** - This file is part of systemd. + This file is part of systemd. - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani - 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 . + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . ***/ #include @@ -24,484 +24,162 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" -#include "hashmap.h" #include "lldp-internal.h" +#include "lldp-neighbor.h" #include "lldp-network.h" -#include "lldp-tlv.h" -#include "prioq.h" -#include "siphash24.h" -#include "string-util.h" +#include "socket-util.h" -struct sd_lldp { - int ifindex; - int fd; +#define LLDP_DEFAULT_NEIGHBORS_MAX 128U - sd_event *event; - int64_t event_priority; - sd_event_source *event_source; - - Prioq *by_expiry; - Hashmap *neighbour_mib; - - sd_lldp_callback_t callback; - void *userdata; -}; - -static void chassis_id_hash_func(const void *p, struct siphash *state) { - const lldp_chassis_id *id = p; - - assert(id); - assert(id->data); - - siphash24_compress(&id->length, sizeof(id->length), state); - siphash24_compress(id->data, id->length, state); -} - -static int chassis_id_compare_func(const void *_a, const void *_b) { - const lldp_chassis_id *a, *b; - - a = _a; - b = _b; - - assert(!a->length || a->data); - assert(!b->length || b->data); - - if (a->type != b->type) - return -1; - - if (a->length != b->length) - return a->length < b->length ? -1 : 1; - - return memcmp(a->data, b->data, a->length); -} - -static const struct hash_ops chassis_id_hash_ops = { - .hash = chassis_id_hash_func, - .compare = chassis_id_compare_func -}; - -static void lldp_mib_delete_objects(sd_lldp *lldp); - -static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { - int r; +static void lldp_flush_neighbors(sd_lldp *lldp) { + sd_lldp_neighbor *n; assert(lldp); - assert(tlv); - - /* Remove expired packets */ - if (prioq_size(lldp->by_expiry) > 0) - lldp_mib_delete_objects(lldp); - - r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv); - if (r < 0) - goto out; - - if (lldp->callback) - lldp->callback(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); - - log_lldp("Packet added. MIB size: %d , PQ size: %d", - hashmap_size(lldp->neighbour_mib), - prioq_size(lldp->by_expiry)); - - out: - if (r < 0) - log_lldp("Receive frame failed: %s", strerror(-r)); - return 0; + while ((n = hashmap_first(lldp->neighbor_by_id))) + lldp_neighbor_unlink(n); } -/* 10.3.2 LLDPDU validation: rxProcessFrame() */ -int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { - bool system_description = false, system_name = false, chassis_id = false; - bool port_id = false, ttl = false, end = false; - uint16_t type, len, i, l, t; - uint8_t *p, *q; - sd_lldp *lldp; - int r; - - assert(tlv); - assert(length > 0); - - lldp = tlv->userdata; - - p = tlv->pdu; - p += sizeof(struct ether_header); - - for (i = 1, l = 0; l <= length; i++) { - - memcpy(&t, p, sizeof(uint16_t)); - - type = ntohs(t) >> 9; - len = ntohs(t) & 0x01ff; - - if (type == LLDP_TYPE_END) { - if (len != 0) { - log_lldp("TLV type end must be length 0 (not %d). Dropping.", len); - - goto out; - } - - end = true; - - break; - } else if (type >=_LLDP_TYPE_MAX) { - log_lldp("TLV type: %d not recognized. Dropping.", type); - - goto out; - } - - /* skip type and length encoding */ - p += 2; - q = p; - - p += len; - l += (len + 2); - - if (i <= 3) { - if (i != type) { - log_lldp("TLV missing or out of order. Dropping."); - - goto out; - } - } - - switch(type) { - case LLDP_TYPE_CHASSIS_ID: - - if (len < 2) { - log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len); - - goto out; - } +static int lldp_make_space(sd_lldp *lldp, size_t extra) { + sd_lldp_neighbor *n; + usec_t t = USEC_INFINITY; + bool changed = false; - if (chassis_id) { - log_lldp("Duplicate Chassis ID TLV found. Dropping."); - - goto out; - } - - /* Look what subtype it has */ - if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q); - - goto out; - - } - - chassis_id = true; - - break; - case LLDP_TYPE_PORT_ID: - - if (len < 2) { - log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len); - - goto out; - } - - if (port_id) { - log_lldp("Duplicate Port ID TLV found. Dropping."); - - goto out; - } - - /* Look what subtype it has */ - if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q); - - goto out; - - } - - port_id = true; - - break; - case LLDP_TYPE_TTL: - - if(len != 2) { - log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len); - - goto out; - } - - if (ttl) { - log_lldp("Duplicate TTL TLV found. Dropping."); - - goto out; - } + assert(lldp); - ttl = true; + /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries + * are free. */ + for (;;) { + n = prioq_peek(lldp->neighbor_by_expiry); + if (!n) break; - case LLDP_TYPE_SYSTEM_NAME: - - /* According to RFC 1035 the length of a FQDN is limited to 255 characters */ - if (len > 255) { - log_lldp("Received invalid system name length: %d. Dropping.", len); - goto out; - } - if (system_name) { - log_lldp("Duplicate system name found. Dropping."); - goto out; - } + if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra)) + goto remove_one; - system_name = true; + if (t == USEC_INFINITY) + t = now(clock_boottime_or_monotonic()); + if (n->until > t) break; - case LLDP_TYPE_SYSTEM_DESCRIPTION: - - /* 0 <= n <= 255 octets */ - if (len > 255) { - log_lldp("Received invalid system description length: %d. Dropping.", len); - goto out; - } - if (system_description) { - log_lldp("Duplicate system description found. Dropping."); - goto out; - } + remove_one: + lldp_neighbor_unlink(n); + changed = true; + } - system_description = true; - break; - default: + return changed; +} - if (len == 0) { - log_lldp("TLV type: %d length 0 received. Dropping.", type); +static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { + sd_lldp_neighbor *old; + bool changed = false; + int r; - goto out; - } - break; + assert(lldp); + assert(n); + assert(!n->lldp); + + /* First retrieve the old entry for this MSAP */ + old = hashmap_get(lldp->neighbor_by_id, &n->id); + if (old) { + if (lldp_neighbor_equal(n, old)) { + /* Is this equal, then restart the TTL counter, but don't do anyting else. */ + lldp_neighbor_start_ttl(old); + return 0; } + + /* Data changed, remove the old entry, and add a new one */ + lldp_neighbor_unlink(old); + changed = true; } - if(!chassis_id || !port_id || !ttl || !end) { - log_lldp("One or more mandatory TLV missing. Dropping."); + /* Then, add the new entry in its place, but only if it has a non-zero TTL. */ + if (n->ttl <= 0) + return changed; - goto out; + /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with + * no caps field set. */ + if (n->has_capabilities && + (n->enabled_capabilities & lldp->capability_mask) == 0) + return changed; - } + /* Then, make room for at least one new neighbor */ + lldp_make_space(lldp, 1); - r = tlv_packet_parse_pdu(tlv, length); - if (r < 0) { - log_lldp("Failed to parse the TLV. Dropping."); + r = hashmap_put(lldp->neighbor_by_id, &n->id, n); + if (r < 0) + return r; - goto out; + r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx); + if (r < 0) { + assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n); + return r; } - return lldp_receive_frame(lldp, tlv); + n->lldp = lldp; - out: - - sd_lldp_packet_unref(tlv); - - return 0; + return true; } -static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) { - const lldp_neighbour_port *p = a, *q = b; - - if (p->until < q->until) - return -1; - - if (p->until > q->until) - return 1; - - return 0; -} - -/* 10.5.5.2.1 mibDeleteObjects () - * The mibDeleteObjects () procedure deletes all information in the LLDP remote - * systems MIB associated with the MSAP identifier if an LLDPDU is received with - * an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */ - -static void lldp_mib_delete_objects(sd_lldp *lldp) { - lldp_neighbour_port *p; - usec_t t = 0; - - /* Remove all entries that are past their TTL */ - for (;;) { - - if (prioq_size(lldp->by_expiry) <= 0) - break; +static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { + int r; - p = prioq_peek(lldp->by_expiry); - if (!p) - break; + assert(lldp); + assert(n); - if (t <= 0) - t = now(clock_boottime_or_monotonic()); + r = lldp_neighbor_parse(n); + if (r == -EBADMSG) /* Ignore bad messages */ + return 0; + if (r < 0) + return r; - if (p->until > t) - break; + lldp_neighbor_start_ttl(n); - lldp_neighbour_port_remove_and_free(p); + r = lldp_add_neighbor(lldp, n); + if (r < 0) { + log_lldp_errno(r, "Failed to add datagram. Ignoring."); + return 0; } -} - -static void lldp_mib_objects_flush(sd_lldp *lldp) { - lldp_neighbour_port *p, *q; - lldp_chassis *c; - assert(lldp); - assert(lldp->neighbour_mib); - assert(lldp->by_expiry); - - /* Drop all packets */ - while ((c = hashmap_steal_first(lldp->neighbour_mib))) { + log_lldp("Successfully processed LLDP datagram."); - LIST_FOREACH_SAFE(port, p, q, c->ports) { - lldp_neighbour_port_remove_and_free(p); - } - } + if (r > 0 && lldp->callback) /* Only invoke the callback if something actually changed. */ + lldp->callback(lldp, lldp->userdata); - assert(hashmap_size(lldp->neighbour_mib) == 0); - assert(prioq_size(lldp->by_expiry) == 0); + return 0; } -int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - uint8_t *mac, *port_id, type; - lldp_neighbour_port *p; - uint16_t data = 0, length = 0; - char buf[LINE_MAX]; - lldp_chassis *c; - usec_t time; - Iterator i; - int r; +static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + ssize_t space, length; + sd_lldp *lldp = userdata; + assert(fd >= 0); assert(lldp); - assert(lldp_file); - - r = fopen_temporary(lldp_file, &f, &temp_path); - if (r < 0) - goto fail; - - fchmod(fileno(f), 0644); - - HASHMAP_FOREACH(c, lldp->neighbour_mib, i) { - LIST_FOREACH(port, p, c->ports) { - _cleanup_free_ char *s = NULL; - char *k, *t; - - r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length); - if (r < 0) - continue; - - sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); - - s = strdup(buf); - if (!s) { - r = -ENOMEM; - goto fail; - } - - r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length); - if (r < 0) - continue; - - if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) { - k = strndup((char *) port_id, length -1); - if (!k) { - r = -ENOMEM; - goto fail; - } - - sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type); - free(k); - } else { - mac = port_id; - sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); - } - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - time = now(clock_boottime_or_monotonic()); - - /* Don't write expired packets */ - if (time - p->until <= 0) - continue; - - sprintf(buf, "'_TTL="USEC_FMT"' ", p->until); - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - r = sd_lldp_packet_read_system_name(p->packet, &k, &length); - if (r < 0) - k = strappend(s, "'_NAME=N/A' "); - else { - t = strndup(k, length); - if (!t) { - r = -ENOMEM; - goto fail; - } - - k = strjoin(s, "'_NAME=", t, "' ", NULL); - free(t); - } - - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - (void) sd_lldp_packet_read_system_capability(p->packet, &data); - - sprintf(buf, "'_CAP=%x'", data); - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - fprintf(f, "%s\n", s); - } - } - r = fflush_and_check(f); - if (r < 0) - goto fail; + space = next_datagram_size_fd(fd); + if (space < 0) + return log_lldp_errno(space, "Failed to determine datagram size to read: %m"); - if (rename(temp_path, lldp_file) < 0) { - r = -errno; - goto fail; - } + n = lldp_neighbor_new(space); + if (!n) + return -ENOMEM; - return 0; + length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); + if (length < 0) + return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); - fail: - if (temp_path) - (void) unlink(temp_path); + if ((size_t) length != n->raw_size) { + log_lldp("Packet size mismatch."); + return -EINVAL; + } - return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file); + return lldp_handle_datagram(lldp, n); } -int sd_lldp_start(sd_lldp *lldp) { +_public_ int sd_lldp_start(sd_lldp *lldp) { int r; assert_return(lldp, -EINVAL); @@ -509,48 +187,49 @@ int sd_lldp_start(sd_lldp *lldp) { if (lldp->fd >= 0) return 0; - assert(!lldp->event_source); + assert(!lldp->io_event_source); lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex); if (lldp->fd < 0) return lldp->fd; if (lldp->event) { - r = sd_event_add_io(lldp->event, &lldp->event_source, lldp->fd, EPOLLIN, lldp_receive_packet, lldp); + r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); if (r < 0) goto fail; - r = sd_event_source_set_priority(lldp->event_source, lldp->event_priority); + r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); if (r < 0) goto fail; - (void) sd_event_source_set_description(lldp->event_source, "lldp"); + (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); } return 1; fail: - lldp->event_source = sd_event_source_unref(lldp->event_source); + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); lldp->fd = safe_close(lldp->fd); return r; } -int sd_lldp_stop(sd_lldp *lldp) { +_public_ int sd_lldp_stop(sd_lldp *lldp) { assert_return(lldp, -EINVAL); if (lldp->fd < 0) return 0; - lldp->event_source = sd_event_source_unref(lldp->event_source); + lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); lldp->fd = safe_close(lldp->fd); - lldp_mib_objects_flush(lldp); + lldp_flush_neighbors(lldp); return 1; } -int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { +_public_ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { int r; assert_return(lldp, -EINVAL); @@ -570,17 +249,16 @@ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { return 0; } -int sd_lldp_detach_event(sd_lldp *lldp) { +_public_ int sd_lldp_detach_event(sd_lldp *lldp) { assert_return(lldp, -EINVAL); assert_return(lldp->fd < 0, -EBUSY); lldp->event = sd_event_unref(lldp->event); - return 0; } -int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { +_public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { assert_return(lldp, -EINVAL); lldp->callback = cb; @@ -589,26 +267,27 @@ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { return 0; } -sd_lldp* sd_lldp_unref(sd_lldp *lldp) { +_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { if (!lldp) return NULL; - /* Drop all packets */ - lldp_mib_objects_flush(lldp); + lldp_flush_neighbors(lldp); - hashmap_free(lldp->neighbour_mib); - prioq_free(lldp->by_expiry); + hashmap_free(lldp->neighbor_by_id); + prioq_free(lldp->neighbor_by_expiry); - sd_event_source_unref(lldp->event_source); + sd_event_source_unref(lldp->io_event_source); + sd_event_source_unref(lldp->timer_event_source); sd_event_unref(lldp->event); safe_close(lldp->fd); free(lldp); + return NULL; } -int sd_lldp_new(int ifindex, sd_lldp **ret) { +_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) { _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; int r; @@ -621,12 +300,14 @@ int sd_lldp_new(int ifindex, sd_lldp **ret) { lldp->fd = -1; lldp->ifindex = ifindex; + lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX; + lldp->capability_mask = (uint16_t) -1; - lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops); - if (!lldp->neighbour_mib) + lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops); + if (!lldp->neighbor_by_id) return -ENOMEM; - r = prioq_ensure_allocated(&lldp->by_expiry, ttl_expiry_item_prioq_compare_func); + r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func); if (r < 0) return r; @@ -636,34 +317,124 @@ int sd_lldp_new(int ifindex, sd_lldp **ret) { return 0; } -int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) { - lldp_neighbour_port *p; - lldp_chassis *c; - Iterator iter; - unsigned count = 0, i; +static int neighbor_compare_func(const void *a, const void *b) { + const sd_lldp_neighbor * const*x = a, * const *y = b; - assert_return(lldp, -EINVAL); - assert_return(tlvs, -EINVAL); + return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); +} + +static int lldp_start_timer(sd_lldp *lldp); + +static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { + sd_lldp *lldp = userdata; + int r, q; + + r = lldp_make_space(lldp, 0); + if (r < 0) + return log_lldp_errno(r, "Failed to make space: %m"); + + q = lldp_start_timer(lldp); + if (q < 0) + return log_lldp_errno(q, "Failed to restart timer: %m"); + + log_lldp("LLDP timer event hit."); + if (r > 0 && lldp->callback) /* Invoke callback if we dropped an entry */ + lldp->callback(lldp, lldp->userdata); + + return 0; +} - HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { - LIST_FOREACH(port, p, c->ports) - count++; +static int lldp_start_timer(sd_lldp *lldp) { + sd_lldp_neighbor *n; + int r; + + assert(lldp); + + n = prioq_peek(lldp->neighbor_by_expiry); + if (!n) { + + if (lldp->timer_event_source) + return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF); + + return 0; + } + + if (lldp->timer_event_source) { + r = sd_event_source_set_time(lldp->timer_event_source, n->until); + if (r < 0) + return r; + + return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT); } - if (!count) { - *tlvs = NULL; + if (!lldp->event) + return 0; + + r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp); + if (r < 0) + return r; + + r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority); + if (r < 0) + return r; + + (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer"); + return 0; +} + +_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { + sd_lldp_neighbor **l = NULL, *n; + Iterator i; + int k = 0, r; + + assert_return(lldp, -EINVAL); + assert_return(ret, -EINVAL); + + /* Flush out old entries, before we return data */ + (void) lldp_make_space(lldp, 0); + + if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */ + *ret = NULL; return 0; } - *tlvs = new(sd_lldp_packet *, count); - if (!*tlvs) + l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id)); + if (!l) return -ENOMEM; - i = 0; - HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { - LIST_FOREACH(port, p, c->ports) - (*tlvs)[i++] = sd_lldp_packet_ref(p->packet); + r = lldp_start_timer(lldp); + if (r < 0) { + free(l); + return r; } - return count; + HASHMAP_FOREACH(n, lldp->neighbor_by_id, i) + l[k++] = sd_lldp_neighbor_ref(n); + + assert((size_t) k == hashmap_size(lldp->neighbor_by_id)); + + /* Return things in a stable order */ + qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func); + *ret = l; + + return k; +} + +_public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) { + assert_return(lldp, -EINVAL); + assert_return(m <= 0, -EINVAL); + + lldp->neighbors_max = m; + lldp_make_space(lldp, 0); + + return 0; +} + +_public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) { + assert_return(lldp, -EINVAL); + assert_return(mask != 0, -EINVAL); + + lldp->capability_mask = mask; + + return 0; } diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 768211a315..589117f56e 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "sd-event.h" #include "sd-lldp.h" @@ -29,7 +30,6 @@ #include "alloc-util.h" #include "fd-util.h" #include "lldp-network.h" -#include "lldp-tlv.h" #include "lldp.h" #include "macro.h" #include "string-util.h" @@ -38,211 +38,8 @@ #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp" #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc" -static int test_fd[2]; - -static struct ether_addr mac_addr = { - .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} -}; - -static int lldp_build_tlv_packet(tlv_packet **ret) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *m = NULL; - const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR; - struct ether_header ether = { - .ether_type = htons(ETHERTYPE_LLDP), - }; - - /* Append Ethernet header */ - memcpy(ðer.ether_dhost, lldp_dst, ETHER_ADDR_LEN); - memcpy(ðer.ether_shost, &mac_addr, ETHER_ADDR_LEN); - - assert_se(tlv_packet_new(&m) >= 0); - - assert_se(tlv_packet_append_bytes(m, ðer, sizeof(struct ether_header)) >= 0); - - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0); - - assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0); - assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* port name */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0); - - assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0); - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* ttl */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0); - - assert_se(tlv_packet_append_u16(m, 170) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* system name */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0); - - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME, - strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0); - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* system descrition */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0); - - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC, - strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* Mark end of packet */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0); - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - *ret = m; - - m = NULL; - - return 0; -} - -static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) { - uint8_t *p, subtype; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0); - assert_se(tlv_packet_read_u8(m, &subtype) >= 0); - - switch (subtype) { - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - - *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS; - assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0); - - assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0); - - break; - default: - assert_not_reached("Unhandled option"); - } - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_port_id_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - uint8_t subtype; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0); - - assert_se(tlv_packet_read_u8(m, &subtype) >= 0); - - switch (subtype) { - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length-1); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_PORT) == 1); - break; - default: - assert_not_reached("Unhandled option"); - } - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_system_name_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0); - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 1; -} - -static int lldp_parse_system_desc_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0); - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_ttl_tlv(tlv_packet *m) { - uint16_t ttl; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0); - assert_se(tlv_packet_read_u16(m, &ttl) >= 0); - - assert_se(ttl == 170); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_get_destination_type(tlv_packet *m) { - int dest; - - assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0); - assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE); - - return 0; -} - -static int lldp_parse_tlv_packet(tlv_packet *m, int len) { - uint8_t subtype; - - assert_se(tlv_packet_parse_pdu(m, len) >= 0); - assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0); - assert_se(lldp_parse_port_id_tlv(m) >= 0); - assert_se(lldp_parse_system_name_tlv(m) >= 0); - assert_se(lldp_parse_ttl_tlv(m) >= 0); - assert_se(lldp_parse_system_desc_tlv(m) >= 0); - - assert_se(lldp_get_destination_type(m) >= 0); - - return 0; -} - -static void test_parser(void) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *tlv = NULL; - - /* form a packet */ - lldp_build_tlv_packet(&tlv); - /* parse the packet */ - tlv_packet_parse_pdu(tlv, tlv->length); - /* verify */ - lldp_parse_tlv_packet(tlv, tlv->length); -} +static int test_fd[2] = { -1, -1 }; +static int lldp_handler_calls; int lldp_network_bind_raw_socket(int ifindex) { if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0) @@ -251,15 +48,14 @@ int lldp_network_bind_raw_socket(int ifindex) { return test_fd[0]; } -static int lldp_handler_calls; -static void lldp_handler (sd_lldp *lldp, int event, void *userdata) { +static void lldp_handler (sd_lldp *lldp, void *userdata) { lldp_handler_calls++; } static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) { int r; - r = sd_lldp_new(42, lldp); + r = sd_lldp_new(lldp, 42); if (r < 0) return r; @@ -296,13 +92,8 @@ static int stop_lldp(sd_lldp *lldp) { } static void test_receive_basic_packet(sd_event *e) { - sd_lldp *lldp; - sd_lldp_packet **packets; - uint8_t type, *data; - uint16_t length, ttl; - int dest_type; - char *str; - uint8_t frame[] = { + + static const uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ @@ -319,51 +110,53 @@ static void test_receive_basic_packet(sd_event *e) { 0x00, 0x00 /* End Of LLDPDU */ }; + sd_lldp *lldp; + sd_lldp_neighbor **neighbors; + uint8_t type; + const void *data; + uint16_t ttl; + size_t length; + const char *str; + lldp_handler_calls = 0; assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 1); - assert_se(sd_lldp_get_packets(lldp, &packets) == 1); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); - assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0); + assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0); assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); assert_se(length == ETH_ALEN); assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN)); - assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0); + assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0); assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME); assert_se(length == 3); assert_se(strneq((char *) data, "1/3", 3)); - assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0); - assert_se(length == 4); - assert_se(strneq(str, "Port", 4)); + assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0); + assert_se(streq(str, "Port")); - assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0); - assert_se(length == 3); - assert_se(strneq(str, "SYS", 3)); + assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0); + assert_se(streq(str, "SYS")); - assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0); - assert_se(length == 4); /* This is the real length in the TLV packet */ - assert_se(strneq(str, "foo", 3)); + assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0); + assert_se(streq(str, "foo")); - assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0); + assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0); assert_se(ttl == 120); - assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0); - assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE); - - sd_lldp_packet_unref(packets[0]); - free(packets); + sd_lldp_neighbor_unref(neighbors[0]); + free(neighbors); assert_se(stop_lldp(lldp) == 0); } static void test_receive_incomplete_packet(sd_event *e) { sd_lldp *lldp; - sd_lldp_packet **packets; + sd_lldp_neighbor **neighbors; uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ @@ -383,18 +176,14 @@ static void test_receive_incomplete_packet(sd_event *e) { assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 0); - assert_se(sd_lldp_get_packets(lldp, &packets) == 0); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0); assert_se(stop_lldp(lldp) == 0); } static void test_receive_oui_packet(sd_event *e) { sd_lldp *lldp; - sd_lldp_packet **packets; - uint32_t id32; - uint16_t id16, len; - uint8_t flags; - char *str; + sd_lldp_neighbor **neighbors; uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ @@ -426,29 +215,30 @@ static void test_receive_oui_packet(sd_event *e) { assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 1); - assert_se(sd_lldp_get_packets(lldp, &packets) == 1); - - assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0); - assert_se(id16 == 0x1234); - - assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0); - assert_se(flags == 1); - assert_se(id16 == 0x7788); - - assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0); - assert_se(id16 == 0x1234); - assert_se(len == 6); - assert_se(strneq(str, "Vlan51", 6)); - - assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0); - assert_se(id16 == 0x0102); - - assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0); - assert_se(flags == 1); - assert_se(id32 == 0x00140012); - - sd_lldp_packet_unref(packets[0]); - free(packets); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); + + assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_CHASSIS_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_PORT_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_TTL) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_END) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0); + + sd_lldp_neighbor_unref(neighbors[0]); + free(neighbors); assert_se(stop_lldp(lldp) == 0); } @@ -456,7 +246,7 @@ static void test_receive_oui_packet(sd_event *e) { int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; - test_parser(); + log_set_max_level(LOG_DEBUG); /* LLDP reception tests */ assert_se(sd_event_new(&e) == 0); diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 62051992ef..26b283f60d 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -187,32 +187,7 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char return network_link_get_strv(ifindex, "DNSSEC_NTA", nta); } -_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { - _cleanup_free_ char *s = NULL, *p = NULL; - size_t size; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(lldp, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0) - return -ENOMEM; - - r = read_full_file(p, &s, &size); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (size <= 0) - return -ENODATA; - - *lldp = s; - s = NULL; - - return 0; -} - -int sd_network_link_get_timezone(int ifindex, char **ret) { +_public_ int sd_network_link_get_timezone(int ifindex, char **ret) { return network_link_get_string(ifindex, "TIMEZONE", ret); } diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 185bdaf293..eecdebd25d 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -23,6 +23,7 @@ #include "sd-device.h" #include "sd-hwdb.h" +#include "sd-lldp.h" #include "sd-netlink.h" #include "sd-network.h" @@ -30,6 +31,7 @@ #include "arphrd-list.h" #include "device-util.h" #include "ether-addr-util.h" +#include "fd-util.h" #include "hwdb-util.h" #include "lldp.h" #include "local-addresses.h" @@ -38,6 +40,7 @@ #include "pager.h" #include "parse-util.h" #include "socket-util.h" +#include "sparse-endian.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" @@ -745,162 +748,29 @@ static int link_status(int argc, char *argv[], void *userdata) { return 0; } -const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_; -LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_; - -static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = { - [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O", - [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P", - [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B", - [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W", - [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R", - [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T", - [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D", - [LLDP_SYSTEM_CAPABILITIES_STATION] = "A", - [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C", - [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S", - [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M", - [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A", -}; - -DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities); - -static char *lldp_system_caps(uint16_t cap) { - _cleanup_free_ char *s = NULL, *t = NULL; - char *capability; - - t = strdup("[ "); - if (!t) - return NULL; - - if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) { - s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR)); - if (!s) - return NULL; - - free(t); - } - - if (!s) { - s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX)); - if (!s) - return NULL; - - free(t); - } +static char *lldp_capabilities_to_string(uint16_t x) { + static const char characters[] = { + 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm', + }; + char *ret; + unsigned i; - t = strappend(s, "]"); - if (!t) + ret = new(char, ELEMENTSOF(characters) + 1); + if (!ret) return NULL; - free(s); - capability = t; + for (i = 0; i < ELEMENTSOF(characters); i++) + ret[i] = (x & (1U << i)) ? characters[i] : '.'; - s = NULL; - t = NULL; - - return capability; + ret[i] = 0; + return ret; } static int link_lldp_status(int argc, char *argv[], void *userdata) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; - double ttl = -1; - uint32_t capability; int i, r, c, j; - const char *p; - char **s; pager_open_if_enabled(); @@ -925,88 +795,85 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { return rtnl_log_parse_error(c); if (arg_legend) - printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability"); + printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", + "LINK", + "CHASSIS ID", + "SYSTEM NAME", + "CAPS", + "PORT ID", + "PORT DESCRIPTION"); for (i = j = 0; i < c; i++) { - _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL; - _cleanup_strv_free_ char **l = NULL; - - r = sd_network_link_get_lldp(links[i].ifindex, &lldp); - if (r < 0) - continue; - - l = strv_split_newlines(lldp); - if (!l) - return -ENOMEM; - - STRV_FOREACH(s, l) { - - p = *s; - for (;;) { - _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s); - - if (r == 0) - break; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; - r = split_pair(word, "=", &a, &b); - if (r < 0) - continue; + if (asprintf(&p, "/run/systemd/netif/lldp/%i", links[i].ifindex) < 0) + return log_oom(); - if (streq(a, "_Chassis")) { - r = free_and_strdup(&chassis, b); - if (r < 0) - return r; - - } else if (streq(a, "_Port")) { - r = free_and_strdup(&port, b); - if (r < 0) - return r; - - } else if (streq(a, "_TTL")) { - long long unsigned x = 0; - usec_t time; - - r = safe_atollu(b, &x); - if (r < 0 || (usec_t) x != x) - return log_warning_errno(r < 0 ? r : ERANGE, - "Failed to parse TTL \"%s\": %m", b); + f = fopen(p, "re"); + if (!f) { + if (errno == ENOENT) + continue; - time = now(clock_boottime_or_monotonic()); - if (x < time) - continue; + log_warning_errno(errno, "Failed to open %s, ignoring: %m", p); + continue; + } - ttl = (double) (x - time) / USEC_PER_SEC; + for (;;) { + const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL; + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + _cleanup_free_ void *raw = NULL; + uint16_t cc; + le64_t u; + size_t l; - } else if (streq(a, "_CAP")) { - sscanf(b, "%x", &capability); + l = fread(&u, 1, sizeof(u), f); + if (l == 0 && feof(f)) /* EOF */ + break; + if (l != sizeof(u)) { + log_warning("Premature end of file, ignoring."); + break; + } - cap = lldp_system_caps(capability); - } + raw = new(uint8_t, le64toh(u)); + if (!raw) + return log_oom(); + if (fread(raw, 1, le64toh(u), f) != le64toh(u)) { + log_warning("Premature end of file, ignoring."); + break; } - if (ttl >= 0) { - printf("%10s %24s %16s %16f %16s\n", - links[i].name, - strna(chassis), strna(port), - ttl, cap); - j++; + r = sd_lldp_neighbor_from_raw(&n, raw, le64toh(u)); + if (r < 0) { + log_warning_errno(r, "Failed to parse LLDP data, ignoring: %m"); + break; } + + (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); + (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); + (void) sd_lldp_neighbor_get_system_name(n, &system_name); + (void) sd_lldp_neighbor_get_port_description(n, &port_description); + + if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) + capabilities = lldp_capabilities_to_string(cc); + + printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", + links[i].name, + strna(chassis_id), + strna(system_name), + strna(capabilities), + strna(port_id), + strna(port_description)); } } - if (arg_legend) { - printf("\nCapability Codes:\n" - "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n" - "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n" - "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n"); - - printf("Total entries displayed: %d\n", j); - } + if (arg_legend) + printf("\nCapabilities:\n" + "o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;\n" + "t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;\n" + "s - Service VLAN, m - Two-port MAC Relay (TPMR)\n\n" + "Total entries displayed: %i\n", j); return 0; } @@ -1022,7 +889,7 @@ static void help(void) { "Commands:\n" " list List links\n" " status [LINK...] Show link status\n" - " lldp Show lldp information\n" + " lldp Show lldp neighbors\n" , program_invocation_short_name); } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index e63af3afdb..02fb04e0cb 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -26,6 +26,7 @@ #include "dhcp-lease-internal.h" #include "fd-util.h" #include "fileio.h" +#include "lldp.h" #include "netlink-util.h" #include "network-internal.h" #include "networkd-link.h" @@ -103,7 +104,7 @@ bool link_lldp_enabled(Link *link) { if (link->network->bridge) return false; - return link->network->lldp; + return link->network->lldp_mode != LLDP_MODE_NO; } static bool link_ipv4_forward_enabled(Link *link) { @@ -347,18 +348,15 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac); if (r < 0) - log_link_debug(link, "MAC address not found for new device, continuing without"); + log_link_debug_errno(link, r, "MAC address not found for new device, continuing without"); - r = asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex); - if (r < 0) + if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0) return -ENOMEM; - r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex); - if (r < 0) + if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0) return -ENOMEM; - r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex); - if (r < 0) + if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0) return -ENOMEM; r = hashmap_ensure_allocated(&manager->links, NULL); @@ -409,7 +407,6 @@ static void link_free(Link *link) { free(link->lease_file); sd_lldp_unref(link->lldp); - free(link->lldp_file); sd_ipv4ll_unref(link->ipv4ll); @@ -1218,7 +1215,7 @@ static int link_set_bridge(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m"); - if(link->network->cost != 0) { + if (link->network->cost != 0) { r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m"); @@ -1237,24 +1234,83 @@ static int link_set_bridge(Link *link) { return r; } -static void lldp_handler(sd_lldp *lldp, int event, void *userdata) { - Link *link = userdata; - int r; +static int link_lldp_save(Link *link) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + sd_lldp_neighbor **l = NULL; + int n = 0, r, i; assert(link); - assert(link->network); - assert(link->manager); + assert(link->lldp_file); + + if (!link->lldp) { + (void) unlink(link->lldp_file); + return 0; + } + + r = sd_lldp_get_neighbors(link->lldp, &l); + if (r < 0) + goto finish; + if (r == 0) { + (void) unlink(link->lldp_file); + goto finish; + } + + n = r; + + r = fopen_temporary(link->lldp_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); - switch (event) { - case SD_LLDP_EVENT_UPDATE_INFO: - r = sd_lldp_save(link->lldp, link->lldp_file); + for (i = 0; i < n; i++) { + const void *p; + le64_t u; + size_t sz; + + r = sd_lldp_neighbor_get_raw(l[i], &p, &sz); if (r < 0) - log_link_warning_errno(link, r, "Could not save LLDP: %m"); + goto finish; + + u = htole64(sz); + (void) fwrite(&u, 1, sizeof(u), f); + (void) fwrite(p, 1, sz, f); + } - break; - default: - break; + r = fflush_and_check(f); + if (r < 0) + goto finish; + + if (rename(temp_path, link->lldp_file) < 0) { + r = -errno; + goto finish; } + +finish: + if (r < 0) { + (void) unlink(link->lldp_file); + if (temp_path) + (void) unlink(temp_path); + + log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file); + } + + if (l) { + for (i = 0; i < n; i++) + sd_lldp_neighbor_unref(l[i]); + free(l); + } + + return r; +} + +static void lldp_handler(sd_lldp *lldp, void *userdata) { + Link *link = userdata; + + assert(link); + + (void) link_lldp_save(link); } static int link_acquire_ipv6_conf(Link *link) { @@ -2116,7 +2172,14 @@ static int link_configure(Link *link) { } if (link_lldp_enabled(link)) { - r = sd_lldp_new(link->ifindex, &link->lldp); + r = sd_lldp_new(&link->lldp, link->ifindex); + if (r < 0) + return r; + + r = sd_lldp_match_capabilities(link->lldp, + link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ? + _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS : + _LLDP_SYSTEM_CAPABILITIES_ALL); if (r < 0) return r; @@ -2714,6 +2777,8 @@ int link_save(Link *link) { return 0; } + link_lldp_save(link); + admin_state = link_state_to_string(link->state); assert(admin_state); @@ -2953,19 +3018,6 @@ int link_save(Link *link) { } } - if (link->lldp) { - assert(link->network); - - r = sd_lldp_save(link->lldp, link->lldp_file); - if (r < 0) - goto fail; - - fprintf(f, - "LLDP_FILE=%s\n", - link->lldp_file); - } else - unlink(link->lldp_file); - r = fflush_and_check(f); if (r < 0) goto fail; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 409df1709f..d67da5d7b6 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -40,7 +40,7 @@ Network.DHCPServer, config_parse_bool, Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) -Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) +Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 4315790093..a6512d26e5 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -1013,3 +1013,13 @@ static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES); + +DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting."); + +static const char* const lldp_mode_table[_LLDP_MODE_MAX] = { + [LLDP_MODE_NO] = "no", + [LLDP_MODE_YES] = "yes", + [LLDP_MODE_ROUTERS_ONLY] = "routers-only", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 03c3f206c3..9dcebfbf7b 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -58,6 +58,14 @@ typedef enum DHCPUseDomains { _DHCP_USE_DOMAINS_INVALID = -1, } DHCPUseDomains; +typedef enum LLDPMode { + LLDP_MODE_NO = 0, + LLDP_MODE_YES = 1, + LLDP_MODE_ROUTERS_ONLY = 2, + _LLDP_MODE_MAX, + _LLDP_MODE_INVALID = -1, +} LLDPMode; + struct Network { Manager *manager; @@ -137,7 +145,7 @@ struct Network { struct ether_addr *mac; unsigned mtu; - bool lldp; + LLDPMode lldp_mode; LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); @@ -181,6 +189,7 @@ int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigne int config_parse_dhcp_server_ntp(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_dnssec_negative_trust_anchors(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_use_domains(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_lldp_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); /* Legacy IPv4LL support */ int config_parse_ipv4ll(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); @@ -197,3 +206,6 @@ IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_; DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_; + +const char* lldp_mode_to_string(LLDPMode m) _const_; +LLDPMode lldp_mode_from_string(const char *s) _pure_; diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 4c896e7fc0..11b89258ed 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -30,22 +30,12 @@ _SD_BEGIN_DECLARATIONS; -enum { - SD_LLDP_EVENT_UPDATE_INFO = 0, -}; - -enum { - SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE, - SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE, - SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE, -}; - typedef struct sd_lldp sd_lldp; -typedef struct sd_lldp_packet sd_lldp_packet; +typedef struct sd_lldp_neighbor sd_lldp_neighbor; -typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, int event, void *userdata); +typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, void *userdata); -int sd_lldp_new(int ifindex, sd_lldp **ret); +int sd_lldp_new(sd_lldp **ret, int ifindex); sd_lldp* sd_lldp_unref(sd_lldp *lldp); int sd_lldp_start(sd_lldp *lldp); @@ -55,32 +45,46 @@ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority); int sd_lldp_detach_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); -int sd_lldp_save(sd_lldp *lldp, const char *file); - -int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl); -int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length); -int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length); -int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data); -int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length); - -/* IEEE 802.1 organizationally specific TLVs */ -int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id); -int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id); -int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length); -int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id); -int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id); - -sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); -sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); - -int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); -int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); +/* Controls how much and what to store in the neighbors database */ +int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n); +int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask); + +int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors); + +int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size); +sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n); +sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n); + +/* Access to LLDP frame metadata */ +int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); + +/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */ +int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); +int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); +int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret); + +/* Low-level, iterative TLV access. This is for evertyhing else, it iteratively goes through all available TLVs + * (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */ +int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n); +int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n); +int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type); +int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type); +int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype); +int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype); +int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref); -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref); _SD_END_DECLARATIONS; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index e20d12c44d..56986c984d 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -133,8 +133,6 @@ int sd_network_link_get_dnssec(int ifindex, char **dnssec); */ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta); -int sd_network_link_get_lldp(int ifindex, char **lldp); - /* Get the search DNS domain names for a given link. */ int sd_network_link_get_search_domains(int ifindex, char ***domains); -- cgit v1.2.3-54-g00ecf From 0070333f26543a319a17aee8b22bdde4071630c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 18:20:40 +0100 Subject: networkctl: split out system status stuff into its own function --- src/network/networkctl.c | 67 ++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index eecdebd25d..058fc864b6 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -663,12 +663,46 @@ static int link_status_one( return 0; } +static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { + _cleanup_free_ char *operational_state = NULL; + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL; + const char *on_color_operational, *off_color_operational; + + assert(rtnl); + + sd_network_get_operational_state(&operational_state); + operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); + + printf("%s%s%s State: %s%s%s\n", + on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, + on_color_operational, strna(operational_state), off_color_operational); + + dump_addresses(rtnl, " Address: ", 0); + dump_gateways(rtnl, hwdb, " Gateway: ", 0); + + sd_network_get_dns(&dns); + dump_list(" DNS: ", dns); + + sd_network_get_search_domains(&search_domains); + dump_list("Search Domains: ", search_domains); + + sd_network_get_route_domains(&route_domains); + dump_list(" Route Domains: ", route_domains); + + sd_network_get_ntp(&ntp); + dump_list(" NTP: ", ntp); + + return 0; +} + static int link_status(int argc, char *argv[], void *userdata) { _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; char **name; int r; + pager_open_if_enabled(); + r = sd_netlink_open(&rtnl); if (r < 0) return log_error_errno(r, "Failed to connect to netlink: %m"); @@ -677,37 +711,8 @@ static int link_status(int argc, char *argv[], void *userdata) { if (r < 0) log_debug_errno(r, "Failed to open hardware database: %m"); - if (argc <= 1 && !arg_all) { - _cleanup_free_ char *operational_state = NULL; - _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains; - const char *on_color_operational, *off_color_operational; - - sd_network_get_operational_state(&operational_state); - operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - - printf("%s%s%s State: %s%s%s\n", - on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, - on_color_operational, strna(operational_state), off_color_operational); - - dump_addresses(rtnl, " Address: ", 0); - dump_gateways(rtnl, hwdb, " Gateway: ", 0); - - sd_network_get_dns(&dns); - dump_list(" DNS: ", dns); - - sd_network_get_search_domains(&search_domains); - dump_list("Search Domains: ", search_domains); - - sd_network_get_route_domains(&route_domains); - dump_list(" Route Domains: ", route_domains); - - sd_network_get_ntp(&ntp); - dump_list(" NTP: ", ntp); - - return 0; - } - - pager_open_if_enabled(); + if (argc <= 1 && !arg_all) + return system_status(rtnl, hwdb); if (arg_all) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; -- cgit v1.2.3-54-g00ecf From 1fb82beb38b6fc98b68b5adbb1232c27d0b64c60 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 18:21:17 +0100 Subject: networkctl: fix dispatch_verb() table VERB_DEFAULT may only appear once. --- src/network/networkctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 058fc864b6..0c5a303174 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -956,9 +956,9 @@ static int parse_argv(int argc, char *argv[]) { static int networkctl_main(int argc, char *argv[]) { const Verb verbs[] = { - { "list", VERB_ANY, 1, VERB_DEFAULT, list_links }, - { "status", 1, VERB_ANY, 0, link_status }, - { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status }, + { "list", VERB_ANY, 1, VERB_DEFAULT, list_links }, + { "status", VERB_ANY, VERB_ANY, 0, link_status }, + { "lldp", VERB_ANY, 1, 0, link_lldp_status }, {} }; -- cgit v1.2.3-54-g00ecf From 7d367b45f6f7151f092e982a4d0685231d31b824 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 18:26:18 +0100 Subject: networkctl: add new call that unifies link data acquisition between "status" and "lldp" verbs --- src/network/networkctl.c | 60 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 0c5a303174..9838e7a5a6 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -197,13 +197,13 @@ static void setup_state_to_color(const char *state, const char **on, const char *on = *off = ""; } -static int list_links(int argc, char *argv[], void *userdata) { +static int acquire_link_info(LinkInfo **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - _cleanup_free_ LinkInfo *links = NULL; - int r, c, i; - pager_open_if_enabled(); + int r; + + assert(ret); r = sd_netlink_open(&rtnl); if (r < 0) @@ -221,12 +221,30 @@ static int list_links(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to enumerate links: %m"); - if (arg_legend) - printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP"); + r = decode_and_sort_links(reply, ret); + if (r < 0) + return rtnl_log_parse_error(r); + + return r; +} - c = decode_and_sort_links(reply, &links); +static int list_links(int argc, char *argv[], void *userdata) { + _cleanup_free_ LinkInfo *links = NULL; + int c, i; + + c = acquire_link_info(&links); if (c < 0) - return rtnl_log_parse_error(c); + return c; + + pager_open_if_enabled(); + + if (arg_legend) + printf("%3s %-16s %-18s %-11s %-10s\n", + "IDX", + "LINK", + "TYPE", + "OPERATIONAL", + "SETUP"); for (i = 0; i < c; i++) { _cleanup_free_ char *setup_state = NULL, *operational_state = NULL; @@ -772,32 +790,14 @@ static char *lldp_capabilities_to_string(uint16_t x) { } static int link_lldp_status(int argc, char *argv[], void *userdata) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; int i, r, c, j; - pager_open_if_enabled(); - - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); - - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_message_request_dump(req, true); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return log_error_errno(r, "Failed to enumerate links: %m"); - - c = decode_and_sort_links(reply, &links); + c = acquire_link_info(&links); if (c < 0) - return rtnl_log_parse_error(c); + return c; + + pager_open_if_enabled(); if (arg_legend) printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", -- cgit v1.2.3-54-g00ecf From e997c4b09d519ec2dcc58a7bb34166eacca8e599 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 18:57:11 +0100 Subject: networkctl: extend "networkctl list" and "networctl lldp" to optionally take interface names This way, the output may be reduced to only show data about the specified interfaces. --- man/networkctl.xml | 33 ++++++++--- src/network/networkctl.c | 151 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 135 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/man/networkctl.xml b/man/networkctl.xml index c688714b30..24e1de6986 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -102,12 +102,14 @@ list + LINK... - Show a list of existing links and their - status. Produces output similar to -IDX LINK TYPE OPERATIONAL SETUP + Show a list of existing links and their status. If no further arguments are specified shows all links, + otherwise just the specified links. Produces output similar to: + + IDX LINK TYPE OPERATIONAL SETUP 1 lo loopback carrier unmanaged 2 eth0 ether routable configured 3 virbr0 ether no-carrier unmanaged @@ -128,10 +130,10 @@ IDX LINK TYPE OPERATIONAL SETUP state, kernel module driver, hardware and IP address, configured DNS servers, etc. - When no links are specified, routable links are - shown. Also see the option . + When no links are specified, an overall network status is shown. Also see the option + . - Produces output similar to + Produces output similar to: ● State: routable Address: 10.193.76.5 on eth0 @@ -148,11 +150,26 @@ IDX LINK TYPE OPERATIONAL SETUP lldp + LINK... - Show LLDP (Link Layer Discovery Protocol) - status. + Show discovered LLDP (Link Layer Discovery Protocol) neighbors. If one or more link names are specified + only neighbors on those interfaces are shown. Otherwise shows discovered neighbors on all interfaces. Note + that for this feature to work, LLDP= must be turned on on the specific interface, see + systemd.network5 for + details. + + Produces output similar to: + LINK CHASSIS ID SYSTEM NAME CAPS PORT ID PORT DESCRIPTION +enp0s25 00:e0:4c:00:00:00 GS1900 ..b........ 2 Port #2 + +Capability Flags: +o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router; +t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN; +s - Service VLAN, m - Two-port MAC Relay (TPMR) + +1 neighbors listed. diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 9838e7a5a6..d19bf131cd 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -73,7 +73,7 @@ static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) * to show a more useful type string for * them */ - (void)sd_device_get_devtype(d, &devtype); + (void) sd_device_get_devtype(d, &devtype); if (streq_ptr(devtype, "wlan")) id = "wlan"; @@ -107,7 +107,7 @@ static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) } typedef struct LinkInfo { - const char *name; + char name[IFNAMSIZ+1]; int ifindex; unsigned short iftype; } LinkInfo; @@ -118,44 +118,56 @@ static int link_info_compare(const void *a, const void *b) { return x->ifindex - y->ifindex; } -static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { - _cleanup_free_ LinkInfo *links = NULL; - size_t size = 0, c = 0; - sd_netlink_message *i; - int r; +static int decode_link_one(sd_netlink_message *m, LinkInfo *info) { + const char *name; + unsigned short iftype; + uint16_t type; + int ifindex, r; - for (i = m; i; i = sd_netlink_message_next(i)) { - const char *name; - unsigned short iftype; - uint16_t type; - int ifindex; + assert(m); + assert(info); - r = sd_netlink_message_get_type(i, &type); - if (r < 0) - return r; + r = sd_netlink_message_get_type(m, &type); + if (r < 0) + return r; - if (type != RTM_NEWLINK) - continue; + if (type != RTM_NEWLINK) + return 0; - r = sd_rtnl_message_link_get_ifindex(i, &ifindex); - if (r < 0) - return r; + r = sd_rtnl_message_link_get_ifindex(m, &ifindex); + if (r < 0) + return r; - r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name); - if (r < 0) - return r; + r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name); + if (r < 0) + return r; - r = sd_rtnl_message_link_get_type(i, &iftype); - if (r < 0) - return r; + r = sd_rtnl_message_link_get_type(m, &iftype); + if (r < 0) + return r; - if (!GREEDY_REALLOC(links, size, c+1)) + strncpy(info->name, name, sizeof(info->name)); + info->ifindex = ifindex; + info->iftype = iftype; + + return 1; +} + +static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { + _cleanup_free_ LinkInfo *links = NULL; + size_t allocated = 0, c = 0; + sd_netlink_message *i; + int r; + + for (i = m; i; i = sd_netlink_message_next(i)) { + if (!GREEDY_REALLOC(links, allocated, c+1)) return -ENOMEM; - links[c].name = name; - links[c].ifindex = ifindex; - links[c].iftype = iftype; - c++; + r = decode_link_one(i, links + c); + if (r < 0) + return r; + if (r > 0) + c++; } qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); @@ -197,7 +209,59 @@ static void setup_state_to_color(const char *state, const char **on, const char *on = *off = ""; } -static int acquire_link_info(LinkInfo **ret) { +static int acquire_link_info_strv(char **l, LinkInfo **ret) { + _cleanup_free_ LinkInfo *links = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + char **i; + size_t c = 0; + int r; + + assert(ret); + + links = new(LinkInfo, strv_length(l)); + if (!links) + return log_oom(); + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + STRV_FOREACH(i, l) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + int ifindex; + + if (parse_ifindex(*i, &ifindex) >= 0) + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex); + else { + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_message_append_string(req, IFLA_IFNAME, *i); + } + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_call(rtnl, req, 0, &reply); + if (r < 0) + return log_error_errno(r, "Failed to request link: %m"); + + r = decode_link_one(reply, links + c); + if (r < 0) + return r; + if (r > 0) + c++; + } + + qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); + + *ret = links; + links = NULL; + + return (int) c; +} + +static int acquire_link_info_all(LinkInfo **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; @@ -232,7 +296,10 @@ static int list_links(int argc, char *argv[], void *userdata) { _cleanup_free_ LinkInfo *links = NULL; int c, i; - c = acquire_link_info(&links); + if (argc > 1) + c = acquire_link_info_strv(argv + 1, &links); + else + c = acquire_link_info_all(&links); if (c < 0) return c; @@ -553,7 +620,6 @@ static int link_status_one( r = sd_netlink_message_append_string(req, IFLA_IFNAME, name); } - if (r < 0) return rtnl_log_create_error(r); @@ -793,7 +859,10 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { _cleanup_free_ LinkInfo *links = NULL; int i, r, c, j; - c = acquire_link_info(&links); + if (argc > 1) + c = acquire_link_info_strv(argv + 1, &links); + else + c = acquire_link_info_all(&links); if (c < 0) return c; @@ -874,11 +943,11 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { } if (arg_legend) - printf("\nCapabilities:\n" + printf("\nCapability Flags:\n" "o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;\n" "t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;\n" "s - Service VLAN, m - Two-port MAC Relay (TPMR)\n\n" - "Total entries displayed: %i\n", j); + "%i neighbors listed.\n", j); return 0; } @@ -892,9 +961,9 @@ static void help(void) { " --no-legend Do not show the headers and footers\n" " -a --all Show status for all links\n\n" "Commands:\n" - " list List links\n" + " list [LINK...] List links\n" " status [LINK...] Show link status\n" - " lldp Show lldp neighbors\n" + " lldp [LINK...] Show lldp neighbors\n" , program_invocation_short_name); } @@ -956,9 +1025,9 @@ static int parse_argv(int argc, char *argv[]) { static int networkctl_main(int argc, char *argv[]) { const Verb verbs[] = { - { "list", VERB_ANY, 1, VERB_DEFAULT, list_links }, + { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links }, { "status", VERB_ANY, VERB_ANY, 0, link_status }, - { "lldp", VERB_ANY, 1, 0, link_lldp_status }, + { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status }, {} }; -- cgit v1.2.3-54-g00ecf From b147503eb49c0510685d60268a59c95c744dd851 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 19:18:12 +0100 Subject: networkctl: rework interface data acquisition Let's always use the same calls to acquire interface data. Specifically port "networkctl status" to use acquire_link_info_strv() and acquire_link_info_all() like the other calls. --- src/network/networkctl.c | 220 +++++++++++++++++------------------------------ 1 file changed, 81 insertions(+), 139 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index d19bf131cd..144e52cbfa 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -110,6 +110,11 @@ typedef struct LinkInfo { char name[IFNAMSIZ+1]; int ifindex; unsigned short iftype; + struct ether_addr mac_address; + uint32_t mtu; + + bool has_mac_address:1; + bool has_mtu:1; } LinkInfo; static int link_info_compare(const void *a, const void *b) { @@ -119,10 +124,10 @@ static int link_info_compare(const void *a, const void *b) { } static int decode_link_one(sd_netlink_message *m, LinkInfo *info) { + static const struct ether_addr null_address = {}; const char *name; - unsigned short iftype; uint16_t type; - int ifindex, r; + int r; assert(m); assert(info); @@ -134,7 +139,7 @@ static int decode_link_one(sd_netlink_message *m, LinkInfo *info) { if (type != RTM_NEWLINK) return 0; - r = sd_rtnl_message_link_get_ifindex(m, &ifindex); + r = sd_rtnl_message_link_get_ifindex(m, &info->ifindex); if (r < 0) return r; @@ -142,13 +147,19 @@ static int decode_link_one(sd_netlink_message *m, LinkInfo *info) { if (r < 0) return r; - r = sd_rtnl_message_link_get_type(m, &iftype); + r = sd_rtnl_message_link_get_type(m, &info->iftype); if (r < 0) return r; strncpy(info->name, name, sizeof(info->name)); - info->ifindex = ifindex; - info->iftype = iftype; + + info->has_mac_address = + sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 && + memcmp(&info->mac_address, &null_address, sizeof(struct ether_addr)) != 0; + + info->has_mtu = + sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) && + info->mtu > 0; return 1; } @@ -209,23 +220,19 @@ static void setup_state_to_color(const char *state, const char **on, const char *on = *off = ""; } -static int acquire_link_info_strv(char **l, LinkInfo **ret) { +static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) { _cleanup_free_ LinkInfo *links = NULL; - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; char **i; size_t c = 0; int r; + assert(rtnl); assert(ret); links = new(LinkInfo, strv_length(l)); if (!links) return log_oom(); - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); - STRV_FOREACH(i, l) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; int ifindex; @@ -261,18 +268,13 @@ static int acquire_link_info_strv(char **l, LinkInfo **ret) { return (int) c; } -static int acquire_link_info_all(LinkInfo **ret) { +static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - int r; + assert(rtnl); assert(ret); - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); if (r < 0) return rtnl_log_create_error(r); @@ -293,13 +295,18 @@ static int acquire_link_info_all(LinkInfo **ret) { } static int list_links(int argc, char *argv[], void *userdata) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; - int c, i; + int c, i, r; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); if (argc > 1) - c = acquire_link_info_strv(argv + 1, &links); + c = acquire_link_info_strv(rtnl, argv + 1, &links); else - c = acquire_link_info_all(&links); + c = acquire_link_info_all(rtnl, &links); if (c < 0) return c; @@ -345,7 +352,7 @@ static int list_links(int argc, char *argv[], void *userdata) { } /* IEEE Organizationally Unique Identifier vendor string */ -static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) { +static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) { const char *description; char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc; int r; @@ -590,10 +597,10 @@ static void dump_list(const char *prefix, char **l) { static int link_status_one( sd_netlink *rtnl, sd_hwdb *hwdb, - const char *name) { + const LinkInfo *info) { + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL; _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL; - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_device_unrefp) sd_device *d = NULL; char devid[2 + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *t = NULL, *network = NULL; @@ -602,72 +609,23 @@ static int link_status_one( *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 short iftype; - int r, ifindex; - bool have_mac; - uint32_t mtu; + int r; assert(rtnl); - assert(name); - - if (parse_ifindex(name, &ifindex) >= 0) - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex); - else { - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_message_append_string(req, IFLA_IFNAME, name); - } - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return log_error_errno(r, "Failed to query link: %m"); - - r = sd_rtnl_message_link_get_ifindex(reply, &ifindex); - if (r < 0) - return rtnl_log_parse_error(r); - - r = sd_netlink_message_read_string(reply, IFLA_IFNAME, &name); - if (r < 0) - return rtnl_log_parse_error(r); - - r = sd_rtnl_message_link_get_type(reply, &iftype); - if (r < 0) - return rtnl_log_parse_error(r); - - have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0; - if (have_mac) { - const uint8_t *p; - bool all_zeroes = true; - - for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++) - if (*p != 0) { - all_zeroes = false; - break; - } - - if (all_zeroes) - have_mac = false; - } - - (void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu); + assert(info); - (void) sd_network_link_get_operational_state(ifindex, &operational_state); + (void) sd_network_link_get_operational_state(info->ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - (void) sd_network_link_get_setup_state(ifindex, &setup_state); + (void) sd_network_link_get_setup_state(info->ifindex, &setup_state); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); - (void) sd_network_link_get_dns(ifindex, &dns); - (void) sd_network_link_get_search_domains(ifindex, &search_domains); - (void) sd_network_link_get_route_domains(ifindex, &route_domains); - (void) sd_network_link_get_ntp(ifindex, &ntp); + (void) sd_network_link_get_dns(info->ifindex, &dns); + (void) sd_network_link_get_search_domains(info->ifindex, &search_domains); + (void) sd_network_link_get_route_domains(info->ifindex, &route_domains); + (void) sd_network_link_get_ntp(info->ifindex, &ntp); - sprintf(devid, "n%i", ifindex); + sprintf(devid, "n%i", info->ifindex); (void) sd_device_new_from_device_id(&d, devid); @@ -685,14 +643,14 @@ static int link_status_one( (void) sd_device_get_property_value(d, "ID_MODEL", &model); } - link_get_type_string(iftype, d, &t); + link_get_type_string(info->iftype, d, &t); - sd_network_link_get_network_file(ifindex, &network); + sd_network_link_get_network_file(info->ifindex, &network); - sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to); - sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by); + sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to); + sd_network_link_get_carrier_bound_by(info->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("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, info->ifindex, info->name); printf(" Link File: %s\n" " Network File: %s\n" @@ -713,23 +671,23 @@ static int link_status_one( if (model) printf(" Model: %s\n", model); - if (have_mac) { + if (info->has_mac_address) { _cleanup_free_ char *description = NULL; char ea[ETHER_ADDR_TO_STRING_MAX]; - ieee_oui(hwdb, &e, &description); + ieee_oui(hwdb, &info->mac_address, &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(&info->mac_address, ea), description); else - printf(" HW Address: %s\n", ether_addr_to_string(&e, ea)); + printf(" HW Address: %s\n", ether_addr_to_string(&info->mac_address, ea)); } - if (mtu > 0) - printf(" MTU: %u\n", mtu); + if (info->has_mtu) + printf(" MTU: %u\n", info->mtu); - dump_addresses(rtnl, " Address: ", ifindex); - dump_gateways(rtnl, hwdb, " Gateway: ", ifindex); + dump_addresses(rtnl, " Address: ", info->ifindex); + dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex); dump_list(" DNS: ", dns); dump_list(" Search Domains: ", search_domains); @@ -740,7 +698,7 @@ static int link_status_one( dump_list("Carrier Bound To: ", carrier_bound_to); dump_list("Carrier Bound By: ", carrier_bound_by); - (void) sd_network_link_get_timezone(ifindex, &tz); + (void) sd_network_link_get_timezone(info->ifindex, &tz); if (tz) printf(" Time Zone: %s", tz); @@ -780,10 +738,10 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { } static int link_status(int argc, char *argv[], void *userdata) { - _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - char **name; - int r; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; + _cleanup_free_ LinkInfo *links = NULL; + int r, c, i; pager_open_if_enabled(); @@ -795,43 +753,20 @@ static int link_status(int argc, char *argv[], void *userdata) { if (r < 0) log_debug_errno(r, "Failed to open hardware database: %m"); - if (argc <= 1 && !arg_all) + if (arg_all) + c = acquire_link_info_all(rtnl, &links); + else if (argc <= 1) return system_status(rtnl, hwdb); + else + c = acquire_link_info_strv(rtnl, argv + 1, &links); + if (c < 0) + return c; - if (arg_all) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_free_ LinkInfo *links = NULL; - int c, i; - - r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_message_request_dump(req, true); - if (r < 0) - return rtnl_log_create_error(r); - - r = sd_netlink_call(rtnl, req, 0, &reply); - if (r < 0) - return log_error_errno(r, "Failed to enumerate links: %m"); - - c = decode_and_sort_links(reply, &links); - if (c < 0) - return rtnl_log_parse_error(c); - - for (i = 0; i < c; i++) { - if (i > 0) - fputc('\n', stdout); - - link_status_one(rtnl, hwdb, links[i].name); - } - } else { - STRV_FOREACH(name, argv + 1) { - if (name != argv + 1) - fputc('\n', stdout); + for (i = 0; i < c; i++) { + if (i > 0) + fputc('\n', stdout); - link_status_one(rtnl, hwdb, *name); - } + link_status_one(rtnl, hwdb, links + i); } return 0; @@ -856,13 +791,18 @@ static char *lldp_capabilities_to_string(uint16_t x) { } static int link_lldp_status(int argc, char *argv[], void *userdata) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; - int i, r, c, j; + int i, r, c, m = 0; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); if (argc > 1) - c = acquire_link_info_strv(argv + 1, &links); + c = acquire_link_info_strv(rtnl, argv + 1, &links); else - c = acquire_link_info_all(&links); + c = acquire_link_info_all(rtnl, &links); if (c < 0) return c; @@ -877,7 +817,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { "PORT ID", "PORT DESCRIPTION"); - for (i = j = 0; i < c; i++) { + for (i = 0; i < c; i++) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; @@ -939,6 +879,8 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { strna(capabilities), strna(port_id), strna(port_description)); + + m++; } } @@ -947,7 +889,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { "o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;\n" "t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;\n" "s - Service VLAN, m - Two-port MAC Relay (TPMR)\n\n" - "%i neighbors listed.\n", j); + "%i neighbors listed.\n", m); return 0; } -- cgit v1.2.3-54-g00ecf From 7e5a080a943f81dfe0d71b0cb53094fe8fe6bc5a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 19:21:30 +0100 Subject: networkctl: simplify networkctl Move decode_and_sort_links() into acquire_info_all() which is the only place this is used. The result is then nicely symmetric to acquire_info_strv(). --- src/network/networkctl.c | 114 +++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 144e52cbfa..a415f988f6 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -106,6 +106,37 @@ static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) return 0; } +static void operational_state_to_color(const char *state, const char **on, const char **off) { + assert(on); + assert(off); + + if (streq_ptr(state, "routable")) { + *on = ansi_highlight_green(); + *off = ansi_normal(); + } else if (streq_ptr(state, "degraded")) { + *on = ansi_highlight_yellow(); + *off = ansi_normal(); + } else + *on = *off = ""; +} + +static void setup_state_to_color(const char *state, const char **on, const char **off) { + assert(on); + assert(off); + + if (streq_ptr(state, "configured")) { + *on = ansi_highlight_green(); + *off = ansi_normal(); + } else if (streq_ptr(state, "configuring")) { + *on = ansi_highlight_yellow(); + *off = ansi_normal(); + } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) { + *on = ansi_highlight_red(); + *off = ansi_normal(); + } else + *on = *off = ""; +} + typedef struct LinkInfo { char name[IFNAMSIZ+1]; int ifindex; @@ -123,7 +154,7 @@ static int link_info_compare(const void *a, const void *b) { return x->ifindex - y->ifindex; } -static int decode_link_one(sd_netlink_message *m, LinkInfo *info) { +static int decode_link(sd_netlink_message *m, LinkInfo *info) { static const struct ether_addr null_address = {}; const char *name; uint16_t type; @@ -164,62 +195,6 @@ static int decode_link_one(sd_netlink_message *m, LinkInfo *info) { return 1; } -static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { - _cleanup_free_ LinkInfo *links = NULL; - size_t allocated = 0, c = 0; - sd_netlink_message *i; - int r; - - for (i = m; i; i = sd_netlink_message_next(i)) { - if (!GREEDY_REALLOC(links, allocated, c+1)) - return -ENOMEM; - - r = decode_link_one(i, links + c); - if (r < 0) - return r; - if (r > 0) - c++; - } - - qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); - - *ret = links; - links = NULL; - - return (int) c; -} - -static void operational_state_to_color(const char *state, const char **on, const char **off) { - assert(on); - assert(off); - - if (streq_ptr(state, "routable")) { - *on = ansi_highlight_green(); - *off = ansi_normal(); - } else if (streq_ptr(state, "degraded")) { - *on = ansi_highlight_yellow(); - *off = ansi_normal(); - } else - *on = *off = ""; -} - -static void setup_state_to_color(const char *state, const char **on, const char **off) { - assert(on); - assert(off); - - if (streq_ptr(state, "configured")) { - *on = ansi_highlight_green(); - *off = ansi_normal(); - } else if (streq_ptr(state, "configuring")) { - *on = ansi_highlight_yellow(); - *off = ansi_normal(); - } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) { - *on = ansi_highlight_red(); - *off = ansi_normal(); - } else - *on = *off = ""; -} - static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) { _cleanup_free_ LinkInfo *links = NULL; char **i; @@ -253,7 +228,7 @@ static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) { if (r < 0) return log_error_errno(r, "Failed to request link: %m"); - r = decode_link_one(reply, links + c); + r = decode_link(reply, links + c); if (r < 0) return r; if (r > 0) @@ -270,6 +245,9 @@ static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) { static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_free_ LinkInfo *links = NULL; + size_t allocated = 0, c = 0; + sd_netlink_message *i; int r; assert(rtnl); @@ -287,11 +265,23 @@ static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) { if (r < 0) return log_error_errno(r, "Failed to enumerate links: %m"); - r = decode_and_sort_links(reply, ret); - if (r < 0) - return rtnl_log_parse_error(r); + for (i = reply; i; i = sd_netlink_message_next(i)) { + if (!GREEDY_REALLOC(links, allocated, c+1)) + return -ENOMEM; - return r; + r = decode_link(i, links + c); + if (r < 0) + return r; + if (r > 0) + c++; + } + + qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); + + *ret = links; + links = NULL; + + return (int) c; } static int list_links(int argc, char *argv[], void *userdata) { -- cgit v1.2.3-54-g00ecf From 691d4da98a1288d75ea62e470280684d075e9725 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 19:24:16 +0100 Subject: networkctl: make use of xsprintf() where we can --- src/network/networkctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index a415f988f6..59d5a38ff0 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -324,8 +324,8 @@ static int list_links(int argc, char *argv[], void *userdata) { sd_network_link_get_setup_state(links[i].ifindex, &setup_state); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); - sprintf(devid, "n%i", links[i].ifindex); - (void)sd_device_new_from_device_id(&d, devid); + xsprintf(devid, "n%i", links[i].ifindex); + (void) sd_device_new_from_device_id(&d, devid); link_get_type_string(links[i].iftype, d, &t); @@ -615,7 +615,7 @@ static int link_status_one( (void) sd_network_link_get_route_domains(info->ifindex, &route_domains); (void) sd_network_link_get_ntp(info->ifindex, &ntp); - sprintf(devid, "n%i", info->ifindex); + xsprintf(devid, "n%i", info->ifindex); (void) sd_device_new_from_device_id(&d, devid); -- cgit v1.2.3-54-g00ecf From 837f57da416be279ef5793e43b34e41247aa90a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 19:50:14 +0100 Subject: networkctl: extend "networkctl status" per-interface output to include LLDP info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a small and useful field to the "systemctl status" output: the router(s) the interface is connected to as reported via LLDP. Example output: ● 2: enp0s25 Link File: /usr/lib/systemd/network/99-default.link Type: ether State: degraded (configured) Path: pci-0000:00:19.0 Driver: e1000e Connected To: GS1900 on port 2 (foobar) i.e. the last line is the relevant one. --- src/network/networkctl.c | 137 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 59d5a38ff0..c5da24e75b 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -489,6 +489,9 @@ static int dump_gateways( _cleanup_free_ struct local_address *local = NULL; int r, n, i; + assert(rtnl); + assert(prefix); + n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local); if (n < 0) return n; @@ -538,6 +541,9 @@ static int dump_addresses( _cleanup_free_ struct local_address *local = NULL; int r, n, i; + assert(rtnl); + assert(prefix); + n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local); if (n < 0) return n; @@ -570,6 +576,92 @@ static int dump_addresses( return 0; } +static int open_lldp_neighbors(int ifindex, FILE **ret) { + _cleanup_free_ char *p = NULL; + FILE *f; + + if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0) + return -ENOMEM; + + f = fopen(p, "re"); + if (!f) + return -errno; + + *ret = f; + return 0; +} + +static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) { + _cleanup_free_ void *raw = NULL; + size_t l; + le64_t u; + int r; + + assert(f); + assert(ret); + + l = fread(&u, 1, sizeof(u), f); + if (l == 0 && feof(f)) + return 0; + if (l != sizeof(u)) + return -EBADMSG; + + raw = new(uint8_t, le64toh(u)); + if (!raw) + return -ENOMEM; + + if (fread(raw, 1, le64toh(u), f) != le64toh(u)) + return -EBADMSG; + + r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u)); + if (r < 0) + return r; + + return 1; +} + +static int dump_lldp_neighbors(const char *prefix, int ifindex) { + _cleanup_fclose_ FILE *f = NULL; + int r, c = 0; + + assert(prefix); + assert(ifindex > 0); + + r = open_lldp_neighbors(ifindex, &f); + if (r < 0) + return r; + + for (;;) { + const char *system_name = NULL, *port_id = NULL, *port_description = NULL; + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + + r = next_lldp_neighbor(f, &n); + if (r < 0) + return r; + if (r == 0) + break; + + printf("%*s", + (int) strlen(prefix), + c == 0 ? prefix : ""); + + (void) sd_lldp_neighbor_get_system_name(n, &system_name); + (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); + (void) sd_lldp_neighbor_get_port_description(n, &port_description); + + printf("%s on port %s", strna(system_name), strna(port_id)); + + if (!isempty(port_description)) + printf(" (%s)", port_description); + + putchar('\n'); + + c++; + } + + return c; +} + static void dump_list(const char *prefix, char **l) { char **i; @@ -692,6 +784,8 @@ static int link_status_one( if (tz) printf(" Time Zone: %s", tz); + (void) dump_lldp_neighbors(" Connected To: ", info->ifindex); + return 0; } @@ -809,50 +903,27 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { for (i = 0; i < c; i++) { _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *p = NULL; - - if (asprintf(&p, "/run/systemd/netif/lldp/%i", links[i].ifindex) < 0) - return log_oom(); - - f = fopen(p, "re"); - if (!f) { - if (errno == ENOENT) - continue; - log_warning_errno(errno, "Failed to open %s, ignoring: %m", p); + r = open_lldp_neighbors(links[i].ifindex, &f); + if (r == -ENOENT) + continue; + if (r < 0) { + log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex); continue; } for (;;) { const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL; _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; - _cleanup_free_ void *raw = NULL; uint16_t cc; - le64_t u; - size_t l; - l = fread(&u, 1, sizeof(u), f); - if (l == 0 && feof(f)) /* EOF */ - break; - if (l != sizeof(u)) { - log_warning("Premature end of file, ignoring."); - break; - } - - raw = new(uint8_t, le64toh(u)); - if (!raw) - return log_oom(); - - if (fread(raw, 1, le64toh(u), f) != le64toh(u)) { - log_warning("Premature end of file, ignoring."); - break; - } - - r = sd_lldp_neighbor_from_raw(&n, raw, le64toh(u)); + r = next_lldp_neighbor(f, &n); if (r < 0) { - log_warning_errno(r, "Failed to parse LLDP data, ignoring: %m"); + log_warning_errno(r, "Failed to read neighbor data: %m"); break; } + if (r == 0) + break; (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); @@ -895,7 +966,7 @@ static void help(void) { "Commands:\n" " list [LINK...] List links\n" " status [LINK...] Show link status\n" - " lldp [LINK...] Show lldp neighbors\n" + " lldp [LINK...] Show LLDP neighbors\n" , program_invocation_short_name); } -- cgit v1.2.3-54-g00ecf From 7cececb2ea707a6d9b063538cf986fd27edd8cd3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 19:59:32 +0100 Subject: networkd: turn on LLDP reception by default, in "routers-only" mode This way "networkctl status" becomes a bit more useful by default, as router information is just visible, without any further configuration. LLDP reception is fully passive and relatively low simple and low traffic, hence this should be safe to enable by default. --- man/systemd.network.xml | 2 +- src/network/networkd-network.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 2de2a550db..bbdcace563 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -339,7 +339,7 @@ routers-only. When true, incoming LLDP packets are accepted and a database of all LLDP neighbors maintained. If routers-only is set only LLDP data of various types of routers is collected and LLDP data about other types of devices ignored (such as stations, telephones and - others). If false, LLDP reception is disabled. Defaults to false. Use + others). If false, LLDP reception is disabled. Defaults to routers-only. Use networkctl1 to query the collected neighbor data. diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index a6512d26e5..935042260b 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -119,6 +119,8 @@ static int network_load_one(Manager *manager, const char *filename) { network->allow_port_to_be_root = true; network->unicast_flood = true; + network->lldp_mode = LLDP_MODE_ROUTERS_ONLY; + network->llmnr = RESOLVE_SUPPORT_YES; network->mdns = RESOLVE_SUPPORT_NO; network->dnssec_mode = _DNSSEC_MODE_INVALID; -- cgit v1.2.3-54-g00ecf From b295beea88a7f2c48897b2887acbe99937335c8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 20:43:03 +0100 Subject: networkd: rework how carrier bindings are serialized Instead of serializing the interface name, expose the interface index, since that's the only stable identifier. --- src/libsystemd/sd-network/sd-network.c | 62 +++++++++++++++++++++++++++++++--- src/network/networkctl.c | 31 ++++++++++++++--- src/network/networkd-link.c | 52 ++++++++++++++-------------- src/systemd/sd-network.h | 10 +++--- 4 files changed, 117 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 26b283f60d..037ffb6e75 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -207,12 +207,66 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret); } -_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) { - return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret); +static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { + _cleanup_free_ char *p = NULL, *s = NULL; + _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ int *ifis = NULL; + size_t allocated = 0, c = 0; + const char *x; + int r; + + assert_return(ifindex > 0, -EINVAL); + assert_return(ret, -EINVAL); + + if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, key, &s, NULL); + if (r == -ENOENT) + return -ENODATA; + if (r < 0) + return r; + if (isempty(s)) { + *ret = NULL; + return 0; + } + + x = s; + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&x, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + + r = parse_ifindex(word, &ifindex); + if (r < 0) + return r; + + if (!GREEDY_REALLOC(ifis, allocated, c + 1)) + return -ENOMEM; + + ifis[c++] = ifindex; + } + + if (!GREEDY_REALLOC(ifis, allocated, c + 1)) + return -ENOMEM; + ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/ + + *ret = ifis; + ifis = NULL; + + return c; +} + +_public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) { + return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret); } -_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) { - return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret); +_public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) { + return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret); } static inline int MONITOR_TO_FD(sd_network_monitor *m) { diff --git a/src/network/networkctl.c b/src/network/networkctl.c index c5da24e75b..8abb1eff9a 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -662,6 +662,30 @@ static int dump_lldp_neighbors(const char *prefix, int ifindex) { return c; } +static void dump_ifindexes(const char *prefix, const int *ifindexes) { + unsigned c; + + assert(prefix); + + if (!ifindexes || ifindexes[0] <= 0) + return; + + for (c = 0; ifindexes[c] > 0; c++) { + char name[IF_NAMESIZE+1]; + + printf("%*s", + (int) strlen(prefix), + c == 0 ? prefix : ""); + + if (if_indextoname(ifindexes[c], name)) + fputs(name, stdout); + else + printf("%i", ifindexes[c]); + + fputc('\n', stdout); + } +} + static void dump_list(const char *prefix, char **l) { char **i; @@ -689,8 +713,7 @@ static int link_status_one( 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; + _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL; int r; assert(rtnl); @@ -777,8 +800,8 @@ static int link_status_one( dump_list(" NTP: ", ntp); - dump_list("Carrier Bound To: ", carrier_bound_to); - dump_list("Carrier Bound By: ", carrier_bound_by); + dump_ifindexes("Carrier Bound To: ", carrier_bound_to); + dump_ifindexes("Carrier Bound By: ", carrier_bound_by); (void) sd_network_link_get_timezone(info->ifindex, &tz); if (tz) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 02fb04e0cb..32437d2195 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1622,7 +1622,7 @@ static int link_new_bound_by_list(Link *link) { m = link->manager; - HASHMAP_FOREACH (carrier, m->links, i) { + HASHMAP_FOREACH(carrier, m->links, i) { if (!carrier->network) continue; @@ -1641,7 +1641,7 @@ static int link_new_bound_by_list(Link *link) { if (list_updated) link_dirty(link); - HASHMAP_FOREACH (carrier, link->bound_by_links, i) { + HASHMAP_FOREACH(carrier, link->bound_by_links, i) { r = link_put_carrier(carrier, link, &carrier->bound_to_links); if (r < 0) return r; @@ -2631,7 +2631,6 @@ int link_carrier_reset(Link *link) { return 0; } - int link_update(Link *link, sd_netlink_message *m) { struct ether_addr mac; const char *ifname; @@ -2752,12 +2751,34 @@ int link_update(Link *link, sd_netlink_message *m) { r = link_carrier_lost(link); if (r < 0) return r; - } return 0; } +static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { + bool space = false; + Iterator i; + Link *link; + + assert(f); + assert(prefix); + + if (hashmap_isempty(h)) + return; + + fputs(prefix, f); + HASHMAP_FOREACH(link, h, i) { + if (space) + fputc(' ', f); + + fprintf(f, "%i", link->ifindex); + space = true; + } + + fputc('\n', f); +} + int link_save(Link *link) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -2958,27 +2979,8 @@ int link_save(Link *link) { fputc('\n', f); } - if (!hashmap_isempty(link->bound_to_links)) { - Link *carrier; - bool space = false; - - fputs("CARRIER_BOUND_TO=", f); - HASHMAP_FOREACH(carrier, link->bound_to_links, i) - fputs_with_space(f, carrier->ifname, NULL, &space); - - fputc('\n', f); - } - - if (!hashmap_isempty(link->bound_by_links)) { - Link *carrier; - bool space = false; - - fputs("CARRIER_BOUND_BY=", f); - HASHMAP_FOREACH(carrier, link->bound_by_links, i) - fputs_with_space(f, carrier->ifname, NULL, &space); - - fputc('\n', f); - } + print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links); + print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links); if (link->dhcp_lease) { struct in_addr address; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 56986c984d..0f13e2bae7 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -99,11 +99,11 @@ int sd_network_link_get_network_file(int ifindex, char **filename); /* Get DNS entries for a given link. These are string representations of * IP addresses */ -int sd_network_link_get_dns(int ifindex, char ***addr); +int sd_network_link_get_dns(int ifindex, char ***ret); /* Get NTP entries for a given link. These are domain names or string * representations of IP addresses */ -int sd_network_link_get_ntp(int ifindex, char ***addr); +int sd_network_link_get_ntp(int ifindex, char ***ret); /* Indicates whether or not LLMNR should be enabled for the link * Possible levels of support: yes, no, resolve @@ -139,11 +139,11 @@ int sd_network_link_get_search_domains(int ifindex, char ***domains); /* Get the route DNS domain names for a given link. */ int sd_network_link_get_route_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 carrier interface indexes to which current link is bound to. */ +int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes); /* Get the CARRIERS that are bound to current link. */ -int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers); +int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes); /* Get the timezone that was learnt on a specific link. */ int sd_network_link_get_timezone(int ifindex, char **timezone); -- cgit v1.2.3-54-g00ecf From 4abd866d6848373ede920b73856e1825d9f00ff8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Feb 2016 21:34:38 +0100 Subject: networkctl: add a couple of (void) casts Where we knowingly ignore possible error results, let's cast to void. --- src/network/networkctl.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 8abb1eff9a..21ad776d0d 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -318,16 +318,16 @@ static int list_links(int argc, char *argv[], void *userdata) { char devid[2 + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *t = NULL; - sd_network_link_get_operational_state(links[i].ifindex, &operational_state); + (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - sd_network_link_get_setup_state(links[i].ifindex, &setup_state); + (void) sd_network_link_get_setup_state(links[i].ifindex, &setup_state); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); xsprintf(devid, "n%i", links[i].ifindex); (void) sd_device_new_from_device_id(&d, devid); - link_get_type_string(links[i].iftype, d, &t); + (void) link_get_type_string(links[i].iftype, d, &t); printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n", links[i].ifindex, links[i].name, strna(t), @@ -748,12 +748,12 @@ static int link_status_one( (void) sd_device_get_property_value(d, "ID_MODEL", &model); } - link_get_type_string(info->iftype, d, &t); + (void) link_get_type_string(info->iftype, d, &t); - sd_network_link_get_network_file(info->ifindex, &network); + (void) sd_network_link_get_network_file(info->ifindex, &network); - sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to); - sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by); + (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to); + (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by); printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, info->ifindex, info->name); @@ -780,7 +780,7 @@ static int link_status_one( _cleanup_free_ char *description = NULL; char ea[ETHER_ADDR_TO_STRING_MAX]; - ieee_oui(hwdb, &info->mac_address, &description); + (void) ieee_oui(hwdb, &info->mac_address, &description); if (description) printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info->mac_address, ea), description); @@ -791,8 +791,8 @@ static int link_status_one( if (info->has_mtu) printf(" MTU: %u\n", info->mtu); - dump_addresses(rtnl, " Address: ", info->ifindex); - dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex); + (void) dump_addresses(rtnl, " Address: ", info->ifindex); + (void) dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex); dump_list(" DNS: ", dns); dump_list(" Search Domains: ", search_domains); @@ -819,26 +819,26 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { assert(rtnl); - sd_network_get_operational_state(&operational_state); + (void) sd_network_get_operational_state(&operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); printf("%s%s%s State: %s%s%s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, on_color_operational, strna(operational_state), off_color_operational); - dump_addresses(rtnl, " Address: ", 0); - dump_gateways(rtnl, hwdb, " Gateway: ", 0); + (void) dump_addresses(rtnl, " Address: ", 0); + (void) dump_gateways(rtnl, hwdb, " Gateway: ", 0); - sd_network_get_dns(&dns); + (void) sd_network_get_dns(&dns); dump_list(" DNS: ", dns); - sd_network_get_search_domains(&search_domains); + (void) sd_network_get_search_domains(&search_domains); dump_list("Search Domains: ", search_domains); - sd_network_get_route_domains(&route_domains); + (void) sd_network_get_route_domains(&route_domains); dump_list(" Route Domains: ", route_domains); - sd_network_get_ntp(&ntp); + (void) sd_network_get_ntp(&ntp); dump_list(" NTP: ", ntp); return 0; -- cgit v1.2.3-54-g00ecf From 5f02f341c08c2a1cd05cc5066ca94bc6aa43243c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Feb 2016 22:06:12 +0100 Subject: sd-network: use xsprintf() instead of asprintf() where we can --- src/libsystemd/sd-network/sd-network.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 037ffb6e75..580047d3ab 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -31,6 +31,7 @@ #include "fs-util.h" #include "macro.h" #include "parse-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -102,16 +103,16 @@ _public_ int sd_network_get_route_domains(char ***ret) { } static int network_link_get_string(int ifindex, const char *field, char **ret) { - _cleanup_free_ char *s = NULL, *p = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; + _cleanup_free_ char *s = NULL; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%i", ifindex) < 0) - return -ENOMEM; + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); - r = parse_env_file(p, NEWLINE, field, &s, NULL); + r = parse_env_file(path, NEWLINE, field, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -126,17 +127,16 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) { } static int network_link_get_strv(int ifindex, const char *key, char ***ret) { - _cleanup_free_ char *p = NULL, *s = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ char *s = NULL; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, key, &s, NULL); + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); + r = parse_env_file(path, NEWLINE, key, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -208,9 +208,10 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { } static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { - _cleanup_free_ char *p = NULL, *s = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; _cleanup_strv_free_ char **a = NULL; _cleanup_free_ int *ifis = NULL; + _cleanup_free_ char *s = NULL; size_t allocated = 0, c = 0; const char *x; int r; @@ -218,10 +219,8 @@ static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, key, &s, NULL); + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); + r = parse_env_file(path, NEWLINE, key, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) -- cgit v1.2.3-54-g00ecf From 33d5013db09729d3453d60a1a194016e27ef4fab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Feb 2016 22:12:14 +0100 Subject: networkctl: if there's no data from networkd about an iface show as "unmanaged" After all, if we know that an interface exists but networkd did not store any info about it, then it's definitely unmanaged by it. (Note that we add this fix-up to networkctl, and not to sd-network, simply because a missing file might also be result of the interface not existing.) --- src/network/networkctl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 21ad776d0d..b7b3b51325 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -321,7 +321,9 @@ static int list_links(int argc, char *argv[], void *userdata) { (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - (void) sd_network_link_get_setup_state(links[i].ifindex, &setup_state); + r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state); + if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */ + setup_state = strdup("unmanaged"); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); xsprintf(devid, "n%i", links[i].ifindex); @@ -722,7 +724,9 @@ static int link_status_one( (void) sd_network_link_get_operational_state(info->ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - (void) sd_network_link_get_setup_state(info->ifindex, &setup_state); + r = sd_network_link_get_setup_state(info->ifindex, &setup_state); + if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */ + setup_state = strdup("unmanaged"); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); (void) sd_network_link_get_dns(info->ifindex, &dns); -- cgit v1.2.3-54-g00ecf From 58fb367825b7ce72b466e24c422dd3eb6d5554f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Feb 2016 22:25:43 +0100 Subject: networkctl: print a nice warning when networkd isn't running --- src/network/networkctl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index b7b3b51325..27a758152e 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -1064,6 +1064,14 @@ static int networkctl_main(int argc, char *argv[]) { return dispatch_verb(argc, argv, verbs, NULL); } +static void warn_networkd_missing(void) { + + if (access("/run/systemd/netif/state", F_OK) >= 0) + return; + + fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n"); +} + int main(int argc, char* argv[]) { int r; @@ -1074,6 +1082,8 @@ int main(int argc, char* argv[]) { if (r <= 0) goto finish; + warn_networkd_missing(); + r = networkctl_main(argc, argv); finish: -- cgit v1.2.3-54-g00ecf From 273eec24f5ce230a185c75c89d47c562a4bf64fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Feb 2016 22:35:02 +0100 Subject: networkd: rework when LLDP reception is enabled Being on the link-layer LLDP is nothing we should turn on only when there's a link beat. Instead, turn it on, whenever the iface is UP regardless if there's a link beat or not. This closes the race between a link beat being available and us subscribing to LLDP as a result. --- src/network/networkd-link.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 32437d2195..aa8adf1eae 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -531,12 +531,6 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } - if (link->lldp) { - k = sd_lldp_stop(link->lldp); - if (k < 0) - r = log_link_warning_errno(link, k, "Could not stop LLDP: %m"); - } - return r; } @@ -1374,16 +1368,6 @@ static int link_acquire_conf(Link *link) { return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); } - if (link_lldp_enabled(link)) { - assert(link->lldp); - - log_link_debug(link, "Starting LLDP"); - - r = sd_lldp_start(link->lldp); - if (r < 0) - return log_link_warning_errno(link, r, "Could not start LLDP: %m"); - } - return 0; } @@ -2093,6 +2077,27 @@ static int link_drop_foreign_config(Link *link) { return 0; } +static int link_update_lldp(Link *link) { + int r; + + assert(link); + + if (!link->lldp) + return 0; + + if (link->flags & IFF_UP) { + r = sd_lldp_start(link->lldp); + if (r > 0) + log_link_debug(link, "Started LLDP."); + } else { + r = sd_lldp_stop(link->lldp); + if (r > 0) + log_link_debug(link, "Stopped LLDP."); + } + + return r; +} + static int link_configure(Link *link) { int r; @@ -2190,6 +2195,10 @@ static int link_configure(Link *link) { r = sd_lldp_set_callback(link->lldp, lldp_handler, link); if (r < 0) return r; + + r = link_update_lldp(link); + if (r < 0) + return r; } if (link_has_carrier(link)) { @@ -2736,6 +2745,10 @@ int link_update(Link *link, sd_netlink_message *m) { if (r < 0) return r; + r = link_update_lldp(link); + if (r < 0) + return r; + carrier_gained = !had_carrier && link_has_carrier(link); carrier_lost = had_carrier && !link_has_carrier(link); -- cgit v1.2.3-54-g00ecf From b9d74c40c6f595e74a140efc2204aa987c3249f9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Feb 2016 23:27:57 +0100 Subject: networkd: make a couple of functions static These functions are nowadays used only within networkd-link.c, hence ther's no point in littering our public namespace with them. --- src/network/networkd-link.c | 29 ++++++++++++++++++++++------- src/network/networkd-link.h | 8 -------- 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index aa8adf1eae..5c3e45fb3c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -39,7 +39,9 @@ #include "util.h" #include "virt.h" -bool link_dhcp6_enabled(Link *link) { +static bool link_dhcp6_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -49,7 +51,9 @@ bool link_dhcp6_enabled(Link *link) { return link->network->dhcp & ADDRESS_FAMILY_IPV6; } -bool link_dhcp4_enabled(Link *link) { +static bool link_dhcp4_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -59,7 +63,9 @@ bool link_dhcp4_enabled(Link *link) { return link->network->dhcp & ADDRESS_FAMILY_IPV4; } -bool link_dhcp4_server_enabled(Link *link) { +static bool link_dhcp4_server_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -69,7 +75,9 @@ bool link_dhcp4_server_enabled(Link *link) { return link->network->dhcp_server; } -bool link_ipv4ll_enabled(Link *link) { +static bool link_ipv4ll_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -79,7 +87,9 @@ bool link_ipv4ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV4; } -bool link_ipv6ll_enabled(Link *link) { +static bool link_ipv6ll_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -89,7 +99,7 @@ bool link_ipv6ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV6; } -bool link_lldp_enabled(Link *link) { +static bool link_lldp_enabled(Link *link) { assert(link); if (link->flags & IFF_LOOPBACK) @@ -108,6 +118,8 @@ bool link_lldp_enabled(Link *link) { } static bool link_ipv4_forward_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; @@ -121,6 +133,7 @@ static bool link_ipv4_forward_enabled(Link *link) { } static bool link_ipv6_forward_enabled(Link *link) { + assert(link); if (!socket_ipv6_is_supported()) return false; @@ -137,7 +150,9 @@ static bool link_ipv6_forward_enabled(Link *link) { return link->network->ip_forward & ADDRESS_FAMILY_IPV6; } -bool link_ipv6_accept_ra_enabled(Link *link) { +static bool link_ipv6_accept_ra_enabled(Link *link) { + assert(link); + if (link->flags & IFF_LOOPBACK) return false; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 4b4ae712b6..d9f637cb6e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -155,14 +155,6 @@ int dhcp6_configure(Link *link); int dhcp6_request_address(Link *link); int ndisc_configure(Link *link); -bool link_lldp_enabled(Link *link); -bool link_ipv4ll_enabled(Link *link); -bool link_ipv6ll_enabled(Link *link); -bool link_dhcp4_server_enabled(Link *link); -bool link_dhcp4_enabled(Link *link); -bool link_dhcp6_enabled(Link *link); -bool link_ipv6_accept_ra_enabled(Link *link); - const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From 33859a6bf5fd2b62a562a751a509708617e19776 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 00:10:55 +0100 Subject: import: don't claim we had copied a settings file if we didn't --- src/import/pull-raw.c | 6 ++++-- src/import/pull-tar.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 8a16602c3e..8993402821 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -355,10 +355,12 @@ static int raw_pull_make_local_copy(RawPull *i) { r = copy_file_atomic(i->settings_path, local_settings, 0644, i->force_local, 0); if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); - else if (r < 0 && r != -ENOENT) + else if (r == -ENOENT) + log_debug_errno(r, "Skipping creation of settings file, since none was found."); + else if (r < 0) log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); else - log_info("Created new settings file '%s.nspawn'", i->local); + log_info("Created new settings file %s.", local_settings); } return 0; diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index afb13366f0..8c61c46f73 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -251,10 +251,12 @@ static int tar_pull_make_local_copy(TarPull *i) { r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0); if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); - else if (r < 0 && r != -ENOENT) + else if (r == -ENOENT) + log_debug_errno(r, "Skipping creation of settings file, since none was found."); + else if (r < 0) log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); else - log_info("Created new settings file '%s.nspawn'", i->local); + log_info("Created new settings file %s.", local_settings); } return 0; -- cgit v1.2.3-54-g00ecf From b553a6b13c68cb72addde48281abe3f3b46e16a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 14:11:34 +0100 Subject: sd-lldp: filter out LLDP messages coming from our own MAC address Let's not get confused should we be connected to some bridge that mirrors back our packets. --- src/basic/ether-addr-util.c | 23 +++++++++++++++++++++++ src/basic/ether-addr-util.h | 5 ++++- src/libsystemd-network/lldp-internal.h | 2 ++ src/libsystemd-network/sd-lldp.c | 21 +++++++++++++++++++++ src/network/networkd-link.c | 4 ++++ src/systemd/sd-lldp.h | 1 + 6 files changed, 55 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index ded6d31f4b..d2c030903b 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -42,3 +42,26 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR return buffer; } + +bool ether_addr_is_null(const struct ether_addr *addr) { + assert(addr); + + return addr->ether_addr_octet[0] == 0 && + addr->ether_addr_octet[1] == 0 && + addr->ether_addr_octet[2] == 0 && + addr->ether_addr_octet[3] == 0 && + addr->ether_addr_octet[4] == 0 && + addr->ether_addr_octet[5] == 0; +} + +bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) { + assert(a); + assert(b); + + return a->ether_addr_octet[0] == b->ether_addr_octet[0] && + a->ether_addr_octet[1] == b->ether_addr_octet[1] && + a->ether_addr_octet[2] == b->ether_addr_octet[2] && + a->ether_addr_octet[3] == b->ether_addr_octet[3] && + a->ether_addr_octet[4] == b->ether_addr_octet[4] && + a->ether_addr_octet[5] == b->ether_addr_octet[5]; +} diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 4487149efd..00c5159fe8 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -20,10 +20,13 @@ ***/ #include +#include #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] #define ETHER_ADDR_TO_STRING_MAX (3*6) - char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); + +bool ether_addr_is_null(const struct ether_addr *addr); +bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b); diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 279975b5c2..7592bc4305 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -45,6 +45,8 @@ struct sd_lldp { void *userdata; uint16_t capability_mask; + + struct ether_addr filter_address; }; #define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 65cfa4e184..3af6133a4e 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -28,6 +28,7 @@ #include "lldp-neighbor.h" #include "lldp-network.h" #include "socket-util.h" +#include "ether-addr-util.h" #define LLDP_DEFAULT_NEIGHBORS_MAX 128U @@ -99,6 +100,11 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { if (n->ttl <= 0) return changed; + /* Filter out the filter address */ + if (!ether_addr_is_null(&lldp->filter_address) && + ether_addr_equal(&lldp->filter_address, &n->source_address)) + return changed; + /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with * no caps field set. */ if (n->has_capabilities && @@ -438,3 +444,18 @@ _public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) { return 0; } + +_public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *addr) { + assert_return(lldp, -EINVAL); + + /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so + * that our own can be filtered out here. */ + + if (!addr) { + zero(lldp->filter_address); + return 0; + } + + lldp->filter_address = *addr; + return 0; +} diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5c3e45fb3c..2bc6e3c842 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2203,6 +2203,10 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = sd_lldp_set_filter_address(link->lldp, &link->mac); + if (r < 0) + return r; + r = sd_lldp_attach_event(link->lldp, NULL, 0); if (r < 0) return r; diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 11b89258ed..2ee32a534c 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -49,6 +49,7 @@ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); /* Controls how much and what to store in the neighbors database */ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n); int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask); +int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *address); int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors); -- cgit v1.2.3-54-g00ecf From 8e1ad1eaf74cd8eadf6a9b14e5d6edb24ab2da91 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 14:14:08 +0100 Subject: networkd: add basic LLDP transmission support Let's add some minimalistic LLDP sender support. The idea is that this is either on or off, and all fields determined automatically rather than configured explicitly. --- Makefile.am | 4 +- src/basic/hostname-util.c | 28 +++ src/basic/hostname-util.h | 1 + src/network/networkd-link.c | 29 ++- src/network/networkd-link.h | 5 + src/network/networkd-lldp-tx.c | 347 +++++++++++++++++++++++++++++++ src/network/networkd-lldp-tx.h | 25 +++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.h | 3 +- 9 files changed, 439 insertions(+), 4 deletions(-) create mode 100644 src/network/networkd-lldp-tx.c create mode 100644 src/network/networkd-lldp-tx.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 70fcedf0da..627a076cd9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5341,7 +5341,9 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-address-pool.h \ src/network/networkd-address-pool.c \ src/network/networkd-util.h \ - src/network/networkd-util.c + src/network/networkd-util.c \ + src/network/networkd-lldp-tx.h \ + src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ src/network/networkd-network-gperf.c \ diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 57031b645c..f900c509a3 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -48,6 +48,9 @@ bool hostname_is_set(void) { char* gethostname_malloc(void) { struct utsname u; + /* This call tries to return something useful, either the actual hostname or it makes something up. The only + * reason it might mail is OOM. It might even return "localhost" if that's set. */ + assert_se(uname(&u) >= 0); if (isempty(u.nodename) || streq(u.nodename, "(none)")) @@ -56,6 +59,31 @@ char* gethostname_malloc(void) { return strdup(u.nodename); } +int gethostname_strict(char **ret) { + struct utsname u; + char *k; + + /* This call will rather fail than make up a name. It will not return "localhost" either. */ + + assert_se(uname(&u) >= 0); + + if (isempty(u.nodename)) + return -ENXIO; + + if (streq(u.nodename, "(none)")) + return -ENXIO; + + if (is_localhost(u.nodename)) + return -ENXIO; + + k = strdup(u.nodename); + if (!k) + return -ENOMEM; + + *ret = k; + return 0; +} + static bool hostname_valid_char(char c) { return (c >= 'a' && c <= 'z') || diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index d062eddea1..7af4e6c7ec 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -26,6 +26,7 @@ bool hostname_is_set(void); char* gethostname_malloc(void); +int gethostname_strict(char **ret); bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; char* hostname_cleanup(char *s); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2bc6e3c842..86fa4f07f2 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -30,6 +30,7 @@ #include "netlink-util.h" #include "network-internal.h" #include "networkd-link.h" +#include "networkd-lldp-tx.h" #include "networkd-netdev.h" #include "set.h" #include "socket-util.h" @@ -99,7 +100,7 @@ static bool link_ipv6ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV6; } -static bool link_lldp_enabled(Link *link) { +static bool link_lldp_rx_enabled(Link *link) { assert(link); if (link->flags & IFF_LOOPBACK) @@ -117,6 +118,21 @@ static bool link_lldp_enabled(Link *link) { return link->network->lldp_mode != LLDP_MODE_NO; } +static bool link_lldp_tx_enabled(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return false; + + if (link->iftype != ARPHRD_ETHER) + return false; + + if (!link->network) + return false; + + return link->network->lldp_emit; +} + static bool link_ipv4_forward_enabled(Link *link) { assert(link); @@ -419,6 +435,8 @@ static void link_free(Link *link) { sd_dhcp_client_unref(link->dhcp_client); sd_dhcp_lease_unref(link->dhcp_lease); + link_lldp_tx_stop(link); + free(link->lease_file); sd_lldp_unref(link->lldp); @@ -546,6 +564,7 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } + link_lldp_tx_stop(link); return r; } @@ -1383,6 +1402,12 @@ static int link_acquire_conf(Link *link) { return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); } + if (link_lldp_tx_enabled(link)) { + r = link_lldp_tx_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m"); + } + return 0; } @@ -2191,7 +2216,7 @@ static int link_configure(Link *link) { return r; } - if (link_lldp_enabled(link)) { + if (link_lldp_rx_enabled(link)) { r = sd_lldp_new(&link->lldp, link->ifindex); if (r < 0) return r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index d9f637cb6e..f2a64ca9b5 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -112,9 +112,14 @@ struct Link { sd_dhcp6_client *dhcp6_client; bool rtnl_extended_attrs; + /* This is about LLDP reception */ sd_lldp *lldp; char *lldp_file; + /* This is about LLDP transmission */ + unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */ + sd_event_source *lldp_tx_event_source; + Hashmap *bound_by_links; Hashmap *bound_to_links; }; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c new file mode 100644 index 0000000000..ae8367a60e --- /dev/null +++ b/src/network/networkd-lldp-tx.c @@ -0,0 +1,347 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#include +#include + +#include "fd-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "lldp.h" +#include "networkd-lldp-tx.h" +#include "random-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "unaligned.h" + +/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */ +#define LLDP_TX_FAST_INIT 4U + +/* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */ +#define LLDP_TX_HOLD 4U + +/* The jitter range to add, see 9.2.2. */ +#define LLDP_JITTER_USEC (400U * USEC_PER_MSEC) + +/* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */ +#define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) + +/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */ +#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) + +static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) { + assert(p); + + if (id > 127) + return -EBADMSG; + if (sz > 511) + return -ENOBUFS; + + (*p)[0] = (id << 1) | !!(sz & 256); + (*p)[1] = sz & 255; + + *p = *p + 2; + return 0; +} + +static int lldp_make_packet( + const struct ether_addr *hwaddr, + const char *machine_id, + const char *ifname, + uint16_t ttl, + const char *port_description, + const char *hostname, + const char *pretty_hostname, + uint16_t system_capabilities, + uint16_t enabled_capabilities, + void **ret, size_t *sz) { + + size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0; + _cleanup_free_ void *packet = NULL; + struct ether_header *h; + uint8_t *p; + size_t l; + int r; + + assert(hwaddr); + assert(machine_id); + assert(ifname); + assert(ret); + assert(sz); + + machine_id_length = strlen(machine_id); + ifname_length = strlen(ifname); + + if (port_description) + port_description_length = strlen(port_description); + + if (hostname) + hostname_length = strlen(hostname); + + if (pretty_hostname) + pretty_hostname_length = strlen(pretty_hostname); + + l = sizeof(struct ether_header) + + /* Chassis ID */ + 2 + 1 + machine_id_length + + /* Port ID */ + 2 + 1 + ifname_length + + /* TTL */ + 2 + 2 + + /* System Capabilities */ + 2 + 4 + + /* End */ + 2; + + /* Port Description */ + if (port_description) + l += 2 + port_description_length; + + /* System Name */ + if (hostname) + l += 2 + hostname_length; + + /* System Description */ + if (pretty_hostname) + l += 2 + pretty_hostname_length; + + packet = malloc(l); + if (!packet) + return -ENOMEM; + + h = (struct ether_header*) packet; + h->ether_type = htobe16(ETHERTYPE_LLDP); + memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN); + memcpy(h->ether_shost, hwaddr, ETH_ALEN); + + p = (uint8_t*) packet + sizeof(struct ether_header); + + r = lldp_write_tlv_header(&p, LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length); + if (r < 0) + return r; + *(p++) = LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED; + p = mempcpy(p, machine_id, machine_id_length); + + r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_ID, 1 + ifname_length); + if (r < 0) + return r; + *(p++) = LLDP_PORT_SUBTYPE_INTERFACE_NAME; + p = mempcpy(p, ifname, ifname_length); + + r = lldp_write_tlv_header(&p, LLDP_TYPE_TTL, 2); + if (r < 0) + return r; + unaligned_write_be16(p, ttl); + p += 2; + + if (port_description) { + r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_DESCRIPTION, port_description_length); + if (r < 0) + return r; + p = mempcpy(p, port_description, port_description_length); + } + + if (hostname) { + r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_NAME, hostname_length); + if (r < 0) + return r; + p = mempcpy(p, hostname, hostname_length); + } + + if (pretty_hostname) { + r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length); + if (r < 0) + return r; + p = mempcpy(p, pretty_hostname, pretty_hostname_length); + } + + r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_CAPABILITIES, 4); + if (r < 0) + return r; + unaligned_write_be16(p, system_capabilities); + p += 2; + unaligned_write_be16(p, enabled_capabilities); + p += 2; + + r = lldp_write_tlv_header(&p, LLDP_TYPE_END, 0); + if (r < 0) + return r; + + assert(p == (uint8_t*) packet + l); + + *ret = packet; + *sz = l; + + packet = NULL; + return 0; +} + +static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) { + + union sockaddr_union sa = { + .ll.sll_family = AF_PACKET, + .ll.sll_protocol = htobe16(ETHERTYPE_LLDP), + .ll.sll_ifindex = ifindex, + .ll.sll_halen = ETH_ALEN, + .ll.sll_addr = LLDP_MULTICAST_ADDR, + }; + + _cleanup_close_ int fd = -1; + ssize_t l; + + assert(ifindex > 0); + assert(packet || packet_size <= 0); + + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW); + if (fd < 0) + return -errno; + + l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll)); + if (l < 0) + return -errno; + + if ((size_t) l != packet_size) + return -EIO; + + return 0; +} + +static int link_send_lldp(Link *link) { + char machine_id_string[SD_ID128_STRING_MAX]; + _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL; + _cleanup_free_ void *packet = NULL; + size_t packet_size = 0; + sd_id128_t machine_id; + uint16_t caps; + usec_t ttl; + int r; + + r = sd_id128_get_machine(&machine_id); + if (r < 0) + return r; + + (void) gethostname_strict(&hostname); + (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL); + + ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC); + if (ttl > (usec_t) UINT16_MAX) + ttl = (usec_t) UINT16_MAX; + + caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ? + LLDP_SYSTEM_CAPABILITIES_ROUTER : + LLDP_SYSTEM_CAPABILITIES_STATION; + + r = lldp_make_packet(&link->mac, + sd_id128_to_string(machine_id, machine_id_string), + link->ifname, + (uint16_t) ttl, + link->network ? link->network->description : NULL, + hostname, + pretty_hostname, + LLDP_SYSTEM_CAPABILITIES_STATION|LLDP_SYSTEM_CAPABILITIES_BRIDGE|LLDP_SYSTEM_CAPABILITIES_ROUTER, + caps, + &packet, &packet_size); + if (r < 0) + return r; + + return lldp_send_packet(link->ifindex, packet, packet_size); +} + +static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { + Link *link = userdata; + usec_t current, delay, next; + int r; + + assert(s); + assert(userdata); + + log_link_debug(link, "Sending LLDP packet..."); + + r = link_send_lldp(link); + if (r < 0) + log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m"); + + if (link->lldp_tx_fast > 0) + link->lldp_tx_fast--; + + assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), ¤t) >= 0); + + delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC; + next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC); + + r = sd_event_source_set_time(s, next); + if (r < 0) + return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m"); + + r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); + if (r < 0) + return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m"); + + return 0; +} + +int link_lldp_tx_start(Link *link) { + usec_t next; + int r; + + assert(link); + + /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */ + + link->lldp_tx_fast = LLDP_TX_FAST_INIT; + + next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC), + (usec_t) random_u64() % LLDP_JITTER_USEC); + + if (link->lldp_tx_event_source) { + usec_t old; + + /* Lower the timeout, maybe */ + r = sd_event_source_get_time(link->lldp_tx_event_source, &old); + if (r < 0) + return r; + + if (old <= next) + return 0; + + return sd_event_source_set_time(link->lldp_tx_event_source, next); + } else { + r = sd_event_add_time( + link->manager->event, + &link->lldp_tx_event_source, + clock_boottime_or_monotonic(), + next, + 0, + on_lldp_timer, + link); + if (r < 0) + return r; + + (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx"); + } + + return 0; +} + +void link_lldp_tx_stop(Link *link) { + assert(link); + + link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source); +} diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h new file mode 100644 index 0000000000..8c7f403005 --- /dev/null +++ b/src/network/networkd-lldp-tx.h @@ -0,0 +1,25 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "networkd-link.h" + +int link_lldp_tx_start(Link *link); +void link_lldp_tx_stop(Link *link); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index d67da5d7b6..a5d1714293 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -41,6 +41,7 @@ Network.LinkLocalAddressing, config_parse_address_family_boolean, Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) +Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 9dcebfbf7b..4a13e2b574 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -145,7 +145,8 @@ struct Network { struct ether_addr *mac; unsigned mtu; - LLDPMode lldp_mode; + LLDPMode lldp_mode; /* LLDP reception */ + bool lldp_emit; /* LLDP transmission */ LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); -- cgit v1.2.3-54-g00ecf From f5207c2206061479e7eb5f3fd6213d7c508e0336 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 14:27:06 +0100 Subject: networkctl: add missing newline to printf() format string --- src/network/networkctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 27a758152e..23d8c4555b 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -809,7 +809,7 @@ static int link_status_one( (void) sd_network_link_get_timezone(info->ifindex, &tz); if (tz) - printf(" Time Zone: %s", tz); + printf(" Time Zone: %s\n", tz); (void) dump_lldp_neighbors(" Connected To: ", info->ifindex); -- cgit v1.2.3-54-g00ecf From d08191a242d51f72e75d41f188b14e67dd8851c4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 14:31:51 +0100 Subject: networkctl: ellipsize long LLDP fields in table output --- src/network/networkctl.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 23d8c4555b..d1aec9a7dc 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -940,6 +940,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { } for (;;) { + _cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL; const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL; _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; uint16_t cc; @@ -957,6 +958,30 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { (void) sd_lldp_neighbor_get_system_name(n, &system_name); (void) sd_lldp_neighbor_get_port_description(n, &port_description); + if (chassis_id) { + cid = ellipsize(chassis_id, 17, 100); + if (cid) + chassis_id = cid; + } + + if (port_id) { + pid = ellipsize(port_id, 17, 100); + if (pid) + port_id = pid; + } + + if (system_name) { + sname = ellipsize(system_name, 16, 100); + if (sname) + system_name = sname; + } + + if (port_description) { + pdesc = ellipsize(port_description, 16, 100); + if (pdesc) + port_description = pdesc; + } + if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) capabilities = lldp_capabilities_to_string(cc); -- cgit v1.2.3-54-g00ecf From 90dffb2241fa03011b625c26943f36f525e6c323 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 20:38:39 +0100 Subject: sd-lldp: beef up callback logic Instead of just notifying about the fact that something changed in the database, actually inform the callback what precisely changed. This is useful, so that the LLDP tx logic can be put into "fast" mode as soon as a previously unknown peer appears, as suggested by the LLDP spec. --- src/libsystemd-network/sd-lldp.c | 102 ++++++++++++++++++++++++------------- src/libsystemd-network/test-lldp.c | 2 +- src/network/networkd-link.c | 13 ++++- src/systemd/sd-lldp.h | 9 +++- 4 files changed, 88 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 3af6133a4e..d0743cf3e2 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -41,8 +41,19 @@ static void lldp_flush_neighbors(sd_lldp *lldp) { lldp_neighbor_unlink(n); } +static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { + assert(lldp); + assert(n); + + log_lldp("Invoking callback for '%c'.", event); + + if (!lldp->callback) + return; + + lldp->callback(lldp, event, n, lldp->userdata); +} + static int lldp_make_space(sd_lldp *lldp, size_t extra) { - sd_lldp_neighbor *n; usec_t t = USEC_INFINITY; bool changed = false; @@ -52,10 +63,14 @@ static int lldp_make_space(sd_lldp *lldp, size_t extra) { * are free. */ for (;;) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + n = prioq_peek(lldp->neighbor_by_expiry); if (!n) break; + sd_lldp_neighbor_ref(n); + if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra)) goto remove_one; @@ -67,66 +82,96 @@ static int lldp_make_space(sd_lldp *lldp, size_t extra) { remove_one: lldp_neighbor_unlink(n); + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); changed = true; } return changed; } +static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { + assert(lldp); + assert(n); + + /* Don't keep data with a zero TTL */ + if (n->ttl <= 0) + return false; + + /* Filter out data from the filter address */ + if (!ether_addr_is_null(&lldp->filter_address) && + ether_addr_equal(&lldp->filter_address, &n->source_address)) + return false; + + /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with + * no caps field set. */ + if (n->has_capabilities && + (n->enabled_capabilities & lldp->capability_mask) == 0) + return false; + + /* Keep everything else */ + return true; +} + static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { - sd_lldp_neighbor *old; - bool changed = false; + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL; + bool keep; int r; assert(lldp); assert(n); assert(!n->lldp); + keep = lldp_keep_neighbor(lldp, n); + /* First retrieve the old entry for this MSAP */ old = hashmap_get(lldp->neighbor_by_id, &n->id); if (old) { + sd_lldp_neighbor_ref(old); + + if (!keep) { + lldp_neighbor_unlink(old); + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); + return 0; + } + if (lldp_neighbor_equal(n, old)) { /* Is this equal, then restart the TTL counter, but don't do anyting else. */ lldp_neighbor_start_ttl(old); + lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); return 0; } /* Data changed, remove the old entry, and add a new one */ lldp_neighbor_unlink(old); - changed = true; - } - /* Then, add the new entry in its place, but only if it has a non-zero TTL. */ - if (n->ttl <= 0) - return changed; - - /* Filter out the filter address */ - if (!ether_addr_is_null(&lldp->filter_address) && - ether_addr_equal(&lldp->filter_address, &n->source_address)) - return changed; - - /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with - * no caps field set. */ - if (n->has_capabilities && - (n->enabled_capabilities & lldp->capability_mask) == 0) - return changed; + } else if (!keep) + return 0; /* Then, make room for at least one new neighbor */ lldp_make_space(lldp, 1); r = hashmap_put(lldp->neighbor_by_id, &n->id, n); if (r < 0) - return r; + goto finish; r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx); if (r < 0) { assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n); - return r; + goto finish; } n->lldp = lldp; - return true; + lldp_neighbor_start_ttl(n); + lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n); + + return 1; + +finish: + if (old) + lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); + + return r; } static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { @@ -141,8 +186,6 @@ static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { if (r < 0) return r; - lldp_neighbor_start_ttl(n); - r = lldp_add_neighbor(lldp, n); if (r < 0) { log_lldp_errno(r, "Failed to add datagram. Ignoring."); @@ -150,10 +193,6 @@ static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { } log_lldp("Successfully processed LLDP datagram."); - - if (r > 0 && lldp->callback) /* Only invoke the callback if something actually changed. */ - lldp->callback(lldp, lldp->userdata); - return 0; } @@ -343,10 +382,6 @@ static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { if (q < 0) return log_lldp_errno(q, "Failed to restart timer: %m"); - log_lldp("LLDP timer event hit."); - if (r > 0 && lldp->callback) /* Invoke callback if we dropped an entry */ - lldp->callback(lldp, lldp->userdata); - return 0; } @@ -396,9 +431,6 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { assert_return(lldp, -EINVAL); assert_return(ret, -EINVAL); - /* Flush out old entries, before we return data */ - (void) lldp_make_space(lldp, 0); - if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */ *ret = NULL; return 0; diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 589117f56e..da4ce293bc 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -48,7 +48,7 @@ int lldp_network_bind_raw_socket(int ifindex) { return test_fd[0]; } -static void lldp_handler (sd_lldp *lldp, void *userdata) { +static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { lldp_handler_calls++; } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 86fa4f07f2..85a439b2a5 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1333,12 +1333,23 @@ finish: return r; } -static void lldp_handler(sd_lldp *lldp, void *userdata) { +static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { Link *link = userdata; + int r; assert(link); (void) link_lldp_save(link); + + if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) { + /* If we received information about a new neighbor, restart the LLDP "fast" logic */ + + log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission."); + + r = link_lldp_tx_start(link); + if (r < 0) + log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m"); + } } static int link_acquire_ipv6_conf(Link *link) { diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 2ee32a534c..f7eff58769 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -33,7 +33,14 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_lldp sd_lldp; typedef struct sd_lldp_neighbor sd_lldp_neighbor; -typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, void *userdata); +typedef enum sd_lldp_event { + SD_LLDP_EVENT_ADDED = 'a', + SD_LLDP_EVENT_REMOVED = 'r', + SD_LLDP_EVENT_UPDATED = 'u', + SD_LLDP_EVENT_REFRESHED = 'f', +} sd_lldp_event; + +typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata); int sd_lldp_new(sd_lldp **ret, int ifindex); sd_lldp* sd_lldp_unref(sd_lldp *lldp); -- cgit v1.2.3-54-g00ecf From cbbf38aefc7a3d18d68f0d8fffb6b59d77948690 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 22:27:01 +0100 Subject: networkd: make sure we allocate the NTA set before we add items to it See: #2683 --- src/network/networkd-network.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 4315790093..54f76fe206 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -994,6 +994,10 @@ int config_parse_dnssec_negative_trust_anchors( continue; } + r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops); + if (r < 0) + return log_oom(); + r = set_put(n->dnssec_negative_trust_anchors, w); if (r < 0) return log_oom(); -- cgit v1.2.3-54-g00ecf From ea3894c1ba26bdfe3f0299dfbe2b767ba92f91dc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 23:25:38 +0100 Subject: util-lib: add (void) cast to indicate that we don't care about the normalization success After all, we verify that every calendar part is not out of bounds later on, and it's fully OK if the normalization has no effect. --- src/basic/calendarspec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 775879076d..07315d73e8 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -978,7 +978,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { for (;;) { /* Normalize the current date */ - mktime_or_timegm(&c, spec->utc); + (void) mktime_or_timegm(&c, spec->utc); c.tm_isdst = -1; c.tm_year += 1900; -- cgit v1.2.3-54-g00ecf From e308ddcae22537b78a9eab22beaa5cb73d86617b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 21 Feb 2016 23:27:20 +0100 Subject: util-lib: fix returned error code Make sure we propagate errors properly. --- src/basic/calendarspec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 07315d73e8..00fc39a499 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -990,8 +990,10 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; } - if (r < 0 || tm_out_of_bounds(&c, spec->utc)) + if (r < 0) return r; + if (tm_out_of_bounds(&c, spec->utc)) + return -ENOENT; c.tm_mon += 1; r = find_matching_component(spec->month, &c.tm_mon); -- cgit v1.2.3-54-g00ecf From 26c34ab4eecb4a4e5166beadd393e3a4ec418d6a Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 22 Feb 2016 13:10:16 +0100 Subject: missing.h: Explicitly check for IFLA_BRPORT_PROXYARP RHEL explicitly disables IFLA_BRPORT_PROXYARP by renaming the enum value. In order to support unpatched builds, we have two options: a) redefine the enum value through missing.h and ignore the fact that it is really unsupported, or b) omit that enum value on rtnl_prot_info_bridge_port_types[] As we are not actually using this netlink type anywhere, and because it is only hooked up for the sake of completeness, this patch opts for the former. --- configure.ac | 1 + src/basic/missing.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/configure.ac b/configure.ac index f51533c2b3..269aceddcc 100644 --- a/configure.ac +++ b/configure.ac @@ -323,6 +323,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, IFLA_IPTUN_ENCAP_DPORT, IFLA_GRE_ENCAP_DPORT, IFLA_BRIDGE_VLAN_INFO, + IFLA_BRPORT_PROXYARP, IFLA_BRPORT_LEARNING_SYNC, IFLA_BR_PRIORITY, NDA_IFINDEX, diff --git a/src/basic/missing.h b/src/basic/missing.h index f3d32362bd..88ecb4ac01 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -883,13 +883,16 @@ static inline int setns(int fd, int nstype) { #define IFLA_BRPORT_FAST_LEAVE 7 #define IFLA_BRPORT_LEARNING 8 #define IFLA_BRPORT_UNICAST_FLOOD 9 -#define IFLA_BRPORT_PROXYARP 10 #define IFLA_BRPORT_LEARNING_SYNC 11 #define __IFLA_BRPORT_MAX 12 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) #endif +#if !HAVE_DECL_IFLA_BRPORT_PROXYARP +#define IFLA_BRPORT_PROXYARP 10 +#endif + #if !HAVE_DECL_NDA_IFINDEX #define NDA_UNSPEC 0 #define NDA_DST 1 -- cgit v1.2.3-54-g00ecf From a022d76e6a7c711954be5535e6308d0a470e232a Mon Sep 17 00:00:00 2001 From: Hristo Venev Date: Mon, 22 Feb 2016 08:02:48 -0500 Subject: calendarspec: fix find_next skipping times reset usec when bumping hours/minutes --- src/basic/calendarspec.c | 4 ++-- src/test/test-calendarspec.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 00fc39a499..2f40ba2b46 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -1029,7 +1029,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { r = find_matching_component(spec->hour, &c.tm_hour); if (r > 0) - c.tm_min = c.tm_sec = 0; + c.tm_min = c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_mday ++; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; @@ -1038,7 +1038,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { r = find_matching_component(spec->minute, &c.tm_min); if (r > 0) - c.tm_sec = 0; + c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_hour ++; c.tm_min = c.tm_sec = tm_usec = 0; diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 8754cb3381..5a8c6cbfb6 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -137,6 +137,7 @@ int main(int argc, char* argv[]) { test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000); test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000); test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000); + test_next("Sun 16:00:00", "CET", 1456041600123456, 1456066800000000); assert_se(calendar_spec_from_string("test", &c) < 0); assert_se(calendar_spec_from_string("", &c) < 0); -- cgit v1.2.3-54-g00ecf From 916a8d4341cc2d188614fee011346f2df8daf86c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 22 Feb 2016 12:17:08 -0500 Subject: udev-rules: fix querying of attributes faccessat returns 0 on success. A cosmetic fix is also included: the slash was doubled unnecessarily. --- src/udev/udev-rules.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 8470456d4c..475856db6f 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -705,10 +705,10 @@ static void attr_subst_subdir(char *attr, size_t len) { for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) if (dent->d_name[0] != '.') { - char n[strlen(dent->d_name) + 1 + strlen(tail) + 1]; + char n[strlen(dent->d_name) + strlen(tail) + 1]; - strscpyl(n, sizeof n, dent->d_name, "/", tail, NULL); - if (faccessat(dirfd(dir), n, F_OK, 0)) { + strscpyl(n, sizeof n, dent->d_name, tail, NULL); + if (faccessat(dirfd(dir), n, F_OK, 0) == 0) { strscpyl(attr, len, path, n, NULL); break; } -- cgit v1.2.3-54-g00ecf From 0f9ae7d73df879ed36e0e7134b756c4d64de3d93 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 15:26:54 +0100 Subject: build-sys: move shared/architecture.[ch] into basic/ After all, it is pretty generic, has no external deps besides libc, and is very similar to virt.[ch] which is also in basic/ --- Makefile.am | 4 +- src/basic/architecture.c | 176 +++++++++++++++++++++++++++++++++++++++ src/basic/architecture.h | 207 ++++++++++++++++++++++++++++++++++++++++++++++ src/shared/architecture.c | 176 --------------------------------------- src/shared/architecture.h | 207 ---------------------------------------------- 5 files changed, 385 insertions(+), 385 deletions(-) create mode 100644 src/basic/architecture.c create mode 100644 src/basic/architecture.h delete mode 100644 src/shared/architecture.c delete mode 100644 src/shared/architecture.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index d7d58ccbee..a0043c2e4a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -850,6 +850,8 @@ libbasic_la_SOURCES = \ src/basic/exit-status.h \ src/basic/virt.c \ src/basic/virt.h \ + src/basic/architecture.c \ + src/basic/architecture.h \ src/basic/smack-util.c \ src/basic/smack-util.h \ src/basic/device-nodes.c \ @@ -963,8 +965,6 @@ libshared_la_SOURCES = \ src/shared/initreq.h \ src/shared/dns-domain.c \ src/shared/dns-domain.h \ - src/shared/architecture.c \ - src/shared/architecture.h \ src/shared/efivars.c \ src/shared/efivars.h \ src/shared/fstab-util.c \ diff --git a/src/basic/architecture.c b/src/basic/architecture.c new file mode 100644 index 0000000000..a9ecfc1cd6 --- /dev/null +++ b/src/basic/architecture.c @@ -0,0 +1,176 @@ +/*** + 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 . +***/ + +#include + +#include "architecture.h" +#include "macro.h" +#include "string-table.h" +#include "string-util.h" + +int uname_architecture(void) { + + /* Return a sanitized enum identifying the architecture we are + * running on. This is based on uname(), and the user may + * hence control what this returns by using + * personality(). This puts the user in control on systems + * that can run binaries of multiple architectures. + * + * We do not translate the string returned by uname() + * 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 distinguish CPUs not CPU features, but + * actual architectures, i.e. that have genuinely different + * code. */ + + static const struct { + const char *machine; + int arch; + } arch_map[] = { +#if defined(__x86_64__) || defined(__i386__) + { "x86_64", ARCHITECTURE_X86_64 }, + { "i686", ARCHITECTURE_X86 }, + { "i586", ARCHITECTURE_X86 }, + { "i486", ARCHITECTURE_X86 }, + { "i386", ARCHITECTURE_X86 }, +#elif defined(__powerpc__) || defined(__powerpc64__) + { "ppc64", ARCHITECTURE_PPC64 }, + { "ppc64le", ARCHITECTURE_PPC64_LE }, + { "ppc", ARCHITECTURE_PPC }, + { "ppcle", ARCHITECTURE_PPC_LE }, +#elif defined(__ia64__) + { "ia64", ARCHITECTURE_IA64 }, +#elif defined(__hppa__) || defined(__hppa64__) + { "parisc64", ARCHITECTURE_PARISC64 }, + { "parisc", ARCHITECTURE_PARISC }, +#elif defined(__s390__) || defined(__s390x__) + { "s390x", ARCHITECTURE_S390X }, + { "s390", ARCHITECTURE_S390 }, +#elif defined(__sparc__) || defined(__sparc64__) + { "sparc64", ARCHITECTURE_SPARC64 }, + { "sparc", ARCHITECTURE_SPARC }, +#elif defined(__mips__) || defined(__mips64__) + { "mips64", ARCHITECTURE_MIPS64 }, + { "mips", ARCHITECTURE_MIPS }, +#elif defined(__alpha__) + { "alpha" , ARCHITECTURE_ALPHA }, +#elif defined(__arm__) || defined(__aarch64__) + { "aarch64", ARCHITECTURE_ARM64 }, + { "aarch64_be", ARCHITECTURE_ARM64_BE }, + { "armv4l", ARCHITECTURE_ARM }, + { "armv4b", ARCHITECTURE_ARM_BE }, + { "armv4tl", ARCHITECTURE_ARM }, + { "armv4tb", ARCHITECTURE_ARM_BE }, + { "armv5tl", ARCHITECTURE_ARM }, + { "armv5tb", ARCHITECTURE_ARM_BE }, + { "armv5tel", ARCHITECTURE_ARM }, + { "armv5teb" , ARCHITECTURE_ARM_BE }, + { "armv5tejl", ARCHITECTURE_ARM }, + { "armv5tejb", ARCHITECTURE_ARM_BE }, + { "armv6l", ARCHITECTURE_ARM }, + { "armv6b", ARCHITECTURE_ARM_BE }, + { "armv7l", ARCHITECTURE_ARM }, + { "armv7b", ARCHITECTURE_ARM_BE }, + { "armv7ml", ARCHITECTURE_ARM }, + { "armv7mb", ARCHITECTURE_ARM_BE }, + { "armv4l", ARCHITECTURE_ARM }, + { "armv4b", ARCHITECTURE_ARM_BE }, + { "armv4tl", ARCHITECTURE_ARM }, + { "armv4tb", ARCHITECTURE_ARM_BE }, + { "armv5tl", ARCHITECTURE_ARM }, + { "armv5tb", ARCHITECTURE_ARM_BE }, + { "armv5tel", ARCHITECTURE_ARM }, + { "armv5teb", ARCHITECTURE_ARM_BE }, + { "armv5tejl", ARCHITECTURE_ARM }, + { "armv5tejb", ARCHITECTURE_ARM_BE }, + { "armv6l", ARCHITECTURE_ARM }, + { "armv6b", ARCHITECTURE_ARM_BE }, + { "armv7l", ARCHITECTURE_ARM }, + { "armv7b", ARCHITECTURE_ARM_BE }, + { "armv7ml", ARCHITECTURE_ARM }, + { "armv7mb", ARCHITECTURE_ARM_BE }, + { "armv8l", ARCHITECTURE_ARM }, + { "armv8b", ARCHITECTURE_ARM_BE }, +#elif defined(__sh__) || defined(__sh64__) + { "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__) + { "tilegx", ARCHITECTURE_TILEGX }, +#elif defined(__cris__) + { "crisv32", ARCHITECTURE_CRIS }, +#else +#error "Please register your architecture here!" +#endif + }; + + static int cached = _ARCHITECTURE_INVALID; + struct utsname u; + unsigned i; + + if (cached != _ARCHITECTURE_INVALID) + return cached; + + assert_se(uname(&u) >= 0); + + for (i = 0; i < ELEMENTSOF(arch_map); i++) + if (streq(arch_map[i].machine, u.machine)) + return cached = arch_map[i].arch; + + assert_not_reached("Couldn't identify architecture. You need to patch systemd."); + return _ARCHITECTURE_INVALID; +} + +static const char *const architecture_table[_ARCHITECTURE_MAX] = { + [ARCHITECTURE_X86] = "x86", + [ARCHITECTURE_X86_64] = "x86-64", + [ARCHITECTURE_PPC] = "ppc", + [ARCHITECTURE_PPC_LE] = "ppc-le", + [ARCHITECTURE_PPC64] = "ppc64", + [ARCHITECTURE_PPC64_LE] = "ppc64-le", + [ARCHITECTURE_IA64] = "ia64", + [ARCHITECTURE_PARISC] = "parisc", + [ARCHITECTURE_PARISC64] = "parisc64", + [ARCHITECTURE_S390] = "s390", + [ARCHITECTURE_S390X] = "s390x", + [ARCHITECTURE_SPARC] = "sparc", + [ARCHITECTURE_SPARC64] = "sparc64", + [ARCHITECTURE_MIPS] = "mips", + [ARCHITECTURE_MIPS_LE] = "mips-le", + [ARCHITECTURE_MIPS64] = "mips64", + [ARCHITECTURE_MIPS64_LE] = "mips64-le", + [ARCHITECTURE_ALPHA] = "alpha", + [ARCHITECTURE_ARM] = "arm", + [ARCHITECTURE_ARM_BE] = "arm-be", + [ARCHITECTURE_ARM64] = "arm64", + [ARCHITECTURE_ARM64_BE] = "arm64-be", + [ARCHITECTURE_SH] = "sh", + [ARCHITECTURE_SH64] = "sh64", + [ARCHITECTURE_M68K] = "m68k", + [ARCHITECTURE_TILEGX] = "tilegx", + [ARCHITECTURE_CRIS] = "cris", +}; + +DEFINE_STRING_TABLE_LOOKUP(architecture, int); diff --git a/src/basic/architecture.h b/src/basic/architecture.h new file mode 100644 index 0000000000..26679e28c6 --- /dev/null +++ b/src/basic/architecture.h @@ -0,0 +1,207 @@ +#pragma once + +/*** + 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 . +***/ + +#include + +#include "macro.h" +#include "util.h" + +/* 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 distinguish word width and + * endianness. */ + +enum { + ARCHITECTURE_X86 = 0, + ARCHITECTURE_X86_64, + ARCHITECTURE_PPC, + ARCHITECTURE_PPC_LE, + ARCHITECTURE_PPC64, + ARCHITECTURE_PPC64_LE, + ARCHITECTURE_IA64, + ARCHITECTURE_PARISC, + ARCHITECTURE_PARISC64, + ARCHITECTURE_S390, + ARCHITECTURE_S390X, + ARCHITECTURE_SPARC, + ARCHITECTURE_SPARC64, + ARCHITECTURE_MIPS, + ARCHITECTURE_MIPS_LE, + ARCHITECTURE_MIPS64, + ARCHITECTURE_MIPS64_LE, + ARCHITECTURE_ALPHA, + ARCHITECTURE_ARM, + ARCHITECTURE_ARM_BE, + ARCHITECTURE_ARM64, + ARCHITECTURE_ARM64_BE, + ARCHITECTURE_SH, + ARCHITECTURE_SH64, + ARCHITECTURE_M68K, + ARCHITECTURE_TILEGX, + ARCHITECTURE_CRIS, + _ARCHITECTURE_MAX, + _ARCHITECTURE_INVALID = -1 +}; + +int uname_architecture(void); + +/* + * LIB_ARCH_TUPLE should resolve to the local library path + * architecture tuple systemd is built for, according to the Debian + * tuple list: + * + * https://wiki.debian.org/Multiarch/Tuples + * + * This is used in library search paths that should understand + * Debian's paths on all distributions. + */ + +#if defined(__x86_64__) +# define native_architecture() ARCHITECTURE_X86_64 +# define LIB_ARCH_TUPLE "x86_64-linux-gnu" +# define PROC_CPUINFO_MODEL "model name" +#elif defined(__i386__) +# define native_architecture() ARCHITECTURE_X86 +# define LIB_ARCH_TUPLE "i386-linux-gnu" +# define PROC_CPUINFO_MODEL "model name" +#elif defined(__powerpc64__) +# if __BYTE_ORDER == __BIG_ENDIAN +# define native_architecture() ARCHITECTURE_PPC64 +# define LIB_ARCH_TUPLE "ppc64-linux-gnu" +# else +# define native_architecture() ARCHITECTURE_PPC64_LE +# define LIB_ARCH_TUPLE "powerpc64le-linux-gnu" +# endif +# define PROC_CPUINFO_MODEL "cpu" +#elif defined(__powerpc__) +# if __BYTE_ORDER == __BIG_ENDIAN +# define native_architecture() ARCHITECTURE_PPC +# define LIB_ARCH_TUPLE "powerpc-linux-gnu" +# else +# define native_architecture() ARCHITECTURE_PPC_LE +# error "Missing LIB_ARCH_TUPLE for PPCLE" +# endif +# define PROC_CPUINFO_MODEL "cpu" +#elif defined(__ia64__) +# define native_architecture() ARCHITECTURE_IA64 +# define LIB_ARCH_TUPLE "ia64-linux-gnu" +#elif defined(__hppa64__) +# define native_architecture() ARCHITECTURE_PARISC64 +# error "Missing LIB_ARCH_TUPLE for HPPA64" +# define PROC_CPUINFO_MODEL "cpu" +#elif defined(__hppa__) +# define native_architecture() ARCHITECTURE_PARISC +# define LIB_ARCH_TUPLE "hppa‑linux‑gnu" +# define PROC_CPUINFO_MODEL "cpu" +#elif defined(__s390x__) +# define native_architecture() ARCHITECTURE_S390X +# define LIB_ARCH_TUPLE "s390x-linux-gnu" +#elif defined(__s390__) +# define native_architecture() ARCHITECTURE_S390 +# define LIB_ARCH_TUPLE "s390-linux-gnu" +#elif defined(__sparc64__) +# define native_architecture() ARCHITECTURE_SPARC64 +# define LIB_ARCH_TUPLE "sparc64-linux-gnu" +# define PROC_CPUINFO_MODEL "cpu" +#elif defined(__sparc__) +# define native_architecture() ARCHITECTURE_SPARC +# define LIB_ARCH_TUPLE "sparc-linux-gnu" +# define PROC_CPUINFO_MODEL "cpu" +#elif defined(__mips64__) +# if __BYTE_ORDER == __BIG_ENDIAN +# define native_architecture() ARCHITECTURE_MIPS64 +# error "Missing LIB_ARCH_TUPLE for MIPS64" +# else +# define native_architecture() ARCHITECTURE_MIPS64_LE +# error "Missing LIB_ARCH_TUPLE for MIPS64_LE" +# endif +# define PROC_CPUINFO_MODEL "cpu model" +#elif defined(__mips__) +# if __BYTE_ORDER == __BIG_ENDIAN +# define native_architecture() ARCHITECTURE_MIPS +# define LIB_ARCH_TUPLE "mips-linux-gnu" +# else +# define native_architecture() ARCHITECTURE_MIPS_LE +# define LIB_ARCH_TUPLE "mipsel-linux-gnu" +# endif +# define PROC_CPUINFO_MODEL "cpu model" +#elif defined(__alpha__) +# define native_architecture() ARCHITECTURE_ALPHA +# define LIB_ARCH_TUPLE "alpha-linux-gnu" +#elif defined(__aarch64__) +# if __BYTE_ORDER == __BIG_ENDIAN +# define native_architecture() ARCHITECTURE_ARM64_BE +# define LIB_ARCH_TUPLE "aarch64_be-linux-gnu" +# else +# define native_architecture() ARCHITECTURE_ARM64 +# define LIB_ARCH_TUPLE "aarch64-linux-gnu" +# endif +#elif defined(__arm__) +# if __BYTE_ORDER == __BIG_ENDIAN +# define native_architecture() ARCHITECTURE_ARM_BE +# if defined(__ARM_EABI__) +# if defined(__ARM_PCS_VFP) +# define LIB_ARCH_TUPLE "armeb-linux-gnueabihf" +# else +# define LIB_ARCH_TUPLE "armeb-linux-gnueabi" +# endif +# else +# define LIB_ARCH_TUPLE "armeb-linux-gnu" +# endif +# else +# define native_architecture() ARCHITECTURE_ARM +# if defined(__ARM_EABI__) +# if defined(__ARM_PCS_VFP) +# define LIB_ARCH_TUPLE "arm-linux-gnueabihf" +# else +# define LIB_ARCH_TUPLE "arm-linux-gnueabi" +# endif +# else +# define LIB_ARCH_TUPLE "arm-linux-gnu" +# endif +# endif +# define PROC_CPUINFO_MODEL "model name" +#elif defined(__sh64__) +# define native_architecture() ARCHITECTURE_SH64 +# error "Missing LIB_ARCH_TUPLE for SH64" +#elif defined(__sh__) +# define native_architecture() ARCHITECTURE_SH +# define LIB_ARCH_TUPLE "sh4-linux-gnu" +#elif defined(__m68k__) +# define native_architecture() ARCHITECTURE_M68K +# define LIB_ARCH_TUPLE "m68k-linux-gnu" +#elif defined(__tilegx__) +# define native_architecture() ARCHITECTURE_TILEGX +# error "Missing LIB_ARCH_TUPLE for TILEGX" +#elif defined(__cris__) +# define native_architecture() ARCHITECTURE_CRIS +# error "Missing LIB_ARCH_TUPLE for CRIS" +#else +# error "Please register your architecture here!" +#endif + +#ifndef PROC_CPUINFO_MODEL +#warning "PROC_CPUINFO_MODEL not defined for your architecture" +#define PROC_CPUINFO_MODEL "model name" +#endif + +const char *architecture_to_string(int a) _const_; +int architecture_from_string(const char *s) _pure_; diff --git a/src/shared/architecture.c b/src/shared/architecture.c deleted file mode 100644 index a9ecfc1cd6..0000000000 --- a/src/shared/architecture.c +++ /dev/null @@ -1,176 +0,0 @@ -/*** - 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 . -***/ - -#include - -#include "architecture.h" -#include "macro.h" -#include "string-table.h" -#include "string-util.h" - -int uname_architecture(void) { - - /* Return a sanitized enum identifying the architecture we are - * running on. This is based on uname(), and the user may - * hence control what this returns by using - * personality(). This puts the user in control on systems - * that can run binaries of multiple architectures. - * - * We do not translate the string returned by uname() - * 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 distinguish CPUs not CPU features, but - * actual architectures, i.e. that have genuinely different - * code. */ - - static const struct { - const char *machine; - int arch; - } arch_map[] = { -#if defined(__x86_64__) || defined(__i386__) - { "x86_64", ARCHITECTURE_X86_64 }, - { "i686", ARCHITECTURE_X86 }, - { "i586", ARCHITECTURE_X86 }, - { "i486", ARCHITECTURE_X86 }, - { "i386", ARCHITECTURE_X86 }, -#elif defined(__powerpc__) || defined(__powerpc64__) - { "ppc64", ARCHITECTURE_PPC64 }, - { "ppc64le", ARCHITECTURE_PPC64_LE }, - { "ppc", ARCHITECTURE_PPC }, - { "ppcle", ARCHITECTURE_PPC_LE }, -#elif defined(__ia64__) - { "ia64", ARCHITECTURE_IA64 }, -#elif defined(__hppa__) || defined(__hppa64__) - { "parisc64", ARCHITECTURE_PARISC64 }, - { "parisc", ARCHITECTURE_PARISC }, -#elif defined(__s390__) || defined(__s390x__) - { "s390x", ARCHITECTURE_S390X }, - { "s390", ARCHITECTURE_S390 }, -#elif defined(__sparc__) || defined(__sparc64__) - { "sparc64", ARCHITECTURE_SPARC64 }, - { "sparc", ARCHITECTURE_SPARC }, -#elif defined(__mips__) || defined(__mips64__) - { "mips64", ARCHITECTURE_MIPS64 }, - { "mips", ARCHITECTURE_MIPS }, -#elif defined(__alpha__) - { "alpha" , ARCHITECTURE_ALPHA }, -#elif defined(__arm__) || defined(__aarch64__) - { "aarch64", ARCHITECTURE_ARM64 }, - { "aarch64_be", ARCHITECTURE_ARM64_BE }, - { "armv4l", ARCHITECTURE_ARM }, - { "armv4b", ARCHITECTURE_ARM_BE }, - { "armv4tl", ARCHITECTURE_ARM }, - { "armv4tb", ARCHITECTURE_ARM_BE }, - { "armv5tl", ARCHITECTURE_ARM }, - { "armv5tb", ARCHITECTURE_ARM_BE }, - { "armv5tel", ARCHITECTURE_ARM }, - { "armv5teb" , ARCHITECTURE_ARM_BE }, - { "armv5tejl", ARCHITECTURE_ARM }, - { "armv5tejb", ARCHITECTURE_ARM_BE }, - { "armv6l", ARCHITECTURE_ARM }, - { "armv6b", ARCHITECTURE_ARM_BE }, - { "armv7l", ARCHITECTURE_ARM }, - { "armv7b", ARCHITECTURE_ARM_BE }, - { "armv7ml", ARCHITECTURE_ARM }, - { "armv7mb", ARCHITECTURE_ARM_BE }, - { "armv4l", ARCHITECTURE_ARM }, - { "armv4b", ARCHITECTURE_ARM_BE }, - { "armv4tl", ARCHITECTURE_ARM }, - { "armv4tb", ARCHITECTURE_ARM_BE }, - { "armv5tl", ARCHITECTURE_ARM }, - { "armv5tb", ARCHITECTURE_ARM_BE }, - { "armv5tel", ARCHITECTURE_ARM }, - { "armv5teb", ARCHITECTURE_ARM_BE }, - { "armv5tejl", ARCHITECTURE_ARM }, - { "armv5tejb", ARCHITECTURE_ARM_BE }, - { "armv6l", ARCHITECTURE_ARM }, - { "armv6b", ARCHITECTURE_ARM_BE }, - { "armv7l", ARCHITECTURE_ARM }, - { "armv7b", ARCHITECTURE_ARM_BE }, - { "armv7ml", ARCHITECTURE_ARM }, - { "armv7mb", ARCHITECTURE_ARM_BE }, - { "armv8l", ARCHITECTURE_ARM }, - { "armv8b", ARCHITECTURE_ARM_BE }, -#elif defined(__sh__) || defined(__sh64__) - { "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__) - { "tilegx", ARCHITECTURE_TILEGX }, -#elif defined(__cris__) - { "crisv32", ARCHITECTURE_CRIS }, -#else -#error "Please register your architecture here!" -#endif - }; - - static int cached = _ARCHITECTURE_INVALID; - struct utsname u; - unsigned i; - - if (cached != _ARCHITECTURE_INVALID) - return cached; - - assert_se(uname(&u) >= 0); - - for (i = 0; i < ELEMENTSOF(arch_map); i++) - if (streq(arch_map[i].machine, u.machine)) - return cached = arch_map[i].arch; - - assert_not_reached("Couldn't identify architecture. You need to patch systemd."); - return _ARCHITECTURE_INVALID; -} - -static const char *const architecture_table[_ARCHITECTURE_MAX] = { - [ARCHITECTURE_X86] = "x86", - [ARCHITECTURE_X86_64] = "x86-64", - [ARCHITECTURE_PPC] = "ppc", - [ARCHITECTURE_PPC_LE] = "ppc-le", - [ARCHITECTURE_PPC64] = "ppc64", - [ARCHITECTURE_PPC64_LE] = "ppc64-le", - [ARCHITECTURE_IA64] = "ia64", - [ARCHITECTURE_PARISC] = "parisc", - [ARCHITECTURE_PARISC64] = "parisc64", - [ARCHITECTURE_S390] = "s390", - [ARCHITECTURE_S390X] = "s390x", - [ARCHITECTURE_SPARC] = "sparc", - [ARCHITECTURE_SPARC64] = "sparc64", - [ARCHITECTURE_MIPS] = "mips", - [ARCHITECTURE_MIPS_LE] = "mips-le", - [ARCHITECTURE_MIPS64] = "mips64", - [ARCHITECTURE_MIPS64_LE] = "mips64-le", - [ARCHITECTURE_ALPHA] = "alpha", - [ARCHITECTURE_ARM] = "arm", - [ARCHITECTURE_ARM_BE] = "arm-be", - [ARCHITECTURE_ARM64] = "arm64", - [ARCHITECTURE_ARM64_BE] = "arm64-be", - [ARCHITECTURE_SH] = "sh", - [ARCHITECTURE_SH64] = "sh64", - [ARCHITECTURE_M68K] = "m68k", - [ARCHITECTURE_TILEGX] = "tilegx", - [ARCHITECTURE_CRIS] = "cris", -}; - -DEFINE_STRING_TABLE_LOOKUP(architecture, int); diff --git a/src/shared/architecture.h b/src/shared/architecture.h deleted file mode 100644 index 26679e28c6..0000000000 --- a/src/shared/architecture.h +++ /dev/null @@ -1,207 +0,0 @@ -#pragma once - -/*** - 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 . -***/ - -#include - -#include "macro.h" -#include "util.h" - -/* 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 distinguish word width and - * endianness. */ - -enum { - ARCHITECTURE_X86 = 0, - ARCHITECTURE_X86_64, - ARCHITECTURE_PPC, - ARCHITECTURE_PPC_LE, - ARCHITECTURE_PPC64, - ARCHITECTURE_PPC64_LE, - ARCHITECTURE_IA64, - ARCHITECTURE_PARISC, - ARCHITECTURE_PARISC64, - ARCHITECTURE_S390, - ARCHITECTURE_S390X, - ARCHITECTURE_SPARC, - ARCHITECTURE_SPARC64, - ARCHITECTURE_MIPS, - ARCHITECTURE_MIPS_LE, - ARCHITECTURE_MIPS64, - ARCHITECTURE_MIPS64_LE, - ARCHITECTURE_ALPHA, - ARCHITECTURE_ARM, - ARCHITECTURE_ARM_BE, - ARCHITECTURE_ARM64, - ARCHITECTURE_ARM64_BE, - ARCHITECTURE_SH, - ARCHITECTURE_SH64, - ARCHITECTURE_M68K, - ARCHITECTURE_TILEGX, - ARCHITECTURE_CRIS, - _ARCHITECTURE_MAX, - _ARCHITECTURE_INVALID = -1 -}; - -int uname_architecture(void); - -/* - * LIB_ARCH_TUPLE should resolve to the local library path - * architecture tuple systemd is built for, according to the Debian - * tuple list: - * - * https://wiki.debian.org/Multiarch/Tuples - * - * This is used in library search paths that should understand - * Debian's paths on all distributions. - */ - -#if defined(__x86_64__) -# define native_architecture() ARCHITECTURE_X86_64 -# define LIB_ARCH_TUPLE "x86_64-linux-gnu" -# define PROC_CPUINFO_MODEL "model name" -#elif defined(__i386__) -# define native_architecture() ARCHITECTURE_X86 -# define LIB_ARCH_TUPLE "i386-linux-gnu" -# define PROC_CPUINFO_MODEL "model name" -#elif defined(__powerpc64__) -# if __BYTE_ORDER == __BIG_ENDIAN -# define native_architecture() ARCHITECTURE_PPC64 -# define LIB_ARCH_TUPLE "ppc64-linux-gnu" -# else -# define native_architecture() ARCHITECTURE_PPC64_LE -# define LIB_ARCH_TUPLE "powerpc64le-linux-gnu" -# endif -# define PROC_CPUINFO_MODEL "cpu" -#elif defined(__powerpc__) -# if __BYTE_ORDER == __BIG_ENDIAN -# define native_architecture() ARCHITECTURE_PPC -# define LIB_ARCH_TUPLE "powerpc-linux-gnu" -# else -# define native_architecture() ARCHITECTURE_PPC_LE -# error "Missing LIB_ARCH_TUPLE for PPCLE" -# endif -# define PROC_CPUINFO_MODEL "cpu" -#elif defined(__ia64__) -# define native_architecture() ARCHITECTURE_IA64 -# define LIB_ARCH_TUPLE "ia64-linux-gnu" -#elif defined(__hppa64__) -# define native_architecture() ARCHITECTURE_PARISC64 -# error "Missing LIB_ARCH_TUPLE for HPPA64" -# define PROC_CPUINFO_MODEL "cpu" -#elif defined(__hppa__) -# define native_architecture() ARCHITECTURE_PARISC -# define LIB_ARCH_TUPLE "hppa‑linux‑gnu" -# define PROC_CPUINFO_MODEL "cpu" -#elif defined(__s390x__) -# define native_architecture() ARCHITECTURE_S390X -# define LIB_ARCH_TUPLE "s390x-linux-gnu" -#elif defined(__s390__) -# define native_architecture() ARCHITECTURE_S390 -# define LIB_ARCH_TUPLE "s390-linux-gnu" -#elif defined(__sparc64__) -# define native_architecture() ARCHITECTURE_SPARC64 -# define LIB_ARCH_TUPLE "sparc64-linux-gnu" -# define PROC_CPUINFO_MODEL "cpu" -#elif defined(__sparc__) -# define native_architecture() ARCHITECTURE_SPARC -# define LIB_ARCH_TUPLE "sparc-linux-gnu" -# define PROC_CPUINFO_MODEL "cpu" -#elif defined(__mips64__) -# if __BYTE_ORDER == __BIG_ENDIAN -# define native_architecture() ARCHITECTURE_MIPS64 -# error "Missing LIB_ARCH_TUPLE for MIPS64" -# else -# define native_architecture() ARCHITECTURE_MIPS64_LE -# error "Missing LIB_ARCH_TUPLE for MIPS64_LE" -# endif -# define PROC_CPUINFO_MODEL "cpu model" -#elif defined(__mips__) -# if __BYTE_ORDER == __BIG_ENDIAN -# define native_architecture() ARCHITECTURE_MIPS -# define LIB_ARCH_TUPLE "mips-linux-gnu" -# else -# define native_architecture() ARCHITECTURE_MIPS_LE -# define LIB_ARCH_TUPLE "mipsel-linux-gnu" -# endif -# define PROC_CPUINFO_MODEL "cpu model" -#elif defined(__alpha__) -# define native_architecture() ARCHITECTURE_ALPHA -# define LIB_ARCH_TUPLE "alpha-linux-gnu" -#elif defined(__aarch64__) -# if __BYTE_ORDER == __BIG_ENDIAN -# define native_architecture() ARCHITECTURE_ARM64_BE -# define LIB_ARCH_TUPLE "aarch64_be-linux-gnu" -# else -# define native_architecture() ARCHITECTURE_ARM64 -# define LIB_ARCH_TUPLE "aarch64-linux-gnu" -# endif -#elif defined(__arm__) -# if __BYTE_ORDER == __BIG_ENDIAN -# define native_architecture() ARCHITECTURE_ARM_BE -# if defined(__ARM_EABI__) -# if defined(__ARM_PCS_VFP) -# define LIB_ARCH_TUPLE "armeb-linux-gnueabihf" -# else -# define LIB_ARCH_TUPLE "armeb-linux-gnueabi" -# endif -# else -# define LIB_ARCH_TUPLE "armeb-linux-gnu" -# endif -# else -# define native_architecture() ARCHITECTURE_ARM -# if defined(__ARM_EABI__) -# if defined(__ARM_PCS_VFP) -# define LIB_ARCH_TUPLE "arm-linux-gnueabihf" -# else -# define LIB_ARCH_TUPLE "arm-linux-gnueabi" -# endif -# else -# define LIB_ARCH_TUPLE "arm-linux-gnu" -# endif -# endif -# define PROC_CPUINFO_MODEL "model name" -#elif defined(__sh64__) -# define native_architecture() ARCHITECTURE_SH64 -# error "Missing LIB_ARCH_TUPLE for SH64" -#elif defined(__sh__) -# define native_architecture() ARCHITECTURE_SH -# define LIB_ARCH_TUPLE "sh4-linux-gnu" -#elif defined(__m68k__) -# define native_architecture() ARCHITECTURE_M68K -# define LIB_ARCH_TUPLE "m68k-linux-gnu" -#elif defined(__tilegx__) -# define native_architecture() ARCHITECTURE_TILEGX -# error "Missing LIB_ARCH_TUPLE for TILEGX" -#elif defined(__cris__) -# define native_architecture() ARCHITECTURE_CRIS -# error "Missing LIB_ARCH_TUPLE for CRIS" -#else -# error "Please register your architecture here!" -#endif - -#ifndef PROC_CPUINFO_MODEL -#warning "PROC_CPUINFO_MODEL not defined for your architecture" -#define PROC_CPUINFO_MODEL "model name" -#endif - -const char *architecture_to_string(int a) _const_; -int architecture_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From 6e5f1b5742f3902469123af29502d06a4515f6b9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 15:39:52 +0100 Subject: util-lib: use the architecture ids from architecture.h for personalities We have this ids, hence let's use them universally. --- src/basic/process-util.c | 51 ++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 27663eee51..5c7530ffa0 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -38,6 +38,7 @@ #endif #include "alloc-util.h" +#include "architecture.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" @@ -674,38 +675,40 @@ bool oom_score_adjust_is_valid(int oa) { } unsigned long personality_from_string(const char *p) { + int architecture; - /* Parse a personality specifier. We introduce our own - * identifiers that indicate specific ABIs, rather than just - * hints regarding the register size, since we want to keep - * things open for multiple locally supported ABIs for the - * same register size. We try to reuse the ABI identifiers - * used by libseccomp. */ + /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just + * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for + * the same register size. */ + + architecture = architecture_from_string(p); + if (architecture < 0) + return PERSONALITY_INVALID; #if defined(__x86_64__) - if (streq(p, "x86")) + if (architecture == ARCHITECTURE_X86) return PER_LINUX32; - if (streq(p, "x86-64")) + if (architecture == ARCHITECTURE_X86_64) return PER_LINUX; #elif defined(__i386__) - if (streq(p, "x86")) + if (architecture == ARCHITECTURE_X86) return PER_LINUX; #elif defined(__s390x__) - if (streq(p, "s390")) + if (architecture == ARCHITECTURE_S390) return PER_LINUX32; - if (streq(p, "s390x")) + if (architecture == ARCHITECTURE_S390X) return PER_LINUX; #elif defined(__s390__) - if (streq(p, "s390")) + if (architecture == ARCHITECTURE_S390) return PER_LINUX; #endif @@ -713,36 +716,38 @@ unsigned long personality_from_string(const char *p) { } const char* personality_to_string(unsigned long p) { + int architecture = _ARCHITECTURE_INVALID; #if defined(__x86_64__) - if (p == PER_LINUX32) - return "x86"; - if (p == PER_LINUX) - return "x86-64"; + architecture = ARCHITECTURE_X86_64; + else if (p == PER_LINUX32) + architecture = ARCHITECTURE_X86; #elif defined(__i386__) if (p == PER_LINUX) - return "x86"; + architecture = ARCHITECTURE_X86; #elif defined(__s390x__) if (p == PER_LINUX) - return "s390x"; - - if (p == PER_LINUX32) - return "s390"; + architecture = ARCHITECTURE_S390X; + else if (p == PER_LINUX32) + architecture = ARCHITECTURE_S390; #elif defined(__s390__) if (p == PER_LINUX) - return "s390"; + architecture = ARCHITECTURE_S390; #endif - return NULL; + if (architecture < 0) + return NULL; + + return architecture_to_string(architecture); } void valgrind_summary_hack(void) { -- cgit v1.2.3-54-g00ecf From f2d1736c60e6df3760545dedfa04d0d72b4451b1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 15:50:35 +0100 Subject: util-lib: support various ppc archs in personality logic --- src/basic/process-util.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 5c7530ffa0..f45e4ca338 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -710,6 +710,37 @@ unsigned long personality_from_string(const char *p) { if (architecture == ARCHITECTURE_S390) return PER_LINUX; + +#elif defined(__powerpc64__) +# if __BYTE_ORDER == __BIG_ENDIAN + + if (architecture == ARCHITECTURE_PPC_LE) + return PER_LINUX32; + + if (architecture == ARCHITECTURE_PPC64_LE) + return PER_LINUX; + +# else + + if (architecture == ARCHITECTURE_PPC) + return PER_LINUX32; + + if (architecture == ARCHITECTURE_PPC64) + return PER_LINUX; + +# endif +#elif defined(__powerpc__) +# if __BYTE_ORDER == __BIG_ENDIAN + + if (architecture == ARCHITECTURE_PPC) + return PER_LINUX; + +# else + + if (architecture == ARCHITECTURE_PPC_LE) + return PER_LINUX; + +# endif #endif return PERSONALITY_INVALID; @@ -742,6 +773,34 @@ const char* personality_to_string(unsigned long p) { if (p == PER_LINUX) architecture = ARCHITECTURE_S390; +#elif defined(__powerpc64__) +# if __BYTE_ORDER == __BIG_ENDIAN + + if (p == PER_LINUX) + architecture = ARCHITECTURE_PPC64; + else if (p == PER_LINUX32) + architecture = ARCHITECTURE_PPC; + +# else + + if (p == PER_LINUX) + architecture = ARCHITECTURE_PPC64_LE; + else if (p == PER_LINUX32) + architecture = ARCHITECTURE_PPC_LE; + +# endif +#elif defined(__powerpc__) +# if __BYTE_ORDER == __BIG_ENDIAN + + if (p == PER_LINUX) + architecture = ARCHITECTURE_PPC; + +# else + + if (p == PER_LINUX) + architecture = ARCHITECTURE_PPC_LE; + +# endif #endif if (architecture < 0) -- cgit v1.2.3-54-g00ecf From d5b687e7c25bb5cc2d516bcdbd3b093749cbd337 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 16:28:17 +0100 Subject: virt: make sure we don't ignore some errors --- src/basic/virt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/basic/virt.c b/src/basic/virt.c index 19b6318e3d..79387007f0 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -201,6 +201,8 @@ static int detect_vm_xen(void) { r = read_one_line_file("/proc/xen/capabilities", &domcap); if (r == -ENOENT) return VIRTUALIZATION_NONE; + if (r < 0) + return r; i = domcap; while ((cap = strsep(&i, ","))) -- cgit v1.2.3-54-g00ecf From 0c0fea07b8da1ef31521658e5764267218da2f13 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 18:29:05 +0100 Subject: util-lib: simplify personality() string matching --- src/basic/architecture.h | 4 ++ src/basic/process-util.c | 113 ++++------------------------------------------- 2 files changed, 13 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/basic/architecture.h b/src/basic/architecture.h index 26679e28c6..63cf6fb703 100644 --- a/src/basic/architecture.h +++ b/src/basic/architecture.h @@ -78,6 +78,7 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_X86_64 # define LIB_ARCH_TUPLE "x86_64-linux-gnu" # define PROC_CPUINFO_MODEL "model name" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_X86 #elif defined(__i386__) # define native_architecture() ARCHITECTURE_X86 # define LIB_ARCH_TUPLE "i386-linux-gnu" @@ -86,9 +87,11 @@ int uname_architecture(void); # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC64 # define LIB_ARCH_TUPLE "ppc64-linux-gnu" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_PPC # else # define native_architecture() ARCHITECTURE_PPC64_LE # define LIB_ARCH_TUPLE "powerpc64le-linux-gnu" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_PPC_LE # endif # define PROC_CPUINFO_MODEL "cpu" #elif defined(__powerpc__) @@ -114,6 +117,7 @@ int uname_architecture(void); #elif defined(__s390x__) # define native_architecture() ARCHITECTURE_S390X # define LIB_ARCH_TUPLE "s390x-linux-gnu" +# define SECONDARY_ARCHITECTURE ARCHITECTURE_S390 #elif defined(__s390__) # define native_architecture() ARCHITECTURE_S390 # define LIB_ARCH_TUPLE "s390-linux-gnu" diff --git a/src/basic/process-util.c b/src/basic/process-util.c index f45e4ca338..ae3f6109ad 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -677,6 +677,9 @@ bool oom_score_adjust_is_valid(int oa) { unsigned long personality_from_string(const char *p) { int architecture; + if (!p) + return PERSONALITY_INVALID; + /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for * the same register size. */ @@ -685,62 +688,11 @@ unsigned long personality_from_string(const char *p) { if (architecture < 0) return PERSONALITY_INVALID; -#if defined(__x86_64__) - - if (architecture == ARCHITECTURE_X86) - return PER_LINUX32; - - if (architecture == ARCHITECTURE_X86_64) - return PER_LINUX; - -#elif defined(__i386__) - - if (architecture == ARCHITECTURE_X86) - return PER_LINUX; - -#elif defined(__s390x__) - - if (architecture == ARCHITECTURE_S390) - return PER_LINUX32; - - if (architecture == ARCHITECTURE_S390X) - return PER_LINUX; - -#elif defined(__s390__) - - if (architecture == ARCHITECTURE_S390) + if (architecture == native_architecture()) return PER_LINUX; - -#elif defined(__powerpc64__) -# if __BYTE_ORDER == __BIG_ENDIAN - - if (architecture == ARCHITECTURE_PPC_LE) +#ifdef SECONDARY_ARCHITECTURE + if (architecture == SECONDARY_ARCHITECTURE) return PER_LINUX32; - - if (architecture == ARCHITECTURE_PPC64_LE) - return PER_LINUX; - -# else - - if (architecture == ARCHITECTURE_PPC) - return PER_LINUX32; - - if (architecture == ARCHITECTURE_PPC64) - return PER_LINUX; - -# endif -#elif defined(__powerpc__) -# if __BYTE_ORDER == __BIG_ENDIAN - - if (architecture == ARCHITECTURE_PPC) - return PER_LINUX; - -# else - - if (architecture == ARCHITECTURE_PPC_LE) - return PER_LINUX; - -# endif #endif return PERSONALITY_INVALID; @@ -749,58 +701,11 @@ unsigned long personality_from_string(const char *p) { const char* personality_to_string(unsigned long p) { int architecture = _ARCHITECTURE_INVALID; -#if defined(__x86_64__) - if (p == PER_LINUX) - architecture = ARCHITECTURE_X86_64; + architecture = native_architecture(); +#ifdef SECONDARY_ARCHITECTURE else if (p == PER_LINUX32) - architecture = ARCHITECTURE_X86; - -#elif defined(__i386__) - - if (p == PER_LINUX) - architecture = ARCHITECTURE_X86; - -#elif defined(__s390x__) - - if (p == PER_LINUX) - architecture = ARCHITECTURE_S390X; - else if (p == PER_LINUX32) - architecture = ARCHITECTURE_S390; - -#elif defined(__s390__) - - if (p == PER_LINUX) - architecture = ARCHITECTURE_S390; - -#elif defined(__powerpc64__) -# if __BYTE_ORDER == __BIG_ENDIAN - - if (p == PER_LINUX) - architecture = ARCHITECTURE_PPC64; - else if (p == PER_LINUX32) - architecture = ARCHITECTURE_PPC; - -# else - - if (p == PER_LINUX) - architecture = ARCHITECTURE_PPC64_LE; - else if (p == PER_LINUX32) - architecture = ARCHITECTURE_PPC_LE; - -# endif -#elif defined(__powerpc__) -# if __BYTE_ORDER == __BIG_ENDIAN - - if (p == PER_LINUX) - architecture = ARCHITECTURE_PPC; - -# else - - if (p == PER_LINUX) - architecture = ARCHITECTURE_PPC_LE; - -# endif + architecture = SECONDARY_ARCHITECTURE; #endif if (architecture < 0) -- cgit v1.2.3-54-g00ecf From 26fbedd7dc3481c34c6a955d9d2328dde8d9c15a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 18:36:54 +0100 Subject: tests: add personality tests --- src/test/test-process-util.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'src') diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 48be5a3a87..4616314200 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -18,12 +18,14 @@ along with systemd; If not, see . ***/ +#include #include #include #include #include #include "alloc-util.h" +#include "architecture.h" #include "log.h" #include "macro.h" #include "process-util.h" @@ -128,6 +130,29 @@ static void test_pid_is_alive(void) { assert_se(!pid_is_alive(-1)); } +static void test_personality(void) { + + assert_se(personality_to_string(PER_LINUX)); + assert_se(!personality_to_string(PERSONALITY_INVALID)); + + assert_se(streq(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()))); + + assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX); + assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX); + +#ifdef __x86_64__ + assert_se(streq_ptr(personality_to_string(PER_LINUX), "x86-64")); + assert_se(streq_ptr(personality_to_string(PER_LINUX32), "x86")); + + assert_se(personality_from_string("x86-64") == PER_LINUX); + assert_se(personality_from_string("x86") == PER_LINUX32); + assert_se(personality_from_string("ia64") == PERSONALITY_INVALID); + assert_se(personality_from_string(NULL) == PERSONALITY_INVALID); + + assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32); +#endif +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -135,6 +160,7 @@ int main(int argc, char *argv[]) { test_get_process_comm(); test_pid_is_unwaited(); test_pid_is_alive(); + test_personality(); return 0; } -- cgit v1.2.3-54-g00ecf From 1a39bc8c650802630696c38e510a4a2a4c6bda92 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 18:40:28 +0100 Subject: hashmap: use void* and uint8_t* for generic pointers As suggested by CODING_STYLE we should use "void*" as type for generic memory, and uint8_t* for generic bytes. Hence use that instead of "char*", which should really be used only for strings these days. --- src/basic/hashmap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 6f1a049d47..85b8d812b3 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -176,7 +176,7 @@ enum HashmapType { }; struct _packed_ indirect_storage { - char *storage; /* where buckets and DIBs are stored */ + void *storage; /* where buckets and DIBs are stored */ uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ unsigned n_entries; /* number of stored entries */ @@ -193,7 +193,7 @@ struct direct_storage { /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ - char storage[sizeof(struct indirect_storage)]; + uint8_t storage[sizeof(struct indirect_storage)]; }; #define DIRECT_BUCKETS(entry_t) \ @@ -302,7 +302,7 @@ static void n_entries_dec(HashmapBase *h) { h->n_direct_entries--; } -static char *storage_ptr(HashmapBase *h) { +static void *storage_ptr(HashmapBase *h) { return h->has_indirect ? h->indirect.storage : h->direct.storage; } @@ -347,7 +347,7 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) { return (struct hashmap_base_entry*) - (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); + ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); } static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) { @@ -381,7 +381,7 @@ static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_ static dib_raw_t *dib_raw_ptr(HashmapBase *h) { return (dib_raw_t*) - (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); + ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); } static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) { @@ -1028,7 +1028,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, */ static int resize_buckets(HashmapBase *h, unsigned entries_add) { struct swap_entries swap; - char *new_storage; + void *new_storage; dib_raw_t *old_dibs, *new_dibs; const struct hashmap_type_info *hi; unsigned idx, optimal_idx; @@ -1095,7 +1095,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) { h->indirect.n_buckets = (1U << new_shift) / (hi->entry_size + sizeof(dib_raw_t)); - old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets); + old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets); new_dibs = dib_raw_ptr(h); /* -- cgit v1.2.3-54-g00ecf From 35aa04e9edf422beac3493afa555d29575b3046c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 22 Feb 2016 20:39:45 +0100 Subject: resolved: fix notification iteration logic when transactions are completed When a transaction is complete, and we notify its owners, make sure we deal correctly with the requesters removing themselves from the list of owners while we continue iterating. This was previously already dealt with with transactions that require other transactions for DNSSEC purposes, fix this for other possibly transaction owners too now. Since iterating through "Set" objects is not safe regarding removal of entries from it, rework the logic to use two Sets, and move each entry we notified from one set to the other set before we dispatch the notification. This move operation requires no additional memory, and enables us to ensure that we don't notify any object twice. Fixes: #2676 --- src/basic/macro.h | 6 ++++ src/basic/set.h | 3 ++ src/resolve/resolved-dns-query.c | 5 +++ src/resolve/resolved-dns-transaction.c | 62 ++++++++++++++++------------------ src/resolve/resolved-dns-transaction.h | 6 ++-- src/resolve/resolved-dns-zone.c | 5 +++ 6 files changed, 52 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/basic/macro.h b/src/basic/macro.h index 2695d0edb7..ab5cc97e17 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -361,6 +361,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { _found; \ }) +#define SWAP_TWO(x, y) do { \ + typeof(x) _t = (x); \ + (x) = (y); \ + (y) = (_t); \ + } while (false) + /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local diff --git a/src/basic/set.h b/src/basic/set.h index 2bff5062da..e0d9dd001c 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -126,6 +126,9 @@ int set_put_strdupv(Set *s, char **l); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) +#define SET_FOREACH_MOVE(e, d, s) \ + for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); ) + DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index a7496aa586..dd133e1097 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -62,6 +62,7 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) { while ((t = set_steal_first(c->transactions))) { set_remove(t->notify_query_candidates, c); + set_remove(t->notify_query_candidates_done, c); dns_transaction_gc(t); } } @@ -139,6 +140,10 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource if (r < 0) goto gc; + r = set_ensure_allocated(&t->notify_query_candidates_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->notify_query_candidates, c); if (r < 0) goto gc; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 3443f71976..1cd5d1be8a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -52,6 +52,7 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) { while ((z = set_steal_first(t->dnssec_transactions))) { set_remove(z->notify_transactions, t); + set_remove(z->notify_transactions_done, t); dns_transaction_gc(z); } } @@ -100,14 +101,26 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { set_remove(c->transactions, t); set_free(t->notify_query_candidates); + while ((c = set_steal_first(t->notify_query_candidates_done))) + set_remove(c->transactions, t); + set_free(t->notify_query_candidates_done); + while ((i = set_steal_first(t->notify_zone_items))) i->probe_transaction = NULL; set_free(t->notify_zone_items); + while ((i = set_steal_first(t->notify_zone_items_done))) + i->probe_transaction = NULL; + set_free(t->notify_zone_items_done); + while ((z = set_steal_first(t->notify_transactions))) set_remove(z->dnssec_transactions, t); set_free(t->notify_transactions); + while ((z = set_steal_first(t->notify_transactions_done))) + set_remove(z->dnssec_transactions, t); + set_free(t->notify_transactions_done); + dns_transaction_flush_dnssec_transactions(t); set_free(t->dnssec_transactions); @@ -127,8 +140,11 @@ bool dns_transaction_gc(DnsTransaction *t) { return true; if (set_isempty(t->notify_query_candidates) && + set_isempty(t->notify_query_candidates_done) && set_isempty(t->notify_zone_items) && - set_isempty(t->notify_transactions)) { + set_isempty(t->notify_zone_items_done) && + set_isempty(t->notify_transactions) && + set_isempty(t->notify_transactions_done)) { dns_transaction_free(t); return false; } @@ -266,6 +282,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { log_debug("We have the lexicographically larger IP address and thus lost in the conflict."); t->block_gc++; + while ((z = set_first(t->notify_zone_items))) { /* First, make sure the zone item drops the reference * to us */ @@ -284,7 +301,6 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { DnsQueryCandidate *c; DnsZoneItem *z; DnsTransaction *d; - Iterator i; const char *st; char key_str[DNS_RESOURCE_KEY_STRING_MAX]; @@ -333,39 +349,17 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { * transaction isn't freed while we are still looking at it */ t->block_gc++; - SET_FOREACH(c, t->notify_query_candidates, i) + SET_FOREACH_MOVE(c, t->notify_query_candidates_done, t->notify_query_candidates) dns_query_candidate_notify(c); - SET_FOREACH(z, t->notify_zone_items, i) - dns_zone_item_notify(z); + SWAP_TWO(t->notify_query_candidates, t->notify_query_candidates_done); - if (!set_isempty(t->notify_transactions)) { - DnsTransaction **nt; - unsigned j, n = 0; - - /* We need to be careful when notifying other - * transactions, as that might destroy other - * transactions in our list. Hence, in order to be - * able to safely iterate through the list of - * transactions, take a GC lock on all of them - * first. Then, in a second loop, notify them, but - * first unlock that specific transaction. */ - - nt = newa(DnsTransaction*, set_size(t->notify_transactions)); - SET_FOREACH(d, t->notify_transactions, i) { - nt[n++] = d; - d->block_gc++; - } - - assert(n == set_size(t->notify_transactions)); + SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items) + dns_zone_item_notify(z); + SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done); - for (j = 0; j < n; j++) { - if (set_contains(t->notify_transactions, nt[j])) - dns_transaction_notify(nt[j], t); - - nt[j]->block_gc--; - dns_transaction_gc(nt[j]); - } - } + SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions) + dns_transaction_notify(d, t); + SWAP_TWO(t->notify_transactions, t->notify_transactions_done); t->block_gc--; dns_transaction_gc(t); @@ -1626,6 +1620,10 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource if (r < 0) goto gc; + r = set_ensure_allocated(&aux->notify_transactions_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->dnssec_transactions, aux); if (r < 0) goto gc; diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 491c62d772..eaece91533 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -118,17 +118,17 @@ struct DnsTransaction { /* Query candidates this transaction is referenced by and that * shall be notified about this specific transaction * completing. */ - Set *notify_query_candidates; + Set *notify_query_candidates, *notify_query_candidates_done; /* Zone items this transaction is referenced by and that shall * be notified about completion. */ - Set *notify_zone_items; + Set *notify_zone_items, *notify_zone_items_done; /* Other transactions that this transactions is referenced by * and that shall be notified about completion. This is used * when transactions want to validate their RRsets, but need * another DNSKEY or DS RR to do so. */ - Set *notify_transactions; + Set *notify_transactions, *notify_transactions_done; /* The opposite direction: the transactions this transaction * created in order to request DNSKEY or DS RRs. */ diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 03813da6a2..850eed8cb8 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -38,6 +38,7 @@ void dns_zone_item_probe_stop(DnsZoneItem *i) { i->probe_transaction = NULL; set_remove(t->notify_zone_items, i); + set_remove(t->notify_zone_items_done, i); dns_transaction_gc(t); } @@ -186,6 +187,10 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { if (r < 0) goto gc; + r = set_ensure_allocated(&t->notify_zone_items_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->notify_zone_items, i); if (r < 0) goto gc; -- cgit v1.2.3-54-g00ecf From ec9ffa2cdd931d8ab8ac0d90b1d9eff180a07288 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Mon, 22 Feb 2016 20:00:13 -0800 Subject: journal: restore offline state on error If we fail to create the thread, technically we should leave the offline_state as OFFLINE_JOINED, not OFFLINE_SYNCING. --- src/journal/journal-file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index f5e2952c99..80e34f6e8b 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -238,8 +238,10 @@ int journal_file_set_offline(JournalFile *f, bool wait) { journal_file_set_offline_internal(f); else { r = pthread_create(&f->offline_thread, NULL, journal_file_set_offline_thread, f); - if (r > 0) + if (r > 0) { + f->offline_state = OFFLINE_JOINED; return -r; + } } return 0; -- cgit v1.2.3-54-g00ecf From 313cefa1d96ff039d31994e4ea22e6c531a99ebd Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Mon, 22 Feb 2016 20:32:04 -0800 Subject: tree-wide: make ++/-- usage consistent WRT spacing Throughout the tree there's spurious use of spaces separating ++ and -- operators from their respective operands. Make ++ and -- operator consistent with the majority of existing uses; discard the spaces. --- src/activate/activate.c | 8 ++++---- src/analyze/analyze-verify.c | 2 +- src/basic/calendarspec.c | 10 +++++----- src/basic/extract-word.c | 14 +++++++------- src/basic/fileio.c | 10 +++++----- src/basic/hexdecoct.c | 10 +++++----- src/basic/hostname-util.c | 2 +- src/basic/io-util.c | 2 +- src/basic/strbuf.c | 2 +- src/basic/string-util.c | 2 +- src/basic/time-util.c | 4 ++-- src/basic/utf8.c | 2 +- src/core/execute.c | 2 +- src/core/job.c | 4 ++-- src/core/load-fragment.c | 4 ++-- src/core/main.c | 2 +- src/core/manager.c | 22 +++++++++++----------- src/core/service.c | 2 +- src/core/socket.c | 4 ++-- src/core/umount.c | 4 ++-- src/core/unit.c | 6 +++--- src/coredump/stacktrace.c | 4 ++-- src/initctl/initctl.c | 2 +- src/journal-remote/journal-remote.c | 4 ++-- src/journal-remote/journal-upload-journal.c | 18 +++++++++--------- src/journal/catalog.c | 2 +- src/journal/journal-file.c | 2 +- src/journal/journal-vacuum.c | 8 ++++---- src/journal/journal-verify.c | 8 ++++---- src/journal/journalctl.c | 12 ++++++------ src/journal/journald-audit.c | 6 +++--- src/journal/journald-kmsg.c | 2 +- src/journal/journald-rate-limit.c | 4 ++-- src/journal/journald-stream.c | 4 ++-- src/journal/mmap-cache.c | 8 ++++---- src/journal/sd-journal.c | 10 +++++----- src/journal/test-journal-enum.c | 2 +- src/libsystemd-network/dhcp-option.c | 2 +- src/libsystemd-network/dhcp-packet.c | 2 +- src/libsystemd-network/network-internal.c | 2 +- src/libsystemd/sd-bus/bus-dump.c | 2 +- src/libsystemd/sd-bus/bus-message.c | 14 +++++++------- src/libsystemd/sd-bus/bus-objects.c | 2 +- src/libsystemd/sd-bus/bus-slot.c | 2 +- src/libsystemd/sd-bus/bus-socket.c | 2 +- src/libsystemd/sd-bus/bus-track.c | 2 +- src/libsystemd/sd-bus/sd-bus.c | 12 ++++++------ src/libsystemd/sd-bus/test-bus-error.c | 2 +- src/libsystemd/sd-device/device-private.c | 6 +++--- src/libsystemd/sd-device/sd-device.c | 14 +++++++------- src/libsystemd/sd-event/sd-event.c | 4 ++-- src/libsystemd/sd-event/test-event.c | 2 +- src/libsystemd/sd-netlink/netlink-message.c | 14 +++++++------- src/libsystemd/sd-netlink/netlink-socket.c | 12 ++++++------ src/libsystemd/sd-netlink/sd-netlink.c | 2 +- src/libsystemd/sd-netlink/test-netlink.c | 6 +++--- src/libsystemd/sd-resolve/sd-resolve.c | 4 ++-- src/libudev/libudev-enumerate.c | 2 +- src/locale/localed.c | 2 +- src/machine/machinectl.c | 4 ++-- src/network/networkd-dhcp4.c | 8 ++++---- src/network/networkd-link.c | 24 ++++++++++++------------ src/network/networkd-ndisc.c | 8 ++++---- src/network/networkd-netdev-bond.c | 2 +- src/nspawn/nspawn-network.c | 2 +- src/nspawn/nspawn.c | 2 +- src/nss-mymachines/nss-mymachines.c | 2 +- src/nss-resolve/nss-resolve.c | 2 +- src/resolve/resolved-bus.c | 10 +++++----- src/resolve/resolved-dns-answer.c | 4 ++-- src/resolve/resolved-dns-cache.c | 4 ++-- src/resolve/resolved-dns-packet.c | 2 +- src/resolve/resolved-dns-query.c | 2 +- src/resolve/resolved-dns-server.c | 8 ++++---- src/resolve/resolved-dns-transaction.c | 4 ++-- src/resolve/resolved-etc-hosts.c | 2 +- src/resolve/resolved-resolv-conf.c | 4 ++-- src/shared/bus-util.c | 2 +- src/shared/dns-domain.c | 6 +++--- src/shared/logs-show.c | 2 +- src/shared/uid-range.c | 2 +- src/socket-proxy/socket-proxyd.c | 2 +- src/systemctl/systemctl.c | 8 ++++---- src/test/test-time.c | 2 +- 84 files changed, 222 insertions(+), 222 deletions(-) (limited to 'src') diff --git a/src/activate/activate.c b/src/activate/activate.c index d6e2d07ff2..8ac8dd8e72 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -77,7 +77,7 @@ static int open_sockets(int *epoll_fd, bool accept) { if (r < 0) return r; - count ++; + count++; } } @@ -105,7 +105,7 @@ static int open_sockets(int *epoll_fd, bool accept) { } assert(fd == SD_LISTEN_FDS_START + count); - count ++; + count++; } if (arg_listen) @@ -176,7 +176,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, if (!envp[n_env]) return log_oom(); - n_env ++; + n_env++; } } @@ -191,7 +191,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd, if (!envp[n_env]) return log_oom(); - n_env ++; + n_env++; } if (arg_inetd) { diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index d36c8db3d4..b83f559e7d 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -290,7 +290,7 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) if (r == 0) r = k; } else - count ++; + count++; } for (i = 0; i < count; i++) { diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 2f40ba2b46..b1f2a511f3 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -1004,7 +1004,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; } if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_year ++; + c.tm_year++; c.tm_mon = 0; c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; @@ -1015,7 +1015,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { if (r > 0) c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_mon ++; + c.tm_mon++; c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; @@ -1031,7 +1031,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { if (r > 0) c.tm_min = c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_mday ++; + c.tm_mday++; c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; } @@ -1040,7 +1040,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { if (r > 0) c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_hour ++; + c.tm_hour++; c.tm_min = c.tm_sec = tm_usec = 0; continue; } @@ -1051,7 +1051,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { c.tm_sec /= USEC_PER_SEC; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { - c.tm_min ++; + c.tm_min++; c.tm_sec = tm_usec = 0; continue; } diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index ee35d2a0ec..d6c1228463 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -63,12 +63,12 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra if (!GREEDY_REALLOC(s, allocated, sz+1)) return -ENOMEM; - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) goto finish_force_terminate; else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; + (*p)++; goto finish_force_next; } } else { @@ -81,7 +81,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra } } - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (backslash) { if (!GREEDY_REALLOC(s, allocated, sz+7)) return -ENOMEM; @@ -129,7 +129,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra backslash = false; } else if (quote) { /* inside either single or double quotes */ - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) { if (flags & EXTRACT_RELAX) goto finish_force_terminate; @@ -149,7 +149,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra } } else { - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) goto finish_force_terminate; else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) { @@ -160,11 +160,11 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra break; } else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; + (*p)++; goto finish_force_next; } /* Skip additional coalesced separators. */ - for (;; (*p) ++, c = **p) { + for (;; (*p)++, c = **p) { if (c == 0) goto finish_force_terminate; if (!strchr(separators, c)) diff --git a/src/basic/fileio.c b/src/basic/fileio.c index e43ca6d29e..2c454e8ea2 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -352,7 +352,7 @@ static int parse_env_file_internal( case KEY: if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; n_key = 0; } else if (c == '=') { state = PRE_VALUE; @@ -376,7 +376,7 @@ static int parse_env_file_internal( case PRE_VALUE: if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; key[n_key] = 0; if (value) @@ -416,7 +416,7 @@ static int parse_env_file_internal( case VALUE: if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; key[n_key] = 0; @@ -535,7 +535,7 @@ static int parse_env_file_internal( state = COMMENT_ESCAPE; else if (strchr(newline, c)) { state = PRE_KEY; - line ++; + line++; } break; @@ -908,7 +908,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin /* Back off one char if there's nothing but whitespace and zeros */ if (!*t || isspace(*t)) - t --; + t--; } len = strcspn(t, terminator); diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index d7ad8d41f2..c5bda6c4d6 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -276,8 +276,8 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l if (padding) { /* strip the padding */ while (l > 0 && p[l - 1] == '=' && pad < 7) { - pad ++; - l --; + pad++; + l--; } } @@ -505,7 +505,7 @@ int unbase64char(char c) { if (c == '+') return offset; - offset ++; + offset++; if (c == '/') return offset; @@ -621,9 +621,9 @@ int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { /* strip the padding */ if (l > 0 && p[l - 1] == '=') - l --; + l--; if (l > 0 && p[l - 1] == '=') - l --; + l--; /* a group of four input bytes needs three output bytes, in case of padding we need to add two or three extra bytes */ diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index f900c509a3..a30cc86456 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -123,7 +123,7 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) { return false; dot = true; - n_dots ++; + n_dots++; } else { if (!hostname_valid_char(*p)) return false; diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 3ec8d61236..0037a37f2a 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -249,7 +249,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { } else if (n > 0) q += n; else - q ++; + q++; } if (q > w) { diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index dac2881603..797f00cf71 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -121,7 +121,7 @@ static void bubbleinsert(struct strbuf_node *node, sizeof(struct strbuf_child_entry) * (node->children_count - left)); node->children[left] = new; - node->children_count ++; + node->children_count++; } /* add string, return the index/offset into the buffer */ diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 0bde55f9d5..293a15f9c0 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -477,7 +477,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne } if (k > x) /* last character was wide and went over quota */ - x ++; + x++; for (j = s + old_length; k < new_length && j > i; ) { char32_t c; diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 9bfd8f4f7a..7ca764abeb 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -576,12 +576,12 @@ int parse_timestamp(const char *t, usec_t *usec) { goto from_tm; } else if (streq(t, "yesterday")) { - tm.tm_mday --; + tm.tm_mday--; tm.tm_sec = tm.tm_min = tm.tm_hour = 0; goto from_tm; } else if (streq(t, "tomorrow")) { - tm.tm_mday ++; + tm.tm_mday++; tm.tm_sec = tm.tm_min = tm.tm_hour = 0; goto from_tm; } diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 629db123cd..6eae2b983d 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -241,7 +241,7 @@ char *utf8_escape_non_printable(const char *str) { *(s++) = hexchar((int) *str); str += 1; - len --; + len--; } } } else { diff --git a/src/core/execute.c b/src/core/execute.c index 184c72dbe7..8ede9e9afb 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2237,7 +2237,7 @@ int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) { if (fn[0] == '-') { ignore = true; - fn ++; + fn++; } if (!path_is_absolute(fn)) { diff --git a/src/core/job.c b/src/core/job.c index 97304c4d05..012cf72d1f 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -222,7 +222,7 @@ Job* job_install(Job *j) { *pj = j; j->installed = true; - j->manager->n_installed_jobs ++; + j->manager->n_installed_jobs++; log_unit_debug(j->unit, "Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); @@ -856,7 +856,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { } if (result == JOB_FAILED || result == JOB_INVALID) - j->manager->n_failed_jobs ++; + j->manager->n_failed_jobs++; job_uninstall(j); job_free(j); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 4a65d174b8..3eeb904d7e 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -620,7 +620,7 @@ int config_parse_exec( separate_argv0 = true; else break; - f ++; + f++; } if (isempty(f)) { @@ -668,7 +668,7 @@ int config_parse_exec( /* Check explicitly for an unquoted semicolon as * command separator token. */ if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) { - p ++; + p++; p += strspn(p, WHITESPACE); semicolon = true; break; diff --git a/src/core/main.c b/src/core/main.c index c725a686f1..ac4fd87585 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1073,7 +1073,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching return log_error_errno(r, "Failed to create serialization file: %m"); /* Make sure nothing is really destructed when we shut down */ - m->n_reloading ++; + m->n_reloading++; bus_manager_send_reloading(m, true); fds = fdset_new(); diff --git a/src/core/manager.c b/src/core/manager.c index f36cf5e320..f13e933578 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1137,7 +1137,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { * this is already known, so we increase the counter here * already */ if (serialization) - m->n_reloading ++; + m->n_reloading++; /* First, enumerate what we can from all config files */ dual_timestamp_get(&m->units_load_start_timestamp); @@ -1171,7 +1171,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { if (serialization) { assert(m->n_reloading > 0); - m->n_reloading --; + m->n_reloading--; /* Let's wait for the UnitNew/JobNew messages being * sent, before we notify that the reload is @@ -2231,7 +2231,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { assert(f); assert(fds); - m->n_reloading ++; + m->n_reloading++; fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id); fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); @@ -2301,13 +2301,13 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { r = unit_serialize(u, f, fds, !switching_root); if (r < 0) { - m->n_reloading --; + m->n_reloading--; return r; } } assert(m->n_reloading > 0); - m->n_reloading --; + m->n_reloading--; if (ferror(f)) return -EIO; @@ -2327,7 +2327,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Deserializing state..."); - m->n_reloading ++; + m->n_reloading++; for (;;) { char line[LINE_MAX], *l; @@ -2495,7 +2495,7 @@ finish: r = -EIO; assert(m->n_reloading > 0); - m->n_reloading --; + m->n_reloading--; return r; } @@ -2511,23 +2511,23 @@ int manager_reload(Manager *m) { if (r < 0) return r; - m->n_reloading ++; + m->n_reloading++; bus_manager_send_reloading(m, true); fds = fdset_new(); if (!fds) { - m->n_reloading --; + m->n_reloading--; return -ENOMEM; } r = manager_serialize(m, f, fds, false); if (r < 0) { - m->n_reloading --; + m->n_reloading--; return r; } if (fseeko(f, 0, SEEK_SET) < 0) { - m->n_reloading --; + m->n_reloading--; return -errno; } diff --git a/src/core/service.c b/src/core/service.c index 1f6d821db3..5d58b0b752 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -942,7 +942,7 @@ static void service_set_state(Service *s, ServiceState state) { if (ec && exec_context_may_touch_console(ec)) { Manager *m = UNIT(s)->manager; - m->n_on_console --; + m->n_on_console--; if (m->n_on_console == 0) /* unset no_console_output flag, since the console is free */ m->no_console_output = false; diff --git a/src/core/socket.c b/src/core/socket.c index a1cb54d77a..87586c1c2e 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1979,7 +1979,7 @@ static void socket_enter_running(Socket *s, int cfd) { service = SERVICE(UNIT_DEREF(s->service)); unit_ref_unset(&s->service); - s->n_accepted ++; + s->n_accepted++; UNIT(service)->no_gc = false; @@ -1990,7 +1990,7 @@ static void socket_enter_running(Socket *s, int cfd) { goto fail; cfd = -1; - s->n_connections ++; + s->n_connections++; r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL); if (r < 0) diff --git a/src/core/umount.c b/src/core/umount.c index a458768e7d..b953fcc152 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -472,7 +472,7 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) { major(root_st.st_dev) != 0 && lstat(m->path, &loopback_st) >= 0 && root_st.st_dev == loopback_st.st_rdev) { - n_failed ++; + n_failed++; continue; } @@ -507,7 +507,7 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) { if (k >= 0 && major(root_st.st_dev) != 0 && root_st.st_dev == m->devnum) { - n_failed ++; + n_failed++; continue; } diff --git a/src/core/unit.c b/src/core/unit.c index 3c4f85e744..af38beb0c3 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -364,7 +364,7 @@ void unit_add_to_gc_queue(Unit *u) { LIST_PREPEND(gc_queue, u->manager->gc_queue, u); u->in_gc_queue = true; - u->manager->n_in_gc_queue ++; + u->manager->n_in_gc_queue++; } void unit_add_to_dbus_queue(Unit *u) { @@ -1864,13 +1864,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su ec = unit_get_exec_context(u); if (ec && exec_context_may_touch_console(ec)) { if (UNIT_IS_INACTIVE_OR_FAILED(ns)) { - m->n_on_console --; + m->n_on_console--; if (m->n_on_console == 0) /* unset no_console_output flag, since the console is free */ m->no_console_output = false; } else - m->n_on_console ++; + m->n_on_console++; } } diff --git a/src/coredump/stacktrace.c b/src/coredump/stacktrace.c index 68806992fc..cc4dad9465 100644 --- a/src/coredump/stacktrace.c +++ b/src/coredump/stacktrace.c @@ -91,7 +91,7 @@ static int frame_callback(Dwfl_Frame *frame, void *userdata) { } fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s)\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname)); - c->n_frame ++; + c->n_frame++; return DWARF_CB_OK; } @@ -117,7 +117,7 @@ static int thread_callback(Dwfl_Thread *thread, void *userdata) { if (dwfl_thread_getframes(thread, frame_callback, c) < 0) return DWARF_CB_ABORT; - c->n_thread ++; + c->n_thread++; return DWARF_CB_OK; } diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index 3e57afb997..41b2237d16 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -314,7 +314,7 @@ static int server_init(Server *s, unsigned n_sockets) { f->fd = fd; LIST_PREPEND(fifo, s->fifos, f); f->server = s; - s->n_fifos ++; + s->n_fifos++; } r = bus_connect_system_systemd(&s->bus); diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 44f9a9b44f..35a1e55f9e 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -434,7 +434,7 @@ static int add_raw_socket(RemoteServer *s, int fd) { return r; fd_ = -1; - s->active ++; + s->active++; return 0; } @@ -742,7 +742,7 @@ static int setup_microhttpd_server(RemoteServer *s, goto error; } - s->active ++; + s->active++; return 0; error: diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index fc8f63c9e3..e61b6bc68f 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -52,7 +52,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (pos + r == size) { /* exactly one character short, but we don't need it */ @@ -76,7 +76,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (r + pos == size) { /* exactly one character short, but we don't need it */ @@ -101,7 +101,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (r + pos == size) { /* exactly one character short, but we don't need it */ @@ -126,7 +126,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { /* not enough space */ return pos; - u->entry_state ++; + u->entry_state++; if (r + pos == size) { /* exactly one character short, but we don't need it */ @@ -156,7 +156,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { continue; } - u->entry_state ++; + u->entry_state++; } /* fall through */ case ENTRY_TEXT_FIELD: @@ -206,7 +206,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { pos += len + 1; u->field_pos = len + 1; - u->entry_state ++; + u->entry_state++; } /* fall through */ case ENTRY_BINARY_FIELD_SIZE: { @@ -220,7 +220,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { memcpy(buf + pos, &le64, 8); pos += 8; - u->entry_state ++; + u->entry_state++; continue; } @@ -230,8 +230,8 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { return pos; buf[pos++] = '\n'; - u->entry_state ++; - u->entries_sent ++; + u->entry_state++; + u->entries_sent++; return pos; diff --git a/src/journal/catalog.c b/src/journal/catalog.c index 72c2da10f1..886f6efd8b 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -217,7 +217,7 @@ int catalog_file_lang(const char* filename, char **lang) { beg = end - 1; while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32) - beg --; + beg--; if (*beg != '.' || end <= beg + 1) return 0; diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index f5e2952c99..7abdceb690 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -2170,7 +2170,7 @@ static int generic_array_bisect_plus_one( goto found; if (r > 0 && idx) - (*idx) ++; + (*idx)++; return r; diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c index 05e97620ae..f09dc66e03 100644 --- a/src/journal/journal-vacuum.c +++ b/src/journal/journal-vacuum.c @@ -239,13 +239,13 @@ int journal_directory_vacuum( /* Vacuum corrupted files */ if (q < 1 + 16 + 1 + 16 + 8 + 1) { - n_active_files ++; + n_active_files++; continue; } if (de->d_name[q-1-8-16-1] != '-' || de->d_name[q-1-8-16-1-16-1] != '@') { - n_active_files ++; + n_active_files++; continue; } @@ -256,7 +256,7 @@ int journal_directory_vacuum( } if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { - n_active_files ++; + n_active_files++; continue; } @@ -302,7 +302,7 @@ int journal_directory_vacuum( list[n_list].realtime = realtime; list[n_list].seqnum_id = seqnum_id; list[n_list].have_seqnum = have_seqnum; - n_list ++; + n_list++; p = NULL; sum += size; diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index b968e89bb8..7a35776eaa 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -894,7 +894,7 @@ int journal_file_verify( goto fail; } - n_objects ++; + n_objects++; r = journal_file_object_verify(f, p, o); if (r < 0) { @@ -991,7 +991,7 @@ int journal_file_verify( entry_realtime = le64toh(o->entry.realtime); entry_realtime_set = true; - n_entries ++; + n_entries++; break; case OBJECT_DATA_HASH_TABLE: @@ -1131,11 +1131,11 @@ int journal_file_verify( last_epoch = le64toh(o->tag.epoch); - n_tags ++; + n_tags++; break; default: - n_weird ++; + n_weird++; } if (p == le64toh(f->header->tail_object_offset)) { diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 273242bea6..cab46d09ef 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1363,7 +1363,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -1383,7 +1383,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -1408,7 +1408,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -1428,7 +1428,7 @@ static int add_units(sd_journal *j) { r = sd_journal_add_disjunction(j); if (r < 0) return r; - count ++; + count++; } } @@ -2181,7 +2181,7 @@ int main(int argc, char *argv[]) { SD_JOURNAL_FOREACH_FIELD(j, field) { printf("%s\n", field); - n_shown ++; + n_shown++; } r = 0; @@ -2273,7 +2273,7 @@ int main(int argc, char *argv[]) { else printf("%.*s\n", (int) size, (const char*) data); - n_shown ++; + n_shown++; } r = 0; diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index b2eb8a33ef..a433c91c54 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -63,7 +63,7 @@ static int map_simple_field(const char *field, const char **p, struct iovec **io (*iov)[*n_iov].iov_base = c; (*iov)[*n_iov].iov_len = l; - (*n_iov) ++; + (*n_iov)++; *p = e; c = NULL; @@ -142,7 +142,7 @@ static int map_string_field_internal(const char *field, const char **p, struct i (*iov)[*n_iov].iov_base = c; (*iov)[*n_iov].iov_len = l; - (*n_iov) ++; + (*n_iov)++; *p = e; c = NULL; @@ -200,7 +200,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec ** } strcpy(t, "="); - e ++; + e++; r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov); if (r < 0) diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index eb1ac90e98..f64abdd431 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -201,7 +201,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) { if (*k != ' ') break; - k ++, l --; + k++, l--; e = memchr(k, '\n', l); if (!e) diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c index 6f6a90fe4e..fce799a6ce 100644 --- a/src/journal/journald-rate-limit.c +++ b/src/journal/journald-rate-limit.c @@ -104,7 +104,7 @@ static void journal_rate_limit_group_free(JournalRateLimitGroup *g) { LIST_REMOVE(lru, g->parent->lru, g); LIST_REMOVE(bucket, g->parent->buckets[g->hash % BUCKETS_MAX], g); - g->parent->n_groups --; + g->parent->n_groups--; } free(g->id); @@ -168,7 +168,7 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, LIST_PREPEND(lru, r->lru, g); if (!g->lru_next) r->lru_tail = g; - r->n_groups ++; + r->n_groups++; g->parent = r; return g; diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 6e8b405b53..59352bcb3f 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -96,7 +96,7 @@ void stdout_stream_free(StdoutStream *s) { if (s->server) { assert(s->server->n_stdout_streams > 0); - s->server->n_stdout_streams --; + s->server->n_stdout_streams--; LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); if (s->in_notify_queue) @@ -511,7 +511,7 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { stream->server = s; LIST_PREPEND(stdout_stream, s->stdout_streams, stream); - s->n_stdout_streams ++; + s->n_stdout_streams++; if (ret) *ret = stream; diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 9c0ce8ccbf..6bcd9b6ac8 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -107,7 +107,7 @@ MMapCache* mmap_cache_ref(MMapCache *m) { assert(m); assert(m->n_ref > 0); - m->n_ref ++; + m->n_ref++; return m; } @@ -361,7 +361,7 @@ MMapCache* mmap_cache_unref(MMapCache *m) { assert(m->n_ref > 0); - m->n_ref --; + m->n_ref--; if (m->n_ref == 0) mmap_cache_free(m); @@ -598,14 +598,14 @@ int mmap_cache_get( /* Check whether the current context is the right one already */ r = try_context(m, fd, prot, context, keep_always, offset, size, ret); if (r != 0) { - m->n_hit ++; + m->n_hit++; return r; } /* Search for a matching mmap */ r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret); if (r != 0) { - m->n_hit ++; + m->n_hit++; return r; } diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 6ff1c67f5f..3ba4981cd4 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1266,7 +1266,7 @@ static int add_any_file(sd_journal *j, const char *path) { check_network(j, f->fd); - j->current_invalidate_counter ++; + j->current_invalidate_counter++; return 0; @@ -1345,7 +1345,7 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { (void) journal_file_close(f); - j->current_invalidate_counter ++; + j->current_invalidate_counter++; } static int dirname_is_machine_id(const char *fn) { @@ -1410,7 +1410,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) } path = NULL; /* avoid freeing in cleanup */ - j->current_invalidate_counter ++; + j->current_invalidate_counter++; log_debug("Directory %s added.", m->path); @@ -1495,7 +1495,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { goto fail; } - j->current_invalidate_counter ++; + j->current_invalidate_counter++; log_debug("Root directory %s added.", m->path); @@ -2078,7 +2078,7 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t if (r < 0) return r; - j->current_field ++; + j->current_field++; return 1; } diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c index e5e9d9dcb3..354c2c3c00 100644 --- a/src/journal/test-journal-enum.c +++ b/src/journal/test-journal-enum.c @@ -44,7 +44,7 @@ int main(int argc, char *argv[]) { printf("%.*s\n", (int) l, (char*) d); - n ++; + n++; if (n >= 10) break; } diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 531b80eb08..c105196334 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -34,7 +34,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, if (code != SD_DHCP_OPTION_END) /* always make sure there is space for an END option */ - size --; + size--; switch (code) { diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index 8d75d49691..8be774061d 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -66,7 +66,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) { /* wrap around in one's complement */ sum++; - buf_64 ++; + buf_64++; } if (len % sizeof(uint64_t)) { diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index fdafcd84d8..abf3b157d0 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -375,7 +375,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { if (r <= 0) continue; - size ++; + size++; } *ret = addresses; diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 7c81e7a25d..5964a01c4f 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -198,7 +198,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { else if (type == SD_BUS_TYPE_DICT_ENTRY) fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents); - level ++; + level++; continue; } diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index c2e913f62a..542c37e41b 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1198,7 +1198,7 @@ struct bus_body_part *message_append_part(sd_bus_message *m) { part->memfd = -1; m->body_end = part; - m->n_body_parts ++; + m->n_body_parts++; return part; } @@ -1643,7 +1643,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void } if (type == SD_BUS_TYPE_UNIX_FD) - m->n_fds ++; + m->n_fds++; if (c->enclosing != SD_BUS_TYPE_ARRAY) c->index++; @@ -2387,9 +2387,9 @@ int bus_message_append_ap( t = types; if (n_array != (unsigned) -1) - n_array --; + n_array--; else { - types ++; + types++; n_struct--; } @@ -3866,7 +3866,7 @@ static int build_struct_offsets( if (r < 0) return r; if (r == 0 && p[n] != 0) /* except the last item */ - n_variable ++; + n_variable++; n_total++; p += n; @@ -4466,9 +4466,9 @@ static int message_read_ap( t = types; if (n_array != (unsigned) -1) - n_array --; + n_array--; else { - types ++; + types++; n_struct--; } diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 1f285ae8a6..3c189b30ec 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -337,7 +337,7 @@ static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, if (cap == 0) cap = CAP_SYS_ADMIN; else - cap --; + cap--; r = sd_bus_query_sender_privilege(m, cap); if (r < 0) diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index a8c74011bf..8e9074c7df 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -206,7 +206,7 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) { assert(slot->n_ref > 0); if (slot->n_ref > 1) { - slot->n_ref --; + slot->n_ref--; return NULL; } diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 13d0aef4b5..f1e2a06050 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -60,7 +60,7 @@ static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) { i->iov_base = NULL; i->iov_len = 0; - (*idx) ++; + (*idx)++; } } diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index bdbf7d4a85..1f436fe560 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -129,7 +129,7 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) { assert(track->n_ref > 0); if (track->n_ref > 1) { - track->n_ref --; + track->n_ref--; return NULL; } diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index c6f626d8aa..cc15afeb1c 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -530,7 +530,7 @@ static void skip_address_key(const char **p) { *p += strcspn(*p, ","); if (**p == ',') - (*p) ++; + (*p)++; } static int parse_unix_address(sd_bus *b, const char **p, char **guid) { @@ -695,7 +695,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { goto fail; } - (*p) ++; + (*p)++; if (ul >= n_argv) { if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) { @@ -1668,7 +1668,7 @@ static int dispatch_wqueue(sd_bus *bus) { * it got full, then all bets are off * anyway. */ - bus->wqueue_size --; + bus->wqueue_size--; sd_bus_message_unref(bus->wqueue[0]); memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size); bus->windex = 0; @@ -1717,7 +1717,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd /* Dispatch a queued message */ *m = bus->rqueue[0]; - bus->rqueue_size --; + bus->rqueue_size--; memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size); return 1; } @@ -1809,7 +1809,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1)) return -ENOMEM; - bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m); + bus->wqueue[bus->wqueue_size++] = sd_bus_message_ref(m); } finish: @@ -2257,7 +2257,7 @@ static int process_timeout(sd_bus *bus) { slot = container_of(c, sd_bus_slot, reply_callback); - bus->iteration_counter ++; + bus->iteration_counter++; bus->current_message = m; bus->current_slot = sd_bus_slot_ref(slot); diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 46d18abd29..66a3874f10 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -146,7 +146,7 @@ static void dump_mapping_table(void) { } printf("%s -> %i/%s\n", strna(m->name), m->code, strna(errno_to_name(m->code))); - m ++; + m++; } printf("---------------------------\n"); } diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index f2af3ab3ae..9082d377f4 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -890,7 +890,7 @@ void device_cleanup_tags(sd_device *device) { set_free_free(device->tags); device->tags = NULL; device->property_tags_outdated = true; - device->tags_generation ++; + device->tags_generation++; } void device_cleanup_devlinks(sd_device *device) { @@ -899,7 +899,7 @@ void device_cleanup_devlinks(sd_device *device) { set_free_free(device->devlinks); device->devlinks = NULL; device->property_devlinks_outdated = true; - device->devlinks_generation ++; + device->devlinks_generation++; } void device_remove_tag(sd_device *device, const char *tag) { @@ -908,7 +908,7 @@ void device_remove_tag(sd_device *device, const char *tag) { free(set_remove(device->tags, tag)); device->property_tags_outdated = true; - device->tags_generation ++; + device->tags_generation++; } static int device_tag(sd_device *device, const char *tag, bool add) { diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index fdd8c05e9c..8657e61cd9 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -136,7 +136,7 @@ int device_add_property_aux(sd_device *device, const char *_key, const char *_va } if (!db) { - device->properties_generation ++; + device->properties_generation++; device->properties_buf_outdated = true; } @@ -309,7 +309,7 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s if (name[len] == '/') name[len] = '!'; - len ++; + len++; } syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name); @@ -669,7 +669,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { return -EINVAL; sysname[0] = '\0'; - sysname ++; + sysname++; return sd_device_new_from_subsystem_sysname(ret, subsys, sysname); } @@ -971,7 +971,7 @@ static int device_set_sysname(sd_device *device) { pos = strrchr(device->devpath, '/'); if (!pos) return -EINVAL; - pos ++; + pos++; /* devpath is not a root directory */ if (*pos == '\0' || pos <= device->devpath) @@ -986,7 +986,7 @@ static int device_set_sysname(sd_device *device) { if (sysname[len] == '!') sysname[len] = '/'; - len ++; + len++; } /* trailing number */ @@ -1066,7 +1066,7 @@ int device_add_tag(sd_device *device, const char *tag) { if (r < 0) return r; - device->tags_generation ++; + device->tags_generation++; device->property_tags_outdated = true; return 0; @@ -1086,7 +1086,7 @@ int device_add_devlink(sd_device *device, const char *devlink) { if (r < 0) return r; - device->devlinks_generation ++; + device->devlinks_generation++; device->property_devlinks_outdated = true; return 0; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 2b46a1ff06..841358ed03 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -951,7 +951,7 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t sd_event_ref(e); LIST_PREPEND(sources, e->sources, s); - e->n_sources ++; + e->n_sources++; return s; } @@ -1235,7 +1235,7 @@ _public_ int sd_event_add_child( return r; } - e->n_enabled_child_sources ++; + e->n_enabled_child_sources++; r = event_make_signal_data(e, SIGCHLD, NULL); if (r < 0) { diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index daea4126f8..fd31588b8f 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -291,7 +291,7 @@ static int n_rtqueue = 0; static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { last_rtqueue_sigval = si->ssi_int; - n_rtqueue ++; + n_rtqueue++; return 0; } diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 3a866fdafe..2ce50edc7e 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -34,7 +34,7 @@ #include "util.h" #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL) -#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; +#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK) #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK) @@ -467,7 +467,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type if (r < 0) return r; - m->containers[m->n_containers ++].offset = r; + m->containers[m->n_containers++].offset = r; return 0; } @@ -498,7 +498,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor if (r < 0) return r; - m->containers[m->n_containers ++].offset = r; + m->containers[m->n_containers++].offset = r; return 0; } @@ -510,7 +510,7 @@ int sd_netlink_message_close_container(sd_netlink_message *m) { assert_return(m->n_containers > 0, -EINVAL); m->containers[m->n_containers].type_system = NULL; - m->n_containers --; + m->n_containers--; return 0; } @@ -842,7 +842,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ else size = (size_t)r; - m->n_containers ++; + m->n_containers++; r = netlink_container_parse(m, &m->containers[m->n_containers], @@ -850,7 +850,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ container, size); if (r < 0) { - m->n_containers --; + m->n_containers--; return r; } @@ -867,7 +867,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) { m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes); m->containers[m->n_containers].type_system = NULL; - m->n_containers --; + m->n_containers--; return 0; } diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 590fc53fc7..c165fa3359 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -82,7 +82,7 @@ static int broadcast_groups_get(sd_netlink *nl) { return r; for (i = 0; i < len; i++) { - for (j = 0; j < sizeof(uint32_t) * 8; j ++) { + for (j = 0; j < sizeof(uint32_t) * 8; j++) { uint32_t offset; unsigned group; @@ -168,7 +168,7 @@ int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) { n_ref = broadcast_group_get_ref(nl, group); - n_ref ++; + n_ref++; r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL); if (r < 0) @@ -216,7 +216,7 @@ int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) { assert(n_ref > 0); - n_ref --; + n_ref--; r = broadcast_group_set_ref(nl, group, n_ref); if (r < 0) @@ -444,14 +444,14 @@ int socket_read_message(sd_netlink *rtnl) { if (r < 0) return r; - rtnl->rqueue[rtnl->rqueue_size ++] = first; + rtnl->rqueue[rtnl->rqueue_size++] = first; first = NULL; if (multi_part && (i < rtnl->rqueue_partial_size)) { /* remove the message form the partial read queue */ memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1, sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1)); - rtnl->rqueue_partial_size --; + rtnl->rqueue_partial_size--; } return 1; @@ -465,7 +465,7 @@ int socket_read_message(sd_netlink *rtnl) { if (r < 0) return r; - rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first; + rtnl->rqueue_partial[rtnl->rqueue_partial_size++] = first; } first = NULL; diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index f5c2b33f46..91701405a5 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -279,7 +279,7 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) { /* Dispatch a queued message */ *message = rtnl->rqueue[0]; - rtnl->rqueue_size --; + rtnl->rqueue_size--; memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size); return 1; diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index de5e0ffc8f..f9b6787187 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -234,7 +234,7 @@ static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) int *counter = userdata; int r; - (*counter) --; + (*counter)--; r = sd_netlink_message_get_errno(m); @@ -276,10 +276,10 @@ static void test_pipe(int ifindex) { assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0); - counter ++; + counter++; assert_se(sd_netlink_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0); - counter ++; + counter++; assert_se(sd_netlink_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0); while (counter > 0) { diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 910e75441f..37585048b8 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -447,7 +447,7 @@ static int start_threads(sd_resolve *resolve, unsigned extra) { if (r != 0) return -r; - resolve->n_valid_workers ++; + resolve->n_valid_workers++; } return 0; @@ -657,7 +657,7 @@ static int complete_query(sd_resolve *resolve, sd_resolve_query *q) { assert(q->resolve == resolve); q->done = true; - resolve->n_done ++; + resolve->n_done++; resolve->current = sd_resolve_query_ref(q); diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c index e416e178b4..3b8abfb260 100644 --- a/src/libudev/libudev-enumerate.c +++ b/src/libudev/libudev-enumerate.c @@ -112,7 +112,7 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) { **/ _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) { if (udev_enumerate) - udev_enumerate->refcount ++; + udev_enumerate->refcount++; return udev_enumerate; } diff --git a/src/locale/localed.c b/src/locale/localed.c index f0fe59cc67..cc86c61edb 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -542,7 +542,7 @@ static int read_next_mapping(const char* filename, return 0; } - (*n) ++; + (*n)++; l = strstrip(line); if (l[0] == 0 || l[0] == '#') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 4853139321..908ae1c2bb 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -180,7 +180,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { if (l > max_service) max_service = l; - n_machines ++; + n_machines++; } if (r < 0) return bus_log_parse_error(r); @@ -2236,7 +2236,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { if (id > max_id) max_id = id; - n_transfers ++; + n_transfers++; } if (r < 0) return bus_log_parse_error(r); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 03c28bbcb6..68998eabf2 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -34,7 +34,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, assert(link); assert(link->dhcp4_messages > 0); - link->dhcp4_messages --; + link->dhcp4_messages--; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -96,7 +96,7 @@ static int link_set_dhcp_routes(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); - link->dhcp4_messages ++; + link->dhcp4_messages++; route->family = AF_INET; route->gw.in = gateway; @@ -110,7 +110,7 @@ static int link_set_dhcp_routes(Link *link) { return r; } - link->dhcp4_messages ++; + link->dhcp4_messages++; } n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes); @@ -137,7 +137,7 @@ static int link_set_dhcp_routes(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); - link->dhcp4_messages ++; + link->dhcp4_messages++; } return 0; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 85a439b2a5..a4652ba9c9 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -473,7 +473,7 @@ Link *link_unref(Link *link) { assert(link->n_ref > 0); - link->n_ref --; + link->n_ref--; if (link->n_ref > 0) return NULL; @@ -489,7 +489,7 @@ Link *link_ref(Link *link) { assert(link->n_ref > 0); - link->n_ref ++; + link->n_ref++; return link; } @@ -677,7 +677,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED, LINK_STATE_LINGER)); - link->link_messages --; + link->link_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -713,7 +713,7 @@ static int link_enter_set_routes(Link *link) { return r; } - link->link_messages ++; + link->link_messages++; } if (link->link_messages == 0) { @@ -755,7 +755,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES, LINK_STATE_FAILED, LINK_STATE_LINGER)); - link->link_messages --; + link->link_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -882,7 +882,7 @@ static int link_enter_set_addresses(Link *link) { return r; } - link->link_messages ++; + link->link_messages++; } /* now that we can figure out a default address for the dhcp server, @@ -1852,7 +1852,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us assert(link); assert(link->network); - link->enslaving --; + link->enslaving--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -1908,7 +1908,7 @@ static int link_enter_join_netdev(Link *link) { return r; } - link->enslaving ++; + link->enslaving++; } if (link->network->bridge) { @@ -1929,7 +1929,7 @@ static int link_enter_join_netdev(Link *link) { return r; } - link->enslaving ++; + link->enslaving++; } HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { @@ -1951,7 +1951,7 @@ static int link_enter_join_netdev(Link *link) { return r; } - link->enslaving ++; + link->enslaving++; } return 0; @@ -2440,7 +2440,7 @@ network_file_fail: continue; } - *prefixlen_str ++ = '\0'; + *prefixlen_str++ = '\0'; r = sscanf(prefixlen_str, "%hhu", &prefixlen); if (r != 1) { @@ -2487,7 +2487,7 @@ network_file_fail: continue; } - *prefixlen_str ++ = '\0'; + *prefixlen_str++ = '\0'; r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime); if (r != 5) { diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 3e8932e160..4577292e44 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -33,7 +33,7 @@ static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void * assert(link); assert(link->ndisc_messages > 0); - link->ndisc_messages --; + link->ndisc_messages--; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { @@ -99,7 +99,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr return; } - link->ndisc_messages ++; + link->ndisc_messages++; } static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) { @@ -137,7 +137,7 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre return; } - link->ndisc_messages ++; + link->ndisc_messages++; } static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { @@ -187,7 +187,7 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a return; } - link->ndisc_messages ++; + link->ndisc_messages++; } static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index 106f15fabc..6b9cbcded6 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -375,7 +375,7 @@ int config_parse_arp_ip_target_address(const char *unit, } LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer); - b->n_arp_ip_targets ++; + b->n_arp_ip_targets++; buffer = NULL; } diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index fcb1efaa74..74a0ae865b 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -232,7 +232,7 @@ int setup_veth_extra( if (r < 0) return r; - idx ++; + idx++; } return 0; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 5a68fec603..ce3695eaf6 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2560,7 +2560,7 @@ static int inner_child( envp[n_env] = strv_find_prefix(environ, "TERM="); if (envp[n_env]) - 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) || diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 1582d702f8..8d57b26cbc 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -66,7 +66,7 @@ static int count_addresses(sd_bus_message *m, int af, unsigned *ret) { if (af != AF_UNSPEC && family != af) continue; - c ++; + c++; } if (r < 0) return r; diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index 69c0d9bdc1..0de6bd2241 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -90,7 +90,7 @@ static int count_addresses(sd_bus_message *m, int af, const char **canonical) { if (af != AF_UNSPEC && family != af) continue; - c ++; + c++; } if (r < 0) return r; diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index a138be2421..214810362d 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -188,7 +188,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { if (!canonical) canonical = dns_resource_record_ref(rr); - added ++; + added++; } if (added <= 0) { @@ -418,7 +418,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (r < 0) goto finish; - added ++; + added++; } if (added <= 0) { @@ -587,7 +587,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { if (r < 0) goto finish; - added ++; + added++; } if (added <= 0) { @@ -1094,9 +1094,9 @@ static void bus_method_resolve_service_complete(DnsQuery *q) { } if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { - q->block_all_complete ++; + q->block_all_complete++; r = resolve_service_hostname(q, rr, ifindex); - q->block_all_complete --; + q->block_all_complete--; if (r < 0) goto finish; diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index c08f7a7edd..5d7b4b4b5c 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -538,7 +538,7 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) { dns_resource_record_unref((*a)->items[i].rr); memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); - (*a)->n_rrs --; + (*a)->n_rrs--; continue; } else @@ -624,7 +624,7 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) { dns_resource_record_unref((*a)->items[i].rr); memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); - (*a)->n_rrs --; + (*a)->n_rrs--; continue; } else diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index fb957db9ef..77c42d7aad 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -640,7 +640,7 @@ int dns_cache_put( cache_keys = dns_answer_size(answer); if (key) - cache_keys ++; + cache_keys++; /* Make some space for our new entries */ dns_cache_make_space(c, cache_keys); @@ -987,7 +987,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { if (r < 0) return r; - ancount ++; + ancount++; } } diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 2e41dae656..64913da573 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -1469,7 +1469,7 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta return r; } - bit ++; + bit++; bitmask >>= 1; } } diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index a7496aa586..a46674f6fe 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -927,7 +927,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) assert(q); - q->n_cname_redirects ++; + q->n_cname_redirects++; if (q->n_cname_redirects > CNAME_MAX) return -ELOOP; diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 27342a0e04..49d488cec5 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -120,7 +120,7 @@ DnsServer* dns_server_ref(DnsServer *s) { return NULL; assert(s->n_ref > 0); - s->n_ref ++; + s->n_ref++; return s; } @@ -130,7 +130,7 @@ DnsServer* dns_server_unref(DnsServer *s) { return NULL; assert(s->n_ref > 0); - s->n_ref --; + s->n_ref--; if (s->n_ref > 0) return NULL; @@ -290,9 +290,9 @@ void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel le if (s->possible_feature_level == level) { if (protocol == IPPROTO_UDP) - s->n_failed_udp ++; + s->n_failed_udp++; else if (protocol == IPPROTO_TCP) - s->n_failed_tcp ++; + s->n_failed_tcp++; } if (s->resend_timeout > usec) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 3443f71976..57f9455131 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -209,7 +209,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) LIST_PREPEND(transactions_by_scope, s->transactions, t); t->scope = s; - s->manager->n_transactions_total ++; + s->manager->n_transactions_total++; if (ret) *ret = t; @@ -1375,7 +1375,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { other->state = DNS_TRANSACTION_PENDING; other->next_attempt_after = ts; - qdcount ++; + qdcount++; if (dns_key_is_shared(other->key)) add_known_answers = true; diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c index 6ccbdca20e..40d650949d 100644 --- a/src/resolve/resolved-etc-hosts.c +++ b/src/resolve/resolved-etc-hosts.c @@ -301,7 +301,7 @@ int manager_etc_hosts_read(Manager *m) { FOREACH_LINE(line, f, return log_error_errno(errno, "Failed to read /etc/hosts: %m")) { char *l; - nr ++; + nr++; l = strstrip(line); if (isempty(l)) diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index 065427b690..ff03acc772 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -158,7 +158,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { if (*count == MAXNS) fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f); - (*count) ++; + (*count)++; fprintf(f, "nameserver %s\n", s->server_string); } @@ -184,7 +184,7 @@ static void write_resolv_conf_search( } (*length) += strlen(domain); - (*count) ++; + (*count)++; fputc(' ', f); fputs(domain, f); diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index c87eaf63d8..0776311837 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1412,7 +1412,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return bus_log_create_error(r); field = strndupa(assignment, eq - assignment); - eq ++; + eq++; if (streq(field, "CPUQuota")) { diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 0fc2a31f04..835557c6b2 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -180,7 +180,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha unsigned slashes = 0; for (y = terminal - 1; y >= name && *y == '\\'; y--) - slashes ++; + slashes++; if (slashes % 2 == 0) { /* The '.' was not escaped */ @@ -192,7 +192,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha } } - terminal --; + terminal--; } r = dns_label_unescape(&name, dest, sz); @@ -1172,7 +1172,7 @@ int dns_name_skip(const char *a, unsigned n_labels, const char **ret) { assert(a); assert(ret); - for (; n_labels > 0; n_labels --) { + for (; n_labels > 0; n_labels--) { r = dns_name_parent(&a); if (r < 0) return r; diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 5eb3bd35c7..e2d2931c51 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -997,7 +997,7 @@ static int show_journal(FILE *f, continue; } - line ++; + line++; maybe_print_begin_newline(f, &flags); r = output_journal(f, j, mode, n_columns, flags, ellipsized); diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c index eb251492c3..b6ec474390 100644 --- a/src/shared/uid-range.c +++ b/src/shared/uid-range.c @@ -54,7 +54,7 @@ static void uid_range_coalesce(UidRange **p, unsigned *n) { if (*n > j+1) memmove(y, y+1, sizeof(UidRange) * (*n - j -1)); - (*n) --; + (*n)--; j--; } } diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index 99d4b62139..1157a0c72e 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -427,7 +427,7 @@ static int resolve_remote(Connection *c) { service = strrchr(arg_remote_host, ':'); if (service) { node = strndupa(arg_remote_host, service - arg_remote_host); - service ++; + service++; } else { node = arg_remote_host; service = "80"; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c75d12c136..7774506a1e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1436,7 +1436,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { }; if (output_show_unit_file(&units[c], strv_skip(argv, 1))) - c ++; + c++; } if (r < 0) @@ -6710,11 +6710,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_FORCE: - arg_force ++; + arg_force++; break; case 'f': - arg_force ++; + arg_force++; break; case ARG_NO_RELOAD: @@ -7180,7 +7180,7 @@ static int telinit_parse_argv(int argc, char *argv[]) { arg_action = table[i].to; - optind ++; + optind++; return 1; } diff --git a/src/test/test-time.c b/src/test/test-time.c index 9062c3f3c1..ee7d55c5ab 100644 --- a/src/test/test-time.c +++ b/src/test/test-time.c @@ -220,7 +220,7 @@ int main(int argc, char *argv[]) { /* Ensure TIME_T_MAX works correctly */ x = (uintmax_t) TIME_T_MAX; - x ++; + x++; assert((time_t) x < 0); return 0; -- cgit v1.2.3-54-g00ecf From 232c84b2d22f2d96982b3c0390d29498bb430835 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 12 Feb 2016 15:03:51 +0100 Subject: Remove systemd-bootchart This commit rips out systemd-bootchart. It will be given a new home, outside of the systemd repository. The code itself isn't actually specific to systemd and can be used without systemd even, so let's put it somewhere else. --- .gitignore | 1 - Makefile-man.am | 14 - Makefile.am | 26 - README | 4 - TODO | 6 - configure.ac | 9 - man/bootchart.conf.xml | 172 ----- man/systemd-bootchart.xml | 323 --------- src/bootchart/Makefile | 1 - src/bootchart/bootchart.c | 531 -------------- src/bootchart/bootchart.conf | 26 - src/bootchart/bootchart.h | 119 ---- src/bootchart/store.c | 555 --------------- src/bootchart/store.h | 36 - src/bootchart/svg.c | 1375 ------------------------------------ src/bootchart/svg.h | 35 - src/systemd/sd-messages.h | 2 - tools/make-directive-index.py | 9 - units/.gitignore | 1 - units/systemd-bootchart.service.in | 20 - 20 files changed, 3265 deletions(-) delete mode 100644 man/bootchart.conf.xml delete mode 100644 man/systemd-bootchart.xml delete mode 120000 src/bootchart/Makefile delete mode 100644 src/bootchart/bootchart.c delete mode 100644 src/bootchart/bootchart.conf delete mode 100644 src/bootchart/bootchart.h delete mode 100644 src/bootchart/store.c delete mode 100644 src/bootchart/store.h delete mode 100644 src/bootchart/svg.c delete mode 100644 src/bootchart/svg.h delete mode 100644 units/systemd-bootchart.service.in (limited to 'src') diff --git a/.gitignore b/.gitignore index 2324e6e478..eab660e859 100644 --- a/.gitignore +++ b/.gitignore @@ -53,7 +53,6 @@ /systemd-ask-password /systemd-backlight /systemd-binfmt -/systemd-bootchart /systemd-bootx64.efi /systemd-cat /systemd-cgls diff --git a/Makefile-man.am b/Makefile-man.am index 8b68bf37cc..b2af8982cd 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -1843,18 +1843,6 @@ man/systemd-binfmt.html: man/systemd-binfmt.service.html endif -if ENABLE_BOOTCHART -MANPAGES += \ - man/bootchart.conf.5 \ - man/systemd-bootchart.1 -MANPAGES_ALIAS += \ - man/bootchart.conf.d.5 -man/bootchart.conf.d.5: man/bootchart.conf.5 -man/bootchart.conf.d.html: man/bootchart.conf.html - $(html-alias) - -endif - if ENABLE_COREDUMP MANPAGES += \ man/coredump.conf.5 \ @@ -2449,7 +2437,6 @@ endif EXTRA_DIST += \ man/binfmt.d.xml \ - man/bootchart.conf.xml \ man/bootctl.xml \ man/bootup.xml \ man/busctl.xml \ @@ -2572,7 +2559,6 @@ EXTRA_DIST += \ man/systemd-ask-password.xml \ man/systemd-backlight@.service.xml \ man/systemd-binfmt.service.xml \ - man/systemd-bootchart.xml \ man/systemd-cat.xml \ man/systemd-cgls.xml \ man/systemd-cgtop.xml \ diff --git a/Makefile.am b/Makefile.am index a0043c2e4a..4c58522d0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4415,32 +4415,6 @@ EXTRA_DIST += \ src/vconsole/90-vconsole.rules.in \ units/systemd-vconsole-setup.service.in -# ------------------------------------------------------------------------------ -if ENABLE_BOOTCHART -systemd_bootchart_SOURCES = \ - src/bootchart/bootchart.c \ - src/bootchart/bootchart.h \ - src/bootchart/store.c \ - src/bootchart/store.h \ - src/bootchart/svg.c \ - src/bootchart/svg.h - -systemd_bootchart_LDADD = \ - libshared.la - -rootlibexec_PROGRAMS += \ - systemd-bootchart - -dist_pkgsysconf_DATA += \ - src/bootchart/bootchart.conf - -nodist_systemunit_DATA += \ - units/systemd-bootchart.service -endif - -EXTRA_DIST += \ - units/systemd-bootchart.service.in - # ------------------------------------------------------------------------------ if ENABLE_QUOTACHECK rootlibexec_PROGRAMS += \ diff --git a/README b/README index 41fb07a298..3bdf4107cf 100644 --- a/README +++ b/README @@ -88,10 +88,6 @@ REQUIREMENTS: Required for CPUQuota= in resource control unit settings CONFIG_CFS_BANDWIDTH - For systemd-bootchart, several proc debug interfaces are required: - CONFIG_SCHEDSTATS - CONFIG_SCHED_DEBUG - For UEFI systems: CONFIG_EFIVAR_FS CONFIG_EFI_PARTITION diff --git a/TODO b/TODO index 038e810955..08b74083d3 100644 --- a/TODO +++ b/TODO @@ -754,12 +754,6 @@ Features: works with ^C - add documentation to systemd.daemon -* bootchart: - - plot per-process IO utilization - - group processes based on service association (cgroups) - - document initcall_debug - - kernel cmdline "bootchart" option for simplicity? - * udev-link-config: - Make sure ID_PATH is always exported and complete for network devices where possible, so we can safely rely diff --git a/configure.ac b/configure.ac index 269aceddcc..e55d1a02a6 100644 --- a/configure.ac +++ b/configure.ac @@ -938,14 +938,6 @@ if test "x$enable_vconsole" != "xno"; then fi AM_CONDITIONAL(ENABLE_VCONSOLE, [test "$have_vconsole" = "yes"]) -# ------------------------------------------------------------------------------ -have_bootchart=no -AC_ARG_ENABLE(bootchart, AS_HELP_STRING([--disable-bootchart], [disable bootchart tool])) -if test "x$enable_bootchart" != "xno"; then - have_bootchart=yes -fi -AM_CONDITIONAL(ENABLE_BOOTCHART, [test "$have_bootchart" = "yes"]) - # ------------------------------------------------------------------------------ have_quotacheck=no AC_ARG_ENABLE(quotacheck, AS_HELP_STRING([--disable-quotacheck], [disable quotacheck tools])) @@ -1571,7 +1563,6 @@ AC_MSG_RESULT([ ELFUTILS: ${have_elfutils} binfmt: ${have_binfmt} vconsole: ${have_vconsole} - bootchart: ${have_bootchart} quotacheck: ${have_quotacheck} tmpfiles: ${have_tmpfiles} sysusers: ${have_sysusers} diff --git a/man/bootchart.conf.xml b/man/bootchart.conf.xml deleted file mode 100644 index f6ac7e6ae2..0000000000 --- a/man/bootchart.conf.xml +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - - - bootchart.conf - systemd - - - - Developer - Auke - Kok - auke-jan.h.kok@intel.com - - - - - - bootchart.conf - 5 - - - - bootchart.conf - bootchart.conf.d - Boot performance analysis graphing tool configuration files - - - - /etc/systemd/bootchart.conf - /etc/systemd/bootchart.conf.d/*.conf - /run/systemd/bootchart.conf.d/*.conf - /usr/lib/systemd/bootchart.conf.d/*.conf - - - - Description - - When starting, systemd-bootchart will read the configuration - file /etc/systemd/bootchart.conf, followed by - the files in the bootchart.conf.d - directories. These configuration files determine logging - parameters and graph output. - - - - - - Options - - - - - Samples=500 - Configure the amount of samples to record in - total before bootchart exits. Each sample will record at - intervals defined by Frequency=. - - - - Frequency=25 - Configure the sample log frequency. This can - be a fractional number, but must be larger than 0.0. Most - systems can cope with values under 25–50 without impacting - boot time severely. - - - - Relative=no - Configures whether the left axis of the output - graph equals time=0.0 (CLOCK_MONOTONIC - start). This is useful for using bootchart at post-boot time - to profile an already booted system, otherwise the graph would - become extremely large. If set to yes, the horizontal axis - starts at the first recorded sample instead of time=0.0. - - - - - Filter=no - Configures whether the resulting graph should - omit tasks that did not contribute significantly to the boot. - Processes that are too short-lived (only seen in one sample) - or that do not consume any significant CPU time (less than - 0.001sec) will not be displayed in the output - graph. - - - - Output=[path] - Configures the output directory for writing - the graphs. By default, bootchart writes the graphs to - /run/log. - - - - Init=[path] - Configures bootchart to run a non-standard - binary instead of - /usr/lib/systemd/systemd. This option is - only relevant if bootchart was invoked from the kernel command - line with - init=/usr/lib/systemd/systemd-bootchart. - - - - PlotMemoryUsage=no - If set to yes, enables logging and graphing of - processes' PSS memory consumption. - - - - PlotEntropyGraph=no - If set to yes, enables logging and graphing of - the kernel random entropy pool size. - - - - ScaleX=100 - Horizontal scaling factor for all variable - graph components. - - - - ScaleY=20 - Vertical scaling factor for all variable graph - components. - - - - ControlGroup=no - Display process control group. - - - - - - - - See Also - - systemd-bootchart1, - systemd.directives7 - - - - diff --git a/man/systemd-bootchart.xml b/man/systemd-bootchart.xml deleted file mode 100644 index bcee11fd0b..0000000000 --- a/man/systemd-bootchart.xml +++ /dev/null @@ -1,323 +0,0 @@ - - - - - - - - - systemd-bootchart - systemd - - - - Developer - Auke - Kok - auke-jan.h.kok@intel.com - - - - - - systemd-bootchart - 1 - - - - systemd-bootchart - Boot performance graphing tool - - - - Description - - systemd-bootchart is a tool, usually run at - system startup, that collects the CPU load, disk load, memory - 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 - - 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. - - - After collecting a certain amount of data (usually 15–30 - seconds, default 20 s) the logging stops and a graph is - generated from the logged information. This graph contains vital - clues as to which resources are being used, in which order, and - where possible problems exist in the startup sequence of the - system. It is essentially a more detailed version of the - systemd-analyze plot function. - - - Of course, bootchart can also be used at any moment in time to - collect and graph some data for an amount of time. It is - recommended to use the switch in this - case. - - - Bootchart does not require root privileges, and will happily run - as a normal user. - - - Bootchart graphs are by default written time-stamped in - /run/log and saved to the journal with - MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518. - Journal field BOOTCHART= contains the - bootchart in SVG format. - - - - - - Invocation - - systemd-bootchart can be invoked in several different ways: - - - - - Kernel invocation - The kernel can invoke - systemd-bootchart instead of the init - process. In turn, systemd-bootchart will - invoke /usr/lib/systemd/systemd. - - - - - Started as a standalone program - One can execute - systemd-bootchart as normal application - from the command line. In this mode, it is highly recommended - to pass the flag in order to not graph the - time elapsed since boot and before systemd-bootchart was - started, as it may result in extremely large graphs. The time - elapsed since boot might also include any time that the system - was suspended. - - - - - - Options - - These options can also be set in the - /etc/systemd/bootchart.conf file. See - bootchart.conf5. - - - - - - - - - Specify the number of samples, - N, to record. Samples will be - recorded at intervals defined with . - - - - - - - Specify the sample log frequency, a positive - real f, in Hz. Most systems can - cope with values up to 25–50 without creating too much - overhead. - - - - - - Use relative times instead of absolute times. - This is useful for using bootchart at post-boot time to - profile an already booted system. Without this option the - graph would become extremely large. If set, the horizontal - axis starts at the first recorded sample instead of time - 0.0. - - - - - - Disable filtering of tasks that did not - contribute significantly to the boot. Processes that are too - short-lived (only seen in one sample) or that do not consume - any significant CPU time (less than 0.001 s) will not be - displayed in the output graph. - - - - - - Display the full command line with arguments - of processes, instead of only the process name. - - - - - - - Display process control group - - - - - - - Specify the output directory for the graphs. - By default, bootchart writes the graphs to - /run/log. - - - - - - Use this init binary. Defaults to - /usr/lib/systemd/systemd. - - - - - - - Enable logging and graphing of processes' PSS - (Proportional Set Size) memory consumption. See - filesystems/proc.txt in the kernel - documentation for an explanation of this field. - - - - - - - Enable logging and graphing of the kernel - random entropy pool size. - - - - - - Horizontal scaling factor for all variable - graph components. - - - - - - Vertical scaling factor for all variable graph - components. - - - - - - - - - Output - - systemd-bootchart generates SVG graphs. - In order to render those on a graphical display any SVG capable - viewer can be used. It should be noted that the SVG render engines - in most browsers (including Chrome and Firefox) are many times - faster than dedicated graphical applications like Gimp and - Inkscape. Just point your browser at - ! - - - - - History - - This version of bootchart was implemented from scratch, but - is inspired by former bootchart incantations: - - - - Original bash - The original bash/shell code implemented - bootchart. This version created a compressed tarball for - processing with external applications. This version did not - graph anything, only generated data. - - - - Ubuntu C Implementation - This version replaced the shell version with a - fast and efficient data logger, but also did not graph the - data. - - - - Java bootchart - This was the original graphing application for - charting the data, written in java. - - - - pybootchartgui.py - pybootchart created a graph from the data - collected by either the bash or C version. - - - - The version of bootchart you are using now combines both the - data collection and the charting into a single application, making - it more efficient and simpler. There are no longer any timing - issues with the data collector and the grapher, as the graphing - cannot be run until the data has been collected. Also, the data - kept in memory is reduced to the absolute minimum needed. - - - - - See Also - - - bootchart.conf5 - - - - - Bugs - - systemd-bootchart does not get the model information for the - hard drive unless the root device is specified with - root=/dev/sdxY. Using UUIDs or PARTUUIDs will boot - fine, but the hard drive model will not be added to the - chart. - For bugs, please contact the author and current maintainer: - - Auke Kok auke-jan.h.kok@intel.com - - - - diff --git a/src/bootchart/Makefile b/src/bootchart/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/bootchart/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile \ No newline at end of file diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c deleted file mode 100644 index 77d158f5f9..0000000000 --- a/src/bootchart/bootchart.c +++ /dev/null @@ -1,531 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok - - 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 . - ***/ - -/*** - - Many thanks to those who contributed ideas and code: - - Ziga Mahkovec - Original bootchart author - - Anders Norgaard - PyBootchartgui - - Michael Meeks - bootchart2 - - Scott James Remnant - Ubuntu C-based logger - - Arjan van der Ven - for the idea to merge bootgraph.pl functionality - - ***/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sd-journal.h" - -#include "alloc-util.h" -#include "bootchart.h" -#include "conf-parser.h" -#include "def.h" -#include "fd-util.h" -#include "fileio.h" -#include "io-util.h" -#include "list.h" -#include "macro.h" -#include "parse-util.h" -#include "path-util.h" -#include "store.h" -#include "string-util.h" -#include "strxcpyx.h" -#include "svg.h" -#include "util.h" - -static int exiting = 0; - -#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 ROOTLIBEXECDIR "/systemd" -#define DEFAULT_OUTPUT "/run/log" - -/* graph defaults */ -bool arg_entropy = false; -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 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; - -char arg_init_path[PATH_MAX] = DEFAULT_INIT; -char arg_output_path[PATH_MAX] = DEFAULT_OUTPUT; - -static void signal_handler(int sig) { - exiting = 1; -} - -#define BOOTCHART_MAX (16*1024*1024) - -static void parse_conf(void) { - char *init = NULL, *output = NULL; - const ConfigTableItem items[] = { - { "Bootchart", "Samples", config_parse_int, 0, &arg_samples_len }, - { "Bootchart", "Frequency", config_parse_double, 0, &arg_hz }, - { "Bootchart", "Relative", config_parse_bool, 0, &arg_relative }, - { "Bootchart", "Filter", config_parse_bool, 0, &arg_filter }, - { "Bootchart", "Output", config_parse_path, 0, &output }, - { "Bootchart", "Init", config_parse_path, 0, &init }, - { "Bootchart", "PlotMemoryUsage", config_parse_bool, 0, &arg_pss }, - { "Bootchart", "PlotEntropyGraph", config_parse_bool, 0, &arg_entropy }, - { "Bootchart", "ScaleX", config_parse_double, 0, &arg_scale_x }, - { "Bootchart", "ScaleY", config_parse_double, 0, &arg_scale_y }, - { "Bootchart", "ControlGroup", config_parse_bool, 0, &arg_show_cgroup }, - { "Bootchart", "PerCPU", config_parse_bool, 0, &arg_percpu }, - { NULL, NULL, NULL, 0, NULL } - }; - - config_parse_many(PKGSYSCONFDIR "/bootchart.conf", - CONF_PATHS_NULSTR("systemd/bootchart.conf.d"), - NULL, config_item_table_lookup, items, true, NULL); - - if (init != NULL) - strscpy(arg_init_path, sizeof(arg_init_path), init); - if (output != NULL) - strscpy(arg_output_path, sizeof(arg_output_path), output); -} - -static void help(void) { - 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[]) { - - enum { - ARG_PERCPU = 0x100, - }; - - static const struct option options[] = { - {"rel", no_argument, NULL, 'r' }, - {"freq", required_argument, NULL, 'f' }, - {"samples", required_argument, NULL, 'n' }, - {"pss", no_argument, NULL, 'p' }, - {"output", required_argument, NULL, 'o' }, - {"init", required_argument, NULL, 'i' }, - {"no-filter", no_argument, NULL, 'F' }, - {"cmdline", no_argument, NULL, 'C' }, - {"control-group", no_argument, NULL, 'c' }, - {"help", no_argument, NULL, 'h' }, - {"scale-x", required_argument, NULL, 'x' }, - {"scale-y", required_argument, NULL, 'y' }, - {"entropy", no_argument, NULL, 'e' }, - {"per-cpu", no_argument, NULL, ARG_PERCPU}, - {} - }; - int c, r; - - if (getpid() == 1) - opterr = 0; - - while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0) - switch (c) { - - case 'r': - arg_relative = true; - break; - case 'f': - r = safe_atod(optarg, &arg_hz); - if (r < 0) - log_warning_errno(r, "failed to parse --freq/-f argument '%s': %m", - optarg); - break; - case 'F': - arg_filter = false; - break; - case 'C': - arg_show_cmdline = true; - break; - case 'c': - arg_show_cgroup = true; - break; - case 'n': - r = safe_atoi(optarg, &arg_samples_len); - if (r < 0) - log_warning_errno(r, "failed to parse --samples/-n argument '%s': %m", - optarg); - break; - case 'o': - path_kill_slashes(optarg); - strscpy(arg_output_path, sizeof(arg_output_path), optarg); - break; - case 'i': - path_kill_slashes(optarg); - strscpy(arg_init_path, sizeof(arg_init_path), optarg); - break; - case 'p': - arg_pss = true; - break; - case 'x': - r = safe_atod(optarg, &arg_scale_x); - if (r < 0) - log_warning_errno(r, "failed to parse --scale-x/-x argument '%s': %m", - optarg); - break; - case 'y': - r = safe_atod(optarg, &arg_scale_y); - if (r < 0) - log_warning_errno(r, "failed to parse --scale-y/-y argument '%s': %m", - optarg); - break; - case 'e': - arg_entropy = true; - break; - case ARG_PERCPU: - arg_percpu = true; - break; - case 'h': - help(); - return 0; - case '?': - if (getpid() != 1) - return -EINVAL; - else - return 0; - default: - assert_not_reached("Unhandled option code."); - } - - if (arg_hz <= 0) { - log_error("Frequency needs to be > 0"); - return -EINVAL; - } - - return 1; -} - -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, j = 0; - ssize_t n; - - bootchart_file = strappend("BOOTCHART_FILE=", 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) - return log_oom(); - - IOVEC_SET_STRING(iovec[j++], bootchart_message); - - p = malloc(10 + BOOTCHART_MAX); - if (!p) - return log_oom(); - - memcpy(p, "BOOTCHART=", 10); - - 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; - j++; - - 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; - _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, samples; - struct ps_struct *ps; - struct rlimit rlim; - struct list_sample_data *head; - struct sigaction sig = { - .sa_handler = signal_handler, - }; - - parse_conf(); - - r = parse_argv(argc, argv); - 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 - * fork: - * - parent execs executable specified via init_path[] (/usr/lib/systemd/systemd by default) as pid=1 - * - child logs data - */ - if (getpid() == 1) { - if (fork()) - /* parent */ - execl(arg_init_path, arg_init_path, NULL); - } - argv[0][0] = '@'; - - rlim.rlim_cur = 4096; - rlim.rlim_max = 4096; - (void) setrlimit(RLIMIT_NOFILE, &rlim); - - /* start with empty ps LL */ - ps_first = new0(struct ps_struct, 1); - if (!ps_first) { - log_oom(); - return EXIT_FAILURE; - } - - /* handle TERM/INT nicely */ - sigaction(SIGHUP, &sig, NULL); - - interval = (1.0 / arg_hz) * 1000000000.0; - - if (arg_relative) - graph_start = log_start = gettime_ns(); - else { - struct timespec n; - double uptime; - - clock_gettime(clock_boottime_or_monotonic(), &n); - uptime = (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC)); - - log_start = gettime_ns(); - graph_start = log_start - uptime; - } - - 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); - - /* main program loop */ - for (samples = 0; !exiting && samples < arg_samples_len; samples++) { - int res; - double sample_stop; - double elapsed; - double timeleft; - - sampledata = new0(struct list_sample_data, 1); - if (sampledata == NULL) { - log_oom(); - return EXIT_FAILURE; - } - - sampledata->sampletime = gettime_ns(); - sampledata->counter = samples; - - if (sysfd < 0) - sysfd = open("/sys", O_RDONLY|O_CLOEXEC); - - if (!build) { - if (parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &build, NULL) == -ENOENT) - parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL); - } - - if (proc) - rewinddir(proc); - else - 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(); - - elapsed = (sample_stop - sampledata->sampletime) * 1000000000.0; - timeleft = interval - elapsed; - - /* - * check if we have not consumed our entire timeslice. If we - * do, don't sleep and take a new sample right away. - * we'll lose all the missed samples and overrun our total - * time - */ - if (timeleft > 0) { - struct timespec req; - - req.tv_sec = (time_t)(timeleft / 1000000000.0); - req.tv_nsec = (long)(timeleft - (req.tv_sec * 1000000000.0)); - - res = nanosleep(&req, NULL); - if (res) { - if (errno == EINTR) - /* caught signal, probably HUP! */ - break; - log_error_errno(errno, "nanosleep() failed: %m"); - return EXIT_FAILURE; - } - } else { - overrun++; - /* calculate how many samples we lost and scrap them */ - arg_samples_len -= (int)(-timeleft / interval); - } - LIST_PREPEND(link, head, sampledata); - } - - /* do some cleanup, close fd's */ - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - ps->schedstat = safe_close(ps->schedstat); - ps->sched = safe_close(ps->sched); - ps->smaps = safe_fclose(ps->smaps); - } - - if (!of) { - 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 (!of) { - log_error("Error opening output file '%s': %m\n", output_file); - return EXIT_FAILURE; - } - - r = svg_do(of, strna(build), head, ps_first, - samples, pscount, n_cpus, graph_start, - log_start, interval, overrun); - - if (r < 0) { - log_error_errno(r, "Error generating svg file: %m"); - return EXIT_FAILURE; - } - - log_info("systemd-bootchart wrote %s\n", output_file); - - r = do_journal_append(output_file); - if (r < 0) - return EXIT_FAILURE; - - /* nitpic cleanups */ - ps = ps_first->next_ps; - while (ps->next_ps) { - struct ps_struct *old; - - old = ps; - old->sample = ps->first; - ps = ps->next_ps; - while (old->sample->next) { - struct ps_sched_struct *oldsample = old->sample; - - old->sample = old->sample->next; - free(oldsample); - } - free(old->cgroup); - free(old->sample); - free(old); - } - - free(ps->cgroup); - free(ps->sample); - free(ps); - - sampledata = head; - while (sampledata->link_prev) { - struct list_sample_data *old_sampledata = sampledata; - sampledata = sampledata->link_prev; - free(old_sampledata); - } - free(sampledata); - - /* don't complain when overrun once, happens most commonly on 1st sample */ - if (overrun > 1) - log_warning("systemd-bootchart: sample time overrun %i times\n", overrun); - - return 0; -} diff --git a/src/bootchart/bootchart.conf b/src/bootchart/bootchart.conf deleted file mode 100644 index 4f5e50936e..0000000000 --- a/src/bootchart/bootchart.conf +++ /dev/null @@ -1,26 +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. -# -# 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. - -[Bootchart] -#Samples=500 -#Frequency=25 -#Relative=no -#Filter=yes -#Output= -#Init=/path/to/init-binary -#PlotMemoryUsage=no -#PlotEntropyGraph=no -#ScaleX=100 -#ScaleY=20 -#ControlGroup=no -#PerCPU=no diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h deleted file mode 100644 index 1b445b954b..0000000000 --- a/src/bootchart/bootchart.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok - - 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 . -***/ - -#include - -#include "list.h" - -#define MAXCPUS 16 -#define MAXPIDS 65535 - -struct block_stat_struct { - /* /proc/vmstat pgpgin & pgpgout */ - int bi; - int bo; -}; - -struct cpu_stat_sample_struct { - /* /proc/schedstat fields 10 & 11 (after name) */ - double runtime; - double waittime; -}; - -/* per process, per sample data we will log */ -struct ps_sched_struct { - /* /proc//schedstat fields 1 & 2 */ - double runtime; - double waittime; - int pss; - struct list_sample_data *sampledata; - struct ps_sched_struct *next; - struct ps_sched_struct *prev; - struct ps_sched_struct *cross; /* cross pointer */ - struct ps_struct *ps_new; -}; - -struct list_sample_data { - double runtime[MAXCPUS]; - double waittime[MAXCPUS]; - double sampletime; - int entropy_avail; - struct block_stat_struct blockstat; - LIST_FIELDS(struct list_sample_data, link); /* DLL */ - int counter; -}; - -/* process info */ -struct ps_struct { - struct ps_struct *next_ps; /* SLL pointer */ - struct ps_struct *parent; /* ppid ref */ - struct ps_struct *children; /* children */ - struct ps_struct *next; /* siblings */ - - /* must match - otherwise it's a new process with same PID */ - char name[256]; - int pid; - int ppid; - char *cgroup; - - /* cache fd's */ - int sched; - int schedstat; - FILE *smaps; - - /* pointers to first/last seen timestamps */ - struct ps_sched_struct *first; - struct ps_sched_struct *last; - - /* records actual start time, may be way before bootchart runs */ - double starttime; - - /* record human readable total cpu time */ - double total; - - /* largest PSS size found */ - int pss_max; - - /* for drawing connection lines later */ - double pos_x; - double pos_y; - - struct ps_sched_struct *sample; -}; - -extern bool arg_relative; -extern bool arg_filter; -extern bool arg_show_cmdline; -extern bool arg_show_cgroup; -extern bool arg_pss; -extern bool arg_entropy; -extern bool arg_percpu; -extern bool arg_initcall; -extern int arg_samples_len; -extern double arg_hz; -extern double arg_scale_x; -extern double arg_scale_y; - -extern char arg_output_path[PATH_MAX]; -extern char arg_init_path[PATH_MAX]; diff --git a/src/bootchart/store.c b/src/bootchart/store.c deleted file mode 100644 index 42cb8043ce..0000000000 --- a/src/bootchart/store.c +++ /dev/null @@ -1,555 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok - - 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 . - ***/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "alloc-util.h" -#include "bootchart.h" -#include "cgroup-util.h" -#include "dirent-util.h" -#include "fd-util.h" -#include "fileio.h" -#include "parse-util.h" -#include "store.h" -#include "string-util.h" -#include "strxcpyx.h" -#include "time-util.h" -#include "util.h" - -/* - * Alloc a static 4k buffer for stdio - primarily used to increase - * PSS buffering from the default 1k stdin buffer to reduce - * read() overhead. - */ -static char smaps_buf[4096]; -static int skip = 0; - -double gettime_ns(void) { - struct timespec n; - - clock_gettime(CLOCK_MONOTONIC, &n); - - return (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC)); -} - -static char *bufgetline(char *buf) { - char *c; - - if (!buf) - return NULL; - - c = strchr(buf, '\n'); - if (c) - c++; - - return c; -} - -static int pid_cmdline_strscpy(int procfd, char *buffer, size_t buf_len, int pid) { - char filename[PATH_MAX]; - _cleanup_close_ int fd = -1; - ssize_t n; - - sprintf(filename, "%d/cmdline", pid); - fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - n = read(fd, buffer, buf_len-1); - if (n > 0) { - int i; - for (i = 0; i < n; i++) - if (buffer[i] == '\0') - buffer[i] = ' '; - buffer[n] = '\0'; - } - - return 0; -} - -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; - _cleanup_free_ char *buf_schedstat = NULL; - char buf[4096]; - char key[256]; - char val[256]; - char rt[256]; - char wt[256]; - char *m; - int r; - int c; - int p; - int mod; - 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; - int taskfd = -1; - - sampledata = *ptr; - - procfd = dirfd(proc); - if (procfd < 0) - return -errno; - - if (vmstat < 0) { - /* block stuff */ - 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) { - vmstat = safe_close(vmstat); - if (n < 0) - return -errno; - return -ENODATA; - } - - buf[n] = '\0'; - - m = buf; - while (m) { - if (sscanf(m, "%s %s", key, val) < 2) - goto vmstat_next; - if (streq(key, "pgpgin")) - sampledata->blockstat.bi = atoi(val); - if (streq(key, "pgpgout")) { - sampledata->blockstat.bo = atoi(val); - break; - } -vmstat_next: - m = bufgetline(m); - if (!m) - break; - } - - /* Parse "/proc/schedstat" for overall CPU utilization */ - r = read_full_file("/proc/schedstat", &buf_schedstat, NULL); - if (r < 0) - return log_error_errno(r, "Unable to read schedstat: %m"); - - m = buf_schedstat; - while (m) { - if (sscanf(m, "%s %*s %*s %*s %*s %*s %*s %s %s", key, rt, wt) < 3) - goto schedstat_next; - - if (strstr(key, "cpu")) { - r = safe_atoi((const char*)(key+3), &c); - if (r < 0 || c > MAXCPUS -1) - /* Oops, we only have room for MAXCPUS data */ - break; - sampledata->runtime[c] = atoll(rt); - sampledata->waittime[c] = atoll(wt); - - if (c == *cpus) - *cpus = c + 1; - } -schedstat_next: - m = bufgetline(m); - if (!m) - break; - } - - if (arg_entropy) { - 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"); - } - - 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); - } - } - - while ((ent = readdir(proc)) != NULL) { - char filename[PATH_MAX]; - int pid; - struct ps_struct *ps; - - if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) - continue; - - pid = atoi(ent->d_name); - - if (pid >= MAXPIDS) - continue; - - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - if (ps->pid == pid) - break; - } - - /* end of our LL? then append a new record */ - if (ps->pid != pid) { - _cleanup_fclose_ FILE *st = NULL; - char t[32]; - struct ps_struct *parent; - - ps->next_ps = new0(struct ps_struct, 1); - 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) - return log_oom(); - - ps->sample->sampledata = sampledata; - - (*pscount)++; - - /* mark our first sample */ - ps->first = ps->last = ps->sample; - ps->sample->runtime = atoll(rt); - ps->sample->waittime = atoll(wt); - - /* get name, start time */ - if (ps->sched < 0) { - sprintf(filename, "%d/sched", pid); - 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) { - ps->sched = safe_close(ps->sched); - continue; - } - buf[s] = '\0'; - - if (!sscanf(buf, "%s %*s %*s", key)) - continue; - - strscpy(ps->name, sizeof(ps->name), key); - - /* cmdline */ - if (arg_show_cmdline) - pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid); - - /* discard line 2 */ - m = bufgetline(buf); - if (!m) - continue; - - m = bufgetline(m); - if (!m) - continue; - - if (!sscanf(m, "%*s %*s %s", t)) - continue; - - r = safe_atod(t, &ps->starttime); - if (r < 0) - continue; - - ps->starttime /= 1000.0; - - if (arg_show_cgroup) - /* if this fails, that's OK */ - cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, - ps->pid, &ps->cgroup); - - /* ppid */ - sprintf(filename, "%d/stat", pid); - fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - continue; - - st = fdopen(fd, "re"); - if (!st) { - close(fd); - continue; - } - - if (!fscanf(st, "%*s %*s %*s %i", &p)) - continue; - - ps->ppid = p; - - /* - * setup child pointers - * - * these are used to paint the tree coherently later - * each parent has a LL of children, and a LL of siblings - */ - if (pid == 1) - continue; /* nothing to do for init atm */ - - /* kthreadd has ppid=0, which breaks our tree ordering */ - if (ps->ppid == 0) - ps->ppid = 1; - - parent = ps_first; - while ((parent->next_ps && parent->pid != ps->ppid)) - parent = parent->next_ps; - - if (parent->pid != ps->ppid) { - /* orphan */ - ps->ppid = 1; - parent = ps_first->next_ps; - } - - ps->parent = parent; - - if (!parent->children) { - /* it's the first child */ - parent->children = ps; - } else { - /* walk all children and append */ - struct ps_struct *children; - children = parent->children; - while (children->next) - children = children->next; - - children->next = ps; - } - } - - /* else -> found pid, append data in ps */ - - /* below here is all continuous logging parts - we get here on every - * iteration */ - - /* rt, wt */ - if (ps->schedstat < 0) { - sprintf(filename, "%d/schedstat", pid); - 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); - 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) - return log_oom(); - - ps->sample->next->prev = ps->sample; - ps->sample = ps->sample->next; - ps->last = ps->sample; - ps->sample->runtime = atoll(rt); - ps->sample->waittime = atoll(wt); - ps->sample->sampledata = sampledata; - ps->sample->ps_new = ps; - if (ps_prev) - ps_prev->cross = ps->sample; - - ps_prev = ps->sample; - ps->total = (ps->last->runtime - ps->first->runtime) - / 1000000000.0; - - /* Take into account CPU runtime/waittime spent in non-main threads of the process - * by parsing "/proc/[pid]/task/[tid]/schedstat" for all [tid] != [pid] - * See https://github.com/systemd/systemd/issues/139 - */ - - /* Browse directory "/proc/[pid]/task" to know the thread ids of process [pid] */ - snprintf(filename, sizeof(filename), PID_FMT "/task", pid); - taskfd = openat(procfd, filename, O_RDONLY|O_DIRECTORY|O_CLOEXEC); - if (taskfd >= 0) { - _cleanup_closedir_ DIR *taskdir = NULL; - - taskdir = fdopendir(taskfd); - if (!taskdir) { - safe_close(taskfd); - return -errno; - } - FOREACH_DIRENT(ent, taskdir, break) { - int tid = -1; - _cleanup_close_ int tid_schedstat = -1; - long long delta_rt; - long long delta_wt; - - if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9')) - continue; - - /* Skip main thread as it was already accounted */ - r = safe_atoi(ent->d_name, &tid); - if (r < 0 || tid == pid) - continue; - - /* Parse "/proc/[pid]/task/[tid]/schedstat" */ - snprintf(filename, sizeof(filename), PID_FMT "/schedstat", tid); - tid_schedstat = openat(taskfd, filename, O_RDONLY|O_CLOEXEC); - - if (tid_schedstat == -1) - continue; - - s = pread(tid_schedstat, buf, sizeof(buf) - 1, 0); - if (s <= 0) - continue; - buf[s] = '\0'; - - if (!sscanf(buf, "%s %s %*s", rt, wt)) - continue; - - r = safe_atolli(rt, &delta_rt); - if (r < 0) - continue; - r = safe_atolli(rt, &delta_wt); - if (r < 0) - continue; - ps->sample->runtime += delta_rt; - ps->sample->waittime += delta_wt; - } - } - - if (!arg_pss) - goto catch_rename; - - /* Pss */ - if (!ps->smaps) { - sprintf(filename, "%d/smaps", pid); - 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 { - rewind(ps->smaps); - } - - /* test to see if we need to skip another field */ - if (skip == 0) { - if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { - continue; - } - if (fread(buf, 1, 28 * 15, ps->smaps) != (28 * 15)) { - continue; - } - if (buf[392] == 'V') { - skip = 2; - } - else { - skip = 1; - } - rewind(ps->smaps); - } - - while (1) { - int pss_kb; - - /* skip one line, this contains the object mapped. */ - if (fgets(buf, sizeof(buf), ps->smaps) == NULL) { - break; - } - /* then there's a 28 char 14 line block */ - if (fread(buf, 1, 28 * 14, ps->smaps) != 28 * 14) { - break; - } - pss_kb = atoi(&buf[61]); - ps->sample->pss += pss_kb; - - /* skip one more line if this is a newer kernel */ - if (skip == 2) { - if (fgets(buf, sizeof(buf), ps->smaps) == NULL) - 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 (((sample - ps->pid) + pid) % (int)(mod) == 0) { - - /* re-fetch name */ - /* get name, start time */ - if (ps->sched < 0) { - sprintf(filename, "%d/sched", pid); - 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 */ - ps->sched = safe_close(ps->sched); - ps->schedstat = safe_close(ps->schedstat); - continue; - } - - buf[s] = '\0'; - - if (!sscanf(buf, "%s %*s %*s", key)) - continue; - - strscpy(ps->name, sizeof(ps->name), key); - - /* cmdline */ - if (arg_show_cmdline) - pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid); - } - } - - return 0; -} diff --git a/src/bootchart/store.h b/src/bootchart/store.h deleted file mode 100644 index 6e9acf2a6f..0000000000 --- a/src/bootchart/store.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok - - 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 . -***/ - -#include - -#include "bootchart.h" - -double gettime_ns(void); -void log_uptime(void); -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 deleted file mode 100644 index f2af535061..0000000000 --- a/src/bootchart/svg.c +++ /dev/null @@ -1,1375 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok - - 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 . - ***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "alloc-util.h" -#include "architecture.h" -#include "bootchart.h" -#include "fd-util.h" -#include "fileio.h" -#include "list.h" -#include "macro.h" -#include "stdio-util.h" -#include "store.h" -#include "svg.h" -#include "utf8.h" -#include "util.h" - -#define time_to_graph(t) ((t) * arg_scale_x) -#define ps_to_graph(n) ((n) * arg_scale_y) -#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001) -#define to_color(n) (192.0 - ((n) * 192.0)) - -static const char * const colorwheel[12] = { - "rgb(255,32,32)", // red - "rgb(32,192,192)", // cyan - "rgb(255,128,32)", // orange - "rgb(128,32,192)", // blue-violet - "rgb(255,255,32)", // yellow - "rgb(192,32,128)", // red-violet - "rgb(32,255,32)", // green - "rgb(255,64,32)", // red-orange - "rgb(32,32,255)", // blue - "rgb(255,192,32)", // yellow-orange - "rgb(192,32,192)", // violet - "rgb(32,192,32)" // yellow-green -}; - -static double idletime = -1.0; -static int pfiltered = 0; -static int pcount = 0; -static int kcount = 0; -static double psize = 0; -static double ksize = 0; -static double esize = 0; -static struct list_sample_data *sampledata; -static struct list_sample_data *prev_sampledata; - -static void svg_header(FILE *of, struct list_sample_data *head, double graph_start, int n_cpus) { - double w; - double h; - struct list_sample_data *sampledata_last; - - assert(head); - - sampledata_last = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - sampledata_last = sampledata; - } - - /* min width is about 1600px due to the label */ - w = 150.0 + 10.0 + time_to_graph(sampledata_last->sampletime - graph_start); - w = ((w < 1600.0) ? 1600.0 : w); - - /* height is variable based on pss, psize, ksize */ - h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */ - + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */ - + psize + ksize + esize + (n_cpus * 15 * arg_scale_y); - - fprintf(of, "\n"); - fprintf(of, "\n"); - - //fprintf(of, "\n", 1000 + 150 + (pcount * 20)); - fprintf(of, "\n\n"); - - /* write some basic info as a comment, including some help */ - fprintf(of, "\n"); - fprintf(of, "\n"); - fprintf(of, "\n"); - fprintf(of, "\n"); - fprintf(of, "\n\n"); - - fprintf(of, "\n", VERSION); - fprintf(of, "\n", arg_hz, arg_samples_len); - fprintf(of, "\n", arg_scale_x, arg_scale_y); - fprintf(of, "\n", arg_relative, arg_filter); - fprintf(of, "\n", arg_pss, arg_entropy); - fprintf(of, "\n\n", arg_output_path, arg_init_path); - - /* style sheet */ - fprintf(of, "\n \n\n\n"); -} - -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"; - const char *cpu; - char *c; - time_t t; - int r; - struct utsname uts; - - 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) { - char rootbdev[4]; - char filename[32]; - - strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1); - rootbdev[3] = '\0'; - xsprintf(filename, "/sys/block/%s/device/model", rootbdev); - - r = read_one_line_file(filename, &model); - if (r < 0) - log_info("Error reading disk model for %s: %m\n", rootbdev); - } - - /* various utsname parameters */ - r = uname(&uts); - if (r < 0) { - log_error("Error getting uname info\n"); - return -errno; - } - - /* date */ - t = time(NULL); - r = strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); - assert_se(r > 0); - - /* CPU type */ - r = get_proc_field("/proc/cpuinfo", PROC_CPUINFO_MODEL, "\n", &buf); - if (r < 0) - cpu = "Unknown"; - else - cpu = buf; - - fprintf(of, "Bootchart for %s - %s\n", - uts.nodename, date); - fprintf(of, "System: %s %s %s %s\n", - uts.sysname, uts.release, uts.version, uts.machine); - fprintf(of, "CPU: %s\n", cpu); - if (model) - fprintf(of, "Disk: %s\n", model); - fprintf(of, "Boot options: %s\n", cmdline); - fprintf(of, "Build: %s\n", build); - fprintf(of, "Log start time: %.03fs\n", log_start); - fprintf(of, "Idle time: "); - - if (idletime >= 0.0) - fprintf(of, "%.03fs", idletime); - else - fprintf(of, "Not detected"); - - fprintf(of, "\n"); - fprintf(of, "Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered\n", - arg_hz, arg_samples_len, overrun, pscount, pfiltered); - - return 0; -} - -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; - struct list_sample_data *sampledata_last; - - sampledata_last = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - sampledata_last = sampledata; - } - - finalsample = sampledata_last->sampletime; - - /* outside box, fill */ - fprintf(of, "\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) - fprintf(of, " \n", - time_to_graph(d - graph_start), - time_to_graph(d - graph_start), - ps_to_graph(height)); - else if (i % 10 == 0) - fprintf(of, " \n", - time_to_graph(d - graph_start), - time_to_graph(d - graph_start), - ps_to_graph(height)); - else - fprintf(of, " \n", - time_to_graph(d - graph_start), - time_to_graph(d - graph_start), - ps_to_graph(height)); - - /* time label */ - if (i % 10 == 0) - fprintf(of, " %.01fs\n", - time_to_graph(d - graph_start), - -5.0, d - graph_start); - - i++; - } -} - -/* xml comments must not contain "--" */ -static char* xml_comment_encode(const char* name) { - char *enc_name, *p; - - enc_name = strdup(name); - if (!enc_name) - return NULL; - - for (p = enc_name; *p; p++) - if (p[0] == '-' && p[1] == '-') - p[1] = '_'; - - return enc_name; -} - -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; - - sampledata_last = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - sampledata_last = sampledata; - } - - - fprintf(of, "\n\n\n"); - - fprintf(of, "\n Memory allocation - Pss\n"); - - /* vsize 1000 == 1000mb */ - svg_graph_box(of, head, 100, graph_start); - /* draw some hlines for usable memory sizes */ - for (i = 100000; i < 1000000; i += 100000) { - fprintf(of, " \n", - time_to_graph(.0), - kb_to_graph(i), - time_to_graph(sampledata_last->sampletime - graph_start), - kb_to_graph(i)); - fprintf(of, " %dM\n", - time_to_graph(sampledata_last->sampletime - graph_start) + 5, - kb_to_graph(i), (1000000 - i) / 1000); - } - fprintf(of, "\n"); - - /* now plot the graph itself */ - i = 1; - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int bottom; - int top; - struct ps_sched_struct *cross_place; - - bottom = 0; - top = 0; - - /* put all the small pss blocks into the bottom */ - ps = ps_first; - while (ps->next_ps) { - 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 (ps->sample->cross) { - cross_place = ps->sample->cross; - ps = ps->sample->cross->ps_new; - ps->sample = cross_place; - if (ps->sample->pss <= (100 * arg_scale_y)) - top += ps->sample->pss; - } - - fprintf(of, " \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 */ - ps = ps_first; - while (ps->next_ps) { - 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; - } - /* don't draw anything smaller than 2mb */ - if (ps->sample->sampledata != sampledata) - continue; - if (ps->sample->pss > (100 * arg_scale_y)) { - top = bottom + ps->sample->pss; - fprintf(of, " \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; - } - - 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; - fprintf(of, " \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++; - } - - /* overlay all the text labels */ - i = 1; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int bottom; - int top = 0; - struct ps_sched_struct *prev_sample; - struct ps_sched_struct *cross_place; - - /* put all the small pss blocks into the bottom */ - ps = ps_first->next_ps; - while (ps->next_ps) { - 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; - if (ps->sample->pss <= (100 * arg_scale_y)) - top += ps->sample->pss; - } - bottom = top; - - /* now plot the ones that are of significant size */ - ps = ps_first; - while (ps->next_ps) { - prev_sample = ps->sample; - ps = ps->next_ps; - if (!ps) - continue; - ps->sample = ps->first; - while (ps->sample->next) { - prev_sample = ps->sample; - ps->sample = ps->sample->next; - if (ps->sample->sampledata == sampledata) - break; - } - /* don't draw anything smaller than 2mb */ - if (ps->sample->sampledata == sampledata) { - if (ps->sample->pss > (100 * arg_scale_y)) { - top = bottom + ps->sample->pss; - /* draw a label with the process / PID */ - if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) - fprintf(of, " %s [%i]\n", - time_to_graph(sampledata->sampletime - graph_start), - kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)), - ps->name, ps->pid); - bottom = top; - } - break; - } - } - while ((cross_place = ps->sample->cross)) { - ps = ps->sample->cross->ps_new; - ps->sample = cross_place; - prev_sample = ps->sample->prev; - if (ps->sample->pss > (100 * arg_scale_y)) { - top = bottom + ps->sample->pss; - /* draw a label with the process / PID */ - if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y))) - fprintf(of, " %s [%i]\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 */ - fprintf(of, "\n\n\n"); - ps = ps_first; - while (ps->next_ps) { - _cleanup_free_ char *enc_name = NULL; - ps = ps->next_ps; - if (!ps) - continue; - - enc_name = xml_comment_encode(ps->name); - if (!enc_name) - continue; - - fprintf(of, "\n"); - } - -} - -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; - int i; - int k; - struct list_sample_data *start_sampledata; - struct list_sample_data *stop_sampledata; - - fprintf(of, "\n"); - fprintf(of, "IO utilization - read\n"); - - /* - * calculate rounding range - * - * We need to round IO data since IO block data is not updated on - * each poll. Applying a smoothing function loses some burst data, - * so keep the smoothing range short. - */ - range = 0.25 / (1.0 / arg_hz); - if (range < 2.0) - range = 2.0; /* no smoothing */ - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* find the max IO first */ - i = 1; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start; - int stop; - int diff; - double tot; - - start = MAX(i - ((range / 2) - 1), 0); - 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++) - start_sampledata = start_sampledata->link_next; - - 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; - - if (tot > max) { - max = tot; - max_here = i; - } - - tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff; - - if (tot > max) - max = tot; - - i++; - } - - /* plot bi */ - i = 1; - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start; - int stop; - int diff; - double tot; - double pbi = 0; - - start = MAX(i - ((range / 2) - 1), 0); - 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++) - start_sampledata = start_sampledata->link_next; - - 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; - - if (max > 0) - pbi = tot / max; - - if (pbi > 0.001) - fprintf(of, "\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) - fprintf(of, " %0.2fmb/sec\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(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; - int i; - int k; - struct list_sample_data *start_sampledata; - struct list_sample_data *stop_sampledata; - - fprintf(of, "\n"); - fprintf(of, "IO utilization - write\n"); - - /* - * calculate rounding range - * - * We need to round IO data since IO block data is not updated on - * each poll. Applying a smoothing function loses some burst data, - * so keep the smoothing range short. - */ - range = 0.25 / (1.0 / arg_hz); - if (range < 2.0) - range = 2.0; /* no smoothing */ - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* find the max IO first */ - i = 0; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start; - int stop; - int diff; - double tot; - - start = MAX(i - ((range / 2) - 1), 0); - 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++) - start_sampledata = start_sampledata->link_next; - - 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; - if (tot > max) - max = tot; - - 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; - - LIST_FOREACH_BEFORE(link, sampledata, head) { - int start, stop, diff; - double tot, pbo; - - pbo = 0; - - start = MAX(i - ((range / 2) - 1), 0); - 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++) - start_sampledata = start_sampledata->link_next; - - 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) - / diff; - - if (max > 0) - pbo = tot / max; - - if (pbo > 0.001) - fprintf(of, "\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) - fprintf(of, " %0.2fmb/sec\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(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) { - - fprintf(of, "\n"); - - if (cpu_num < 0) - fprintf(of, "CPU[overall] utilization\n"); - else - fprintf(of, "CPU[%d] utilization\n", cpu_num); - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* bars for each sample, proportional to the CPU util. */ - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int c; - double trt; - double ptrt; - - ptrt = trt = 0.0; - - if (cpu_num < 0) - 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]; - - trt = trt / 1000000000.0; - - if (cpu_num < 0) - trt = trt / (double)n_cpus; - - if (trt > 0.0) - ptrt = trt / (sampledata->sampletime - prev_sampledata->sampletime); - - if (ptrt > 1.0) - ptrt = 1.0; - - if (ptrt > 0.001) - fprintf(of, "\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(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) { - - fprintf(of, "\n"); - - if (cpu_num < 0) - fprintf(of, "CPU[overall] wait\n"); - else - fprintf(of, "CPU[%d] wait\n", cpu_num); - - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* bars for each sample, proportional to the CPU util. */ - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - int c; - double twt; - double ptwt; - - ptwt = twt = 0.0; - - if (cpu_num < 0) - 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]; - - twt = twt / 1000000000.0; - - if (cpu_num < 0) - twt = twt / (double)n_cpus; - - if (twt > 0.0) - ptwt = twt / (sampledata->sampletime - prev_sampledata->sampletime); - - if (ptwt > 1.0) - ptwt = 1.0; - - if (ptwt > 0.001) - fprintf(of, "\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(FILE *of, struct list_sample_data *head, double graph_start) { - - fprintf(of, "\n"); - - fprintf(of, "Entropy pool size\n"); - /* surrounding box */ - svg_graph_box(of, head, 5, graph_start); - - /* bars for each sample, scale 0-4096 */ - prev_sampledata = head; - LIST_FOREACH_BEFORE(link, sampledata, head) { - fprintf(of, "\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, struct ps_struct *ps_first) { - /* - * walk the list of processes and return the next one to be - * painted - */ - if (ps == ps_first) - return ps->next_ps; - - /* go deep */ - if (ps->children) - return ps->children; - - /* find siblings */ - if (ps->next) - return ps->next; - - /* go back for parent siblings */ - for (;;) { - if (ps->parent && ps->parent->next) - return ps->parent->next; - - ps = ps->parent; - if (!ps) - return ps; - } - - return NULL; -} - -static bool ps_filter(struct ps_struct *ps) { - if (!arg_filter) - return false; - - /* can't draw data when there is only 1 sample (need start + stop) */ - if (ps->first == ps->last) - return true; - - /* don't filter kthreadd */ - if (ps->pid == 2) - return false; - - /* drop stuff that doesn't use any real CPU time */ - if (ps->total <= 0.001) - return true; - - return 0; -} - -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]; - int ret; - int usecs; - - /* can't plot initcall when disabled or in relative mode */ - if (!arg_initcall || arg_relative) { - kcount = 0; - return; - } - - if (!count_only) { - fprintf(of, "\n"); - fprintf(of, "Kernel init threads\n"); - /* surrounding box */ - svg_graph_box(of, head, kcount, graph_start); - } - - kcount = 0; - - /* - * Initcall graphing - parses dmesg buffer and displays kernel threads - * This somewhat uses the same methods and scaling to show processes - * but looks a lot simpler. It's overlaid entirely onto the PS graph - * when appropriate. - */ - - f = popen("dmesg", "r"); - if (!f) - return; - - while (!feof(f)) { - int c; - int z = 0; - char l[256]; - - if (fgets(l, sizeof(l) - 1, f) == NULL) - continue; - - c = sscanf(l, "[%lf] initcall %s %*s %d %*s %d %*s", - &t, func, &ret, &usecs); - if (c != 4) { - /* also parse initcalls done by module loading */ - c = sscanf(l, "[%lf] initcall %s %*s %*s %d %*s %d %*s", - &t, func, &ret, &usecs); - if (c != 4) - continue; - } - - /* chop the +0xXX/0xXX stuff */ - while(func[z] != '+') - z++; - func[z] = 0; - - if (count_only) { - /* filter out irrelevant stuff */ - if (usecs >= 1000) - kcount++; - continue; - } - - fprintf(of, "\n", - func, t, usecs, ret); - - if (usecs < 1000) - continue; - - /* rect */ - fprintf(of, " \n", - time_to_graph(t - (usecs / 1000000.0)), - ps_to_graph(kcount), - time_to_graph(usecs / 1000000.0), - ps_to_graph(1)); - - /* label */ - fprintf(of, " %s %.03fs\n", - time_to_graph(t - (usecs / 1000000.0)) + 5, - ps_to_graph(kcount) + 15, - func, usecs / 1000000.0); - - kcount++; - } -} - -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; - - fprintf(of, "\n"); - fprintf(of, "Processes\n"); - - /* surrounding box */ - svg_graph_box(of, head, pcount, graph_start); - - /* pass 2 - ps boxes */ - ps = ps_first; - while ((ps = get_next_ps(ps, ps_first))) { - _cleanup_free_ char *enc_name = NULL, *escaped = NULL; - double endtime; - double starttime; - int t; - - if (!utf8_is_printable(ps->name, strlen(ps->name))) - escaped = utf8_escape_non_printable(ps->name); - - enc_name = xml_comment_encode(escaped ? escaped : ps->name); - if (!enc_name) - continue; - - /* leave some trace of what we actually filtered etc. */ - fprintf(of, "\n", enc_name, ps->pid, - ps->ppid, ps->total); - - starttime = ps->first->sampledata->sampletime; - - if (!ps_filter(ps)) { - /* remember where _to_ our children need to draw a line */ - ps->pos_x = time_to_graph(starttime - graph_start); - ps->pos_y = ps_to_graph(j+1); /* bottom left corner */ - } else if (ps->parent){ - /* hook children to our parent coords instead */ - ps->pos_x = ps->parent->pos_x; - ps->pos_y = ps->parent->pos_y; - - /* if this is the last child, we might still need to draw a connecting line */ - if ((!ps->next) && (ps->parent)) - fprintf(of, " \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; - fprintf(of, " \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; - t = 1; - while (ps->sample->next) { - double rt, prt; - double wt, wrt; - struct ps_sched_struct *prev; - - prev = ps->sample; - ps->sample = ps->sample->next; - - /* calculate over interval */ - rt = ps->sample->runtime - prev->runtime; - wt = ps->sample->waittime - prev->waittime; - - prt = (rt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); - wrt = (wt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime); - - /* this can happen if timekeeping isn't accurate enough */ - if (prt > 1.0) - prt = 1.0; - if (wrt > 1.0) - wrt = 1.0; - - if ((prt < 0.1) && (wrt < 0.1)) /* =~ 26 (color threshold) */ - continue; - - fprintf(of, " \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 */ - fprintf(of, " \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++; - } - - /* determine where to display the process name */ - if ((endtime - starttime) < 1.5) - /* too small to fit label inside the box */ - w = endtime; - else - w = starttime; - - /* text label of process name */ - fprintf(of, " %s [%i]%.03fs %s\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 */ - fprintf(of, " \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) - fprintf(of, " \n", - ps->parent->pos_x, - ps_to_graph(j) + 10.0, - ps->parent->pos_x, - ps->parent->pos_y); - } - - j++; /* count boxes */ - - fprintf(of, "\n"); - } - - /* last pass - determine when idle */ - pid = getpid(); - /* make sure we start counting from the point where we actually have - * data: assume that bootchart's first sample is when data started - */ - - ps = ps_first; - while (ps->next_ps) { - ps = ps->next_ps; - if (ps->pid == pid) - break; - } - - /* need to know last node first */ - ps->sample = ps->first; - i = ps->sample->next->sampledata->counter; - - while (ps->sample->next && i<(n_samples-(arg_hz/2))) { - double crt; - double brt; - int c; - int ii; - struct ps_sched_struct *sample_hz; - - ps->sample = ps->sample->next; - sample_hz = ps->sample; - 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 < 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": - * - * if for (hz / 2) we've used less CPU than (interval / 2) ... - * defaults to 4.0%, which experimentally, is where atom idles - */ - if ((crt - brt) < (interval / 2.0)) { - idletime = ps->sample->sampledata->sampletime - graph_start; - fprintf(of, "\n\n", idletime); - fprintf(of, "\n", - time_to_graph(idletime), - -arg_scale_y, - time_to_graph(idletime), - ps_to_graph(pcount) + arg_scale_y); - fprintf(of, "%.01fs\n", - time_to_graph(idletime) + 5.0, - ps_to_graph(pcount) + arg_scale_y, - idletime); - break; - } - - i++; - } -} - -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; - int n, m; - - for (n = 0; n < (int) ELEMENTSOF(top); n++) - top[n] = &emptyps; - - /* walk all ps's and setup ptrs */ - ps = ps_first; - while ((ps = get_next_ps(ps, ps_first))) { - for (n = 0; n < 10; n++) { - if (ps->total <= top[n]->total) - continue; - /* cascade insert */ - for (m = 9; m > n; m--) - top[m] = top[m-1]; - top[n] = ps; - break; - } - } - - fprintf(of, "Top CPU consumers:\n"); - for (n = 0; n < 10; n++) - fprintf(of, "%3.03fs - %s [%d]\n", - 20 + (n * 13), - top[n]->total, - top[n]->name, - top[n]->pid); -} - -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; - int n, m; - - for (n = 0; n < (int) ELEMENTSOF(top); n++) - top[n] = &emptyps; - - /* walk all ps's and setup ptrs */ - ps = ps_first; - 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]; - top[n] = ps; - break; - } - } - - fprintf(of, "Top PSS consumers:\n"); - for (n = 0; n < 10; n++) - fprintf(of, "%dK - %s [%d]\n", - 20 + (n * 13), - top[n]->pss_max, - top[n]->name, - top[n]->pid); -} - -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 r, c; - - sampledata = head; - LIST_FIND_TAIL(link, sampledata, head); - ps = ps_first; - - /* count initcall thread count first */ - 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, ps_first))) { - if (!ps_filter(ps)) - pcount++; - else - pfiltered++; - } - psize = ps_to_graph(pcount) + (arg_scale_y * 2); - - esize = (arg_entropy ? arg_scale_y * 7 : 0); - - /* after this, we can draw the header with proper sizing */ - svg_header(of, head, graph_start, arg_percpu ? n_cpus : 0); - fprintf(of, "\n\n"); - - fprintf(of, "\n"); - svg_io_bi_bar(of, head, n_samples, graph_start, interval); - fprintf(of, "\n\n"); - - fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); - svg_io_bo_bar(of, head, n_samples, graph_start, interval); - fprintf(of, "\n\n"); - - for (c = -1; c < (arg_percpu ? n_cpus : 0); c++) { - offset += 7; - fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); - svg_cpu_bar(of, head, n_cpus, c, graph_start); - fprintf(of, "\n\n"); - - offset += 7; - fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); - svg_wait_bar(of, head, n_cpus, c, graph_start); - fprintf(of, "\n\n"); - } - - if (kcount) { - offset += 7; - fprintf(of, "\n", 400.0 + (arg_scale_y * offset)); - svg_do_initcall(of, head, 0, graph_start); - fprintf(of, "\n\n"); - } - - offset += 7; - fprintf(of, "\n", 400.0 + (arg_scale_y * offset) + ksize); - svg_ps_bars(of, head, n_samples, n_cpus, ps_first, graph_start, interval); - fprintf(of, "\n\n"); - - fprintf(of, "\n"); - r = svg_title(of, build, pscount, log_start, overrun); - fprintf(of, "\n\n"); - - if (r < 0) - return r; - - fprintf(of, "\n"); - svg_top_ten_cpu(of, ps_first); - fprintf(of, "\n\n"); - - if (arg_entropy) { - fprintf(of, "\n", 400.0 + (arg_scale_y * offset) + ksize + psize); - svg_entropy_bar(of, head, graph_start); - fprintf(of, "\n\n"); - } - - if (arg_pss) { - fprintf(of, "\n", 400.0 + (arg_scale_y * offset) + ksize + psize + esize); - svg_pss_graph(of, head, ps_first, graph_start); - fprintf(of, "\n\n"); - - fprintf(of, "\n"); - svg_top_ten_pss(of, ps_first); - fprintf(of, "\n\n"); - } - - /* fprintf footer */ - fprintf(of, "\n\n"); - - return 0; -} diff --git a/src/bootchart/svg.h b/src/bootchart/svg.h deleted file mode 100644 index 6e06b5ad97..0000000000 --- a/src/bootchart/svg.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2009-2013 Intel Corporation - - Authors: - Auke Kok - - 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 . -***/ - -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/systemd/sd-messages.h b/src/systemd/sd-messages.h index 8a72576ec8..3c44d63021 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -82,8 +82,6 @@ _SD_BEGIN_DECLARATIONS; #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) - #define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d) #define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65) #define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57) diff --git a/tools/make-directive-index.py b/tools/make-directive-index.py index 8091683fee..256ff3dc5d 100755 --- a/tools/make-directive-index.py +++ b/tools/make-directive-index.py @@ -131,15 +131,6 @@ TEMPLATE = '''\ - - bootchart.conf directives - - Directives for configuring the behaviour of the - systemd-bootchart process. - - - - command line options diff --git a/units/.gitignore b/units/.gitignore index e62fd01466..47e99154ee 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -22,7 +22,6 @@ /systemd-ask-password-wall.service /systemd-backlight@.service /systemd-binfmt.service -/systemd-bootchart.service /systemd-coredump@.service /systemd-firstboot.service /systemd-fsck-root.service diff --git a/units/systemd-bootchart.service.in b/units/systemd-bootchart.service.in deleted file mode 100644 index 396817f0ce..0000000000 --- a/units/systemd-bootchart.service.in +++ /dev/null @@ -1,20 +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. - -# Note: it's usually a better idea to run systemd-bootchart via the -# init= kernel command line switch. See the man page for details. - -[Unit] -Description=Boot Process Profiler -Documentation=man:systemd-bootchart.service(1) man:bootchart.conf(5) -DefaultDependencies=no - -[Service] -ExecStart=@rootlibexecdir@/systemd-bootchart -r - -[Install] -WantedBy=sysinit.target -- cgit v1.2.3-54-g00ecf From 4c2bb6b3b3cc7a3b88cce0df01fe754b6819f18b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 22 Feb 2016 21:01:39 +0100 Subject: architecture.h: remove PROC_CPUINFO_MODEL This was only needed for bootchart, so it can go now. --- src/basic/architecture.h | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'src') diff --git a/src/basic/architecture.h b/src/basic/architecture.h index 63cf6fb703..c22cbc8279 100644 --- a/src/basic/architecture.h +++ b/src/basic/architecture.h @@ -77,12 +77,10 @@ int uname_architecture(void); #if defined(__x86_64__) # define native_architecture() ARCHITECTURE_X86_64 # define LIB_ARCH_TUPLE "x86_64-linux-gnu" -# define PROC_CPUINFO_MODEL "model name" # define SECONDARY_ARCHITECTURE ARCHITECTURE_X86 #elif defined(__i386__) # define native_architecture() ARCHITECTURE_X86 # define LIB_ARCH_TUPLE "i386-linux-gnu" -# define PROC_CPUINFO_MODEL "model name" #elif defined(__powerpc64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC64 @@ -93,7 +91,6 @@ int uname_architecture(void); # define LIB_ARCH_TUPLE "powerpc64le-linux-gnu" # define SECONDARY_ARCHITECTURE ARCHITECTURE_PPC_LE # endif -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__powerpc__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC @@ -102,18 +99,15 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_PPC_LE # error "Missing LIB_ARCH_TUPLE for PPCLE" # endif -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__ia64__) # define native_architecture() ARCHITECTURE_IA64 # define LIB_ARCH_TUPLE "ia64-linux-gnu" #elif defined(__hppa64__) # define native_architecture() ARCHITECTURE_PARISC64 # error "Missing LIB_ARCH_TUPLE for HPPA64" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__hppa__) # define native_architecture() ARCHITECTURE_PARISC # define LIB_ARCH_TUPLE "hppa‑linux‑gnu" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__s390x__) # define native_architecture() ARCHITECTURE_S390X # define LIB_ARCH_TUPLE "s390x-linux-gnu" @@ -124,11 +118,9 @@ int uname_architecture(void); #elif defined(__sparc64__) # define native_architecture() ARCHITECTURE_SPARC64 # define LIB_ARCH_TUPLE "sparc64-linux-gnu" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__sparc__) # define native_architecture() ARCHITECTURE_SPARC # define LIB_ARCH_TUPLE "sparc-linux-gnu" -# define PROC_CPUINFO_MODEL "cpu" #elif defined(__mips64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS64 @@ -137,7 +129,6 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_MIPS64_LE # error "Missing LIB_ARCH_TUPLE for MIPS64_LE" # endif -# define PROC_CPUINFO_MODEL "cpu model" #elif defined(__mips__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS @@ -146,7 +137,6 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_MIPS_LE # define LIB_ARCH_TUPLE "mipsel-linux-gnu" # endif -# define PROC_CPUINFO_MODEL "cpu model" #elif defined(__alpha__) # define native_architecture() ARCHITECTURE_ALPHA # define LIB_ARCH_TUPLE "alpha-linux-gnu" @@ -182,7 +172,6 @@ int uname_architecture(void); # define LIB_ARCH_TUPLE "arm-linux-gnu" # endif # endif -# define PROC_CPUINFO_MODEL "model name" #elif defined(__sh64__) # define native_architecture() ARCHITECTURE_SH64 # error "Missing LIB_ARCH_TUPLE for SH64" @@ -202,10 +191,5 @@ int uname_architecture(void); # error "Please register your architecture here!" #endif -#ifndef PROC_CPUINFO_MODEL -#warning "PROC_CPUINFO_MODEL not defined for your architecture" -#define PROC_CPUINFO_MODEL "model name" -#endif - const char *architecture_to_string(int a) _const_; int architecture_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From 953d28cc21d25dc61f886d61d628b577aed4e042 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 23 Feb 2016 08:17:19 -0500 Subject: Fix two typos --- src/basic/hostname-util.c | 5 +++-- src/machine/machinectl.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index f900c509a3..5ed98eeb6a 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -48,8 +48,9 @@ bool hostname_is_set(void) { char* gethostname_malloc(void) { struct utsname u; - /* This call tries to return something useful, either the actual hostname or it makes something up. The only - * reason it might mail is OOM. It might even return "localhost" if that's set. */ + /* This call tries to return something useful, either the actual hostname + * or it makes something up. The only reason it might fail is OOM. + * It might even return "localhost" if that's set. */ assert_se(uname(&u) >= 0); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 4853139321..4bb712ca5a 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1763,7 +1763,7 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) { r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { - log_error("Failed transfer image: %s", bus_error_message(&error, -r)); + log_error("Failed to transfer image: %s", bus_error_message(&error, -r)); return r; } -- cgit v1.2.3-54-g00ecf From 6b0132e4e785de7b339da071eb1506adf2362edd Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 23 Feb 2016 08:17:19 -0500 Subject: basic: simplify ether_addr_is_null --- src/basic/ether-addr-util.c | 11 ----------- src/basic/ether-addr-util.h | 7 ++++++- 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index d2c030903b..a4d8d656da 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -43,17 +43,6 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR return buffer; } -bool ether_addr_is_null(const struct ether_addr *addr) { - assert(addr); - - return addr->ether_addr_octet[0] == 0 && - addr->ether_addr_octet[1] == 0 && - addr->ether_addr_octet[2] == 0 && - addr->ether_addr_octet[3] == 0 && - addr->ether_addr_octet[4] == 0 && - addr->ether_addr_octet[5] == 0; -} - bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) { assert(a); assert(b); diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 00c5159fe8..074363793e 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -28,5 +28,10 @@ #define ETHER_ADDR_TO_STRING_MAX (3*6) char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); -bool ether_addr_is_null(const struct ether_addr *addr); bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b); + +#define ETHER_ADDR_NULL ((const struct ether_addr){}) + +static inline bool ether_addr_is_null(const struct ether_addr *addr) { + return ether_addr_equal(addr, ÐER_ADDR_NULL); +} -- cgit v1.2.3-54-g00ecf From 4c3160f1502e5ebad8cb73ae70cdeead2e534997 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 22 Feb 2016 23:23:56 -0500 Subject: networkctl: only print lldp legend for capabilities that were actually seen --- src/network/networkctl.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index d1aec9a7dc..07ac15f478 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -901,10 +901,43 @@ static char *lldp_capabilities_to_string(uint16_t x) { return ret; } +static void lldp_capabilities_legend(uint16_t x) { + unsigned w, i, cols = columns(); + static const char const* table[] = { + "o - Other", + "p - Repeater", + "b - Bridge", + "w - WLAN Access Point", + "r - Router", + "t - Telephone", + "d - DOCSIS cable device", + "a - Station", + "c - Customer VLAN", + "s - Service VLAN", + "m - Two-port MAC Relay (TPMR)", + }; + + if (x == 0) + return; + + printf("\nCapability Flags:\n"); + for (w = 0, i = 0; i < ELEMENTSOF(table); i++) + if (x & (1U << i) || arg_all) { + bool newline; + + newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols; + if (newline) + w = 0; + w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]); + } + puts(""); +} + static int link_lldp_status(int argc, char *argv[], void *userdata) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; int i, r, c, m = 0; + uint16_t all = 0; r = sd_netlink_open(&rtnl); if (r < 0) @@ -982,8 +1015,10 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { port_description = pdesc; } - if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) + if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) { capabilities = lldp_capabilities_to_string(cc); + all |= cc; + } printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", links[i].name, @@ -997,12 +1032,10 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { } } - if (arg_legend) - printf("\nCapability Flags:\n" - "o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;\n" - "t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;\n" - "s - Service VLAN, m - Two-port MAC Relay (TPMR)\n\n" - "%i neighbors listed.\n", m); + if (arg_legend) { + lldp_capabilities_legend(all); + printf("\n%i neighbors listed.\n", m); + } return 0; } -- cgit v1.2.3-54-g00ecf From 5798eb4ccebde4e2f942195e9b4fbc050be3c27e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Feb 2016 13:17:00 +0100 Subject: tests: fix x86 personality tests to only on x86 --- src/test/test-execute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/test-execute.c b/src/test/test-execute.c index d021be4671..0d2e4bfc15 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -91,7 +91,7 @@ static void test_exec_personality(Manager *m) { #elif defined(__s390__) test(m, "exec-personality-s390.service", 0, CLD_EXITED); -#else +#elif defined(__i386__) test(m, "exec-personality-x86.service", 0, CLD_EXITED); #endif } -- cgit v1.2.3-54-g00ecf From 7c9337dae8c27b8ff963412274aa95eaf1ec04a5 Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Tue, 23 Feb 2016 19:21:54 +0100 Subject: basic: mark unused variable as such --- src/basic/signal-util.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index 72b10e8712..a7322ff26a 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -44,9 +44,9 @@ static inline void block_signals_reset(sigset_t *ss) { assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0); } -#define BLOCK_SIGNALS(...) \ - _cleanup_(block_signals_reset) sigset_t _saved_sigset = ({ \ - sigset_t t; \ +#define BLOCK_SIGNALS(...) \ + _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ + sigset_t t; \ assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \ - t; \ + t; \ }) -- cgit v1.2.3-54-g00ecf From 662ea1b14ab2306de8c7793e6283994d695cc09d Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Tue, 23 Feb 2016 20:16:59 +0100 Subject: tree-wide: remove unused variables --- src/libsystemd/sd-network/sd-network.c | 1 - src/resolve/resolved-bus.c | 1 - src/resolve/test-dns-packet.c | 1 - 3 files changed, 3 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 580047d3ab..f8e18f23fd 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -209,7 +209,6 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; - _cleanup_strv_free_ char **a = NULL; _cleanup_free_ int *ifis = NULL; _cleanup_free_ char *s = NULL; size_t allocated = 0, c = 0; diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 214810362d..16cae8c1e5 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1137,7 +1137,6 @@ finish: static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; const char *name, *type, *domain; - _cleanup_free_ char *n = NULL; Manager *m = userdata; int family, ifindex; uint64_t flags; diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index 1abbd3fa2e..c232a69ce1 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -89,7 +89,6 @@ static void test_packet_from_file(const char* filename, bool canonical) { int main(int argc, char **argv) { int i, N; _cleanup_globfree_ glob_t g = {}; - _cleanup_strv_free_ char **globs = NULL; char **fnames; log_parse_environment(); -- cgit v1.2.3-54-g00ecf From 404d53a968147cbb44b3ecf756b0ab4db77d962a Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Tue, 23 Feb 2016 20:25:48 +0100 Subject: networkctl: fix const --- src/network/networkctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 07ac15f478..6b1fbc603e 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -903,7 +903,7 @@ static char *lldp_capabilities_to_string(uint16_t x) { static void lldp_capabilities_legend(uint16_t x) { unsigned w, i, cols = columns(); - static const char const* table[] = { + static const char* const table[] = { "o - Other", "p - Repeater", "b - Bridge", -- cgit v1.2.3-54-g00ecf From 9f63a08d99bf41b51b7c11710b4e3349f10ccc5c Mon Sep 17 00:00:00 2001 From: Stefan Schallenberg aka nafets227 Date: Thu, 18 Feb 2016 21:10:28 +0100 Subject: basic: Debug-logging of Virtualisation detection print out every single detection executed and its result. --- src/basic/virt.c | 52 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/basic/virt.c b/src/basic/virt.c index 79387007f0..8d25a7d2f4 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -98,6 +98,8 @@ static int detect_vm_cpuid(void) { : "0" (eax) ); + log_debug("Virtualization found, CPUID=%s", sig.text); + for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++) if (streq(sig.text, cpuid_vendor_table[j].cpuid)) return cpuid_vendor_table[j].id; @@ -105,6 +107,7 @@ static int detect_vm_cpuid(void) { return VIRTUALIZATION_VM_OTHER; } #endif + log_debug("No virtualization found in CPUID"); return VIRTUALIZATION_NONE; } @@ -121,19 +124,25 @@ static int detect_vm_device_tree(void) { dir = opendir("/proc/device-tree"); if (!dir) { - if (errno == ENOENT) + if (errno == ENOENT) { + log_debug_errno(errno, "/proc/device-tree: %m"); return VIRTUALIZATION_NONE; + } return -errno; } FOREACH_DIRENT(dent, dir, return -errno) - if (strstr(dent->d_name, "fw-cfg")) + if (strstr(dent->d_name, "fw-cfg")) { + log_debug("Virtualization QEMU: \"fw-cfg\" present in /proc/device-tree/%s", dent->d_name); return VIRTUALIZATION_QEMU; + } + log_debug("No virtualization found in /proc/device-tree/*"); return VIRTUALIZATION_NONE; } else if (r < 0) return r; + log_debug("Virtualization %s found in /proc/device-tree/hypervisor/compatible", hvtype); if (streq(hvtype, "linux,kvm")) return VIRTUALIZATION_KVM; else if (strstr(hvtype, "xen")) @@ -141,6 +150,7 @@ static int detect_vm_device_tree(void) { else return VIRTUALIZATION_VM_OTHER; #else + log_debug("This platform does not support /proc/device-tree"); return VIRTUALIZATION_NONE; #endif } @@ -184,12 +194,18 @@ static int detect_vm_dmi(void) { return r; } + + for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++) - if (startswith(s, dmi_vendor_table[j].vendor)) + if (startswith(s, dmi_vendor_table[j].vendor)) { + log_debug("Virtualization %s found in DMI (%s)", s, dmi_vendors[i]); return dmi_vendor_table[j].id; + } } #endif + log_debug("No virtualization found in DMI"); + return VIRTUALIZATION_NONE; } @@ -199,8 +215,10 @@ static int detect_vm_xen(void) { int r; r = read_one_line_file("/proc/xen/capabilities", &domcap); - if (r == -ENOENT) + if (r == -ENOENT) { + log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist"); return VIRTUALIZATION_NONE; + } if (r < 0) return r; @@ -209,7 +227,13 @@ static int detect_vm_xen(void) { if (streq(cap, "control_d")) break; - return cap ? VIRTUALIZATION_NONE : VIRTUALIZATION_XEN; + if (!cap) { + log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)"); + return VIRTUALIZATION_XEN; + } + + log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)"); + return VIRTUALIZATION_NONE; } static int detect_vm_hypervisor(void) { @@ -222,6 +246,8 @@ static int detect_vm_hypervisor(void) { if (r < 0) return r; + log_debug("Virtualization %s found in /sys/hypervisor/type", hvtype); + if (streq(hvtype, "xen")) return VIRTUALIZATION_XEN; else @@ -236,9 +262,13 @@ static int detect_vm_uml(void) { r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL); if (r < 0) return r; - if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) + + if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) { + log_debug("UML virtualization found in /proc/cpuinfo"); return VIRTUALIZATION_UML; + } + log_debug("No virtualization found in /proc/cpuinfo (%s)", cpuinfo_contents); return VIRTUALIZATION_NONE; } @@ -254,11 +284,13 @@ static int detect_vm_zvm(void) { if (r < 0) return r; + log_debug("Virtualization %s found in /proc/sysinfo", t); if (streq(t, "z/VM")) return VIRTUALIZATION_ZVM; else return VIRTUALIZATION_KVM; #else + log_debug("This platform does not support /proc/sysinfo"); return VIRTUALIZATION_NONE; #endif } @@ -327,6 +359,7 @@ int detect_vm(void) { finish: cached_found = r; + log_debug("Found VM virtualization %s", virtualization_to_string(r)); return r; } @@ -414,6 +447,7 @@ int detect_container(void) { r = VIRTUALIZATION_CONTAINER_OTHER; finish: + log_debug("Found container virtualization %s", virtualization_to_string(r)); cached_found = r; return r; } @@ -422,10 +456,10 @@ int detect_virtualization(void) { int r; r = detect_container(); - if (r != 0) - return r; + if (r == 0) + r = detect_vm(); - return detect_vm(); + return r; } int running_in_chroot(void) { -- cgit v1.2.3-54-g00ecf From 3f61278b56d7f97d0325d3bf6c20c32e4fcdb7ff Mon Sep 17 00:00:00 2001 From: Stefan Schallenberg aka nafets227 Date: Tue, 16 Feb 2016 21:36:12 +0100 Subject: basic: Bugfix Detect XEN Dom0 as no virtualization When running in XEN Dom0 the virtualization check: 1) detect_xen returns HYPERVISOR_NONE so next checks are executed 2) /proc/sys/hypervisor detects a XEN hypervisor it is lacking the special Dom0 detection as in detect_xen With this patch, at the end of all virtualization checks we double-check if running in XEN Dom0 or DomU. --- src/basic/virt.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/virt.c b/src/basic/virt.c index 8d25a7d2f4..e6c5a095a0 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -210,6 +210,19 @@ static int detect_vm_dmi(void) { } static int detect_vm_xen(void) { + /* Check for Dom0 will be executed later in detect_vm_xen_dom0 + Thats why we dont check the content of /proc/xen/capabilities here. */ + if (access("/proc/xen/capabilities", F_OK) < 0) { + log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist"); + return VIRTUALIZATION_NONE; + } + + log_debug("Virtualization XEN found (/proc/xen/capabilities exists)"); + return VIRTUALIZATION_XEN; + +} + +static bool detect_vm_xen_dom0(void) { _cleanup_free_ char *domcap = NULL; char *cap, *i; int r; @@ -217,7 +230,7 @@ static int detect_vm_xen(void) { r = read_one_line_file("/proc/xen/capabilities", &domcap); if (r == -ENOENT) { log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist"); - return VIRTUALIZATION_NONE; + return false; } if (r < 0) return r; @@ -226,14 +239,13 @@ static int detect_vm_xen(void) { while ((cap = strsep(&i, ","))) if (streq(cap, "control_d")) break; - if (!cap) { log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)"); - return VIRTUALIZATION_XEN; + return false; } log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)"); - return VIRTUALIZATION_NONE; + return true; } static int detect_vm_hypervisor(void) { @@ -358,6 +370,12 @@ int detect_vm(void) { return r; finish: + /* x86 xen Dom0 is detected as XEN in hypervisor and maybe others. + * In order to detect the Dom0 as not virtualization we need to + * double-check it */ + if (r == VIRTUALIZATION_XEN && detect_vm_xen_dom0()) + r = VIRTUALIZATION_NONE; + cached_found = r; log_debug("Found VM virtualization %s", virtualization_to_string(r)); return r; -- cgit v1.2.3-54-g00ecf From 9ed794a32d4824c6a42fc222ea1054bb3d1394d7 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Tue, 23 Feb 2016 09:52:52 -0800 Subject: tree-wide: minor formatting inconsistency cleanups --- src/analyze/analyze.c | 2 +- src/basic/MurmurHash2.c | 2 +- src/basic/calendarspec.c | 2 +- src/basic/cgroup-util.c | 2 +- src/basic/io-util.h | 2 +- src/basic/list.h | 14 +++++++------- src/basic/log.h | 2 +- src/basic/macro.h | 2 +- src/basic/parse-util.c | 2 +- src/basic/stdio-util.h | 2 +- src/boot/efi/splash.c | 4 ++-- src/core/load-fragment.c | 8 ++++---- src/delta/delta.c | 2 +- src/journal-remote/browse.html | 2 +- src/journal-remote/journal-upload.c | 2 +- src/journal/journal-send.c | 2 +- src/journal/journal-verify.c | 12 ++++++------ src/journal/journald-server.c | 2 +- src/journal/sd-journal.c | 2 +- src/libsystemd-network/network-internal.c | 2 +- src/libsystemd-network/sd-ipv4acd.c | 2 +- src/libsystemd-network/sd-ipv4ll.c | 2 +- src/libsystemd/sd-bus/bus-objects.c | 2 +- src/libsystemd/sd-netlink/netlink-message.c | 4 ++-- src/machine/machine.c | 2 +- src/machine/machined-dbus.c | 2 +- src/network/networkd-fdb.c | 6 +++--- src/network/networkd-ipv4ll.c | 2 +- src/network/networkd-link.c | 4 ++-- src/network/networkd-netdev-tuntap.c | 4 ++-- src/network/networkd-netdev-vxlan.c | 6 +++--- src/nspawn/nspawn.c | 4 ++-- src/resolve/resolved-conf.c | 4 ++-- src/resolve/resolved-dns-packet.c | 4 ++-- src/shared/bus-util.c | 2 +- src/shared/conf-parser.h | 2 +- src/shared/sleep-config.c | 2 +- src/systemctl/systemctl.c | 8 ++++---- src/sysv-generator/sysv-generator.c | 2 +- src/test/test-netlink-manual.c | 6 +++--- src/test/test-path.c | 2 +- src/test/test-unit-file.c | 2 +- src/udev/mtd_probe/probe_smartmedia.c | 2 +- src/udev/udev-builtin-input_id.c | 2 +- src/udev/udevadm-monitor.c | 2 +- src/udev/udevadm-test.c | 2 +- 46 files changed, 76 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index a847084781..6db8e406f8 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -60,7 +60,7 @@ svg(" ", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \ svg(format, ## __VA_ARGS__); \ svg("\n"); \ - } while(false) + } while (false) static enum dot { DEP_ALL, diff --git a/src/basic/MurmurHash2.c b/src/basic/MurmurHash2.c index 2f4149dbe9..9020793930 100644 --- a/src/basic/MurmurHash2.c +++ b/src/basic/MurmurHash2.c @@ -50,7 +50,7 @@ uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) const unsigned char * data = (const unsigned char *)key; - while(len >= 4) + while (len >= 4) { uint32_t k = *(uint32_t*)data; diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index b1f2a511f3..6e0bab9b94 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -114,7 +114,7 @@ static void sort_chain(CalendarComponent **c) { static void fix_year(CalendarComponent *c) { /* Turns 12 → 2012, 89 → 1989 */ - while(c) { + while (c) { CalendarComponent *n = c->next; if (c->value >= 0 && c->value < 70) diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 6ef00d51df..56c1fcaab9 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -1248,7 +1248,7 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) { return 0; } -int cg_path_decode_unit(const char *cgroup, char **unit){ +int cg_path_decode_unit(const char *cgroup, char **unit) { char *c, *s; size_t n; diff --git a/src/basic/io-util.h b/src/basic/io-util.h index 142c940d92..4684ed3bfc 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -46,7 +46,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); char *_s = (char *)(s); \ _i->iov_base = _s; \ _i->iov_len = strlen(_s); \ - } while(false) + } while (false) static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { unsigned j; diff --git a/src/basic/list.h b/src/basic/list.h index c68185f587..5962aa4211 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -32,7 +32,7 @@ #define LIST_HEAD_INIT(head) \ do { \ (head) = NULL; } \ - while(false) + while (false) /* Initialize a list item */ #define LIST_INIT(name,item) \ @@ -40,7 +40,7 @@ typeof(*(item)) *_item = (item); \ assert(_item); \ _item->name##_prev = _item->name##_next = NULL; \ - } while(false) + } while (false) /* Prepend an item to the list */ #define LIST_PREPEND(name,head,item) \ @@ -51,7 +51,7 @@ _item->name##_next->name##_prev = _item; \ _item->name##_prev = NULL; \ *_head = _item; \ - } while(false) + } while (false) /* Append an item to the list */ #define LIST_APPEND(name,head,item) \ @@ -59,7 +59,7 @@ typeof(*(head)) *_tail; \ LIST_FIND_TAIL(name,head,_tail); \ LIST_INSERT_AFTER(name,head,_tail,item); \ - } while(false) + } while (false) /* Remove an item from the list */ #define LIST_REMOVE(name,head,item) \ @@ -75,7 +75,7 @@ *_head = _item->name##_next; \ } \ _item->name##_next = _item->name##_prev = NULL; \ - } while(false) + } while (false) /* Find the head of the list */ #define LIST_FIND_HEAD(name,item,head) \ @@ -119,7 +119,7 @@ _b->name##_prev = _a; \ _a->name##_next = _b; \ } \ - } while(false) + } while (false) /* Insert an item before another one (a = where, b = what) */ #define LIST_INSERT_BEFORE(name,head,a,b) \ @@ -145,7 +145,7 @@ _b->name##_next = _a; \ _a->name##_prev = _b; \ } \ - } while(false) + } while (false) #define LIST_JUST_US(name,item) \ (!(item)->name##_prev && !(item)->name##_next) \ diff --git a/src/basic/log.h b/src/basic/log.h index 60ddead74c..f9fb1742a1 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -193,7 +193,7 @@ void log_assert_failed_return( #ifdef LOG_TRACE # define log_trace(...) log_debug(__VA_ARGS__) #else -# define log_trace(...) do {} while(0) +# define log_trace(...) do {} while (0) #endif /* Structured logging */ diff --git a/src/basic/macro.h b/src/basic/macro.h index 2695d0edb7..ddf0968d1b 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -224,7 +224,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { /* We override the glibc assert() here. */ #undef assert #ifdef NDEBUG -#define assert(expr) do {} while(false) +#define assert(expr) do {} while (false) #else #define assert(expr) assert_message_se(expr, #expr) #endif diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index a3cb81b040..6c11b605a9 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -505,7 +505,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { s = *p; /* accept any number of digits, strtoull is limted to 19 */ - for(i=0; i < digits; i++,s++) { + for (i=0; i < digits; i++,s++) { if (*s < '0' || *s > '9') { if (i == 0) return -EINVAL; diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h index 0a675571ff..bd1144b4c9 100644 --- a/src/basic/stdio-util.h +++ b/src/basic/stdio-util.h @@ -73,4 +73,4 @@ do { \ assert_not_reached("Unknown format string argument."); \ } \ } \ -} while(false) +} while (false) diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c index b1cc2c0b72..c0ef7f64fe 100644 --- a/src/boot/efi/splash.c +++ b/src/boot/efi/splash.c @@ -281,9 +281,9 @@ EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_ if (EFI_ERROR(err)) goto err; - if(dib->x < GraphicsOutput->Mode->Info->HorizontalResolution) + if (dib->x < GraphicsOutput->Mode->Info->HorizontalResolution) x_pos = (GraphicsOutput->Mode->Info->HorizontalResolution - dib->x) / 2; - if(dib->y < GraphicsOutput->Mode->Info->VerticalResolution) + if (dib->y < GraphicsOutput->Mode->Info->VerticalResolution) y_pos = (GraphicsOutput->Mode->Info->VerticalResolution - dib->y) / 2; uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput, diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 3eeb904d7e..e1bfdccbca 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -119,7 +119,7 @@ int config_parse_unit_deps( assert(rvalue); p = rvalue; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL, *k = NULL; int r; @@ -1599,7 +1599,7 @@ int config_parse_service_sockets( assert(data); p = rvalue; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL, *k = NULL; r = extract_first_word(&p, &word, NULL, 0); @@ -3361,7 +3361,7 @@ int config_parse_protect_home( ProtectHome h; h = protect_home_from_string(rvalue); - if (h < 0){ + if (h < 0) { log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue); return 0; } @@ -3404,7 +3404,7 @@ int config_parse_protect_system( ProtectSystem s; s = protect_system_from_string(rvalue); - if (s < 0){ + if (s < 0) { log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue); return 0; } diff --git a/src/delta/delta.c b/src/delta/delta.c index a54fc89de6..202a030c54 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -431,7 +431,7 @@ finish: hashmap_free_free(top); hashmap_free_free(bottom); - HASHMAP_FOREACH_KEY(h, key, drops, i){ + HASHMAP_FOREACH_KEY(h, key, drops, i) { hashmap_free_free(hashmap_remove(drops, key)); hashmap_remove(drops, key); free(key); diff --git a/src/journal-remote/browse.html b/src/journal-remote/browse.html index 3594f70c87..32848c7673 100644 --- a/src/journal-remote/browse.html +++ b/src/journal-remote/browse.html @@ -391,7 +391,7 @@ entry = document.getElementById("tableentry"); var buf = ""; - for (var key in d){ + for (var key in d) { var data = d[key]; if (data == null) diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 440563e7d3..6e1c3bb9ef 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -75,7 +75,7 @@ static void close_fd_input(Uploader *u); curl_easy_strerror(code)); \ cmd; \ } \ - } while(0) + } while (0) static size_t output_callback(char *buf, size_t size, diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index c7d670f4ff..a79846146a 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -50,7 +50,7 @@ *_f = alloca(_fl + 10); \ memcpy(*_f, "CODE_FUNC=", 10); \ memcpy(*_f + 10, _func, _fl); \ - } while(false) + } while (false) /* We open a single fd, and we'll share it with the current process, * all its threads, and all its subprocesses. This means we need to diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 7a35776eaa..a1241c9bcf 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -97,20 +97,20 @@ static void flush_progress(void) { fflush(stdout); } -#define debug(_offset, _fmt, ...) do{ \ +#define debug(_offset, _fmt, ...) do { \ flush_progress(); \ log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \ - } while(0) + } while (0) -#define warning(_offset, _fmt, ...) do{ \ +#define warning(_offset, _fmt, ...) do { \ flush_progress(); \ log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \ - } while(0) + } while (0) -#define error(_offset, _fmt, ...) do{ \ +#define error(_offset, _fmt, ...) do { \ flush_progress(); \ log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \ - } while(0) + } while (0) static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) { uint64_t i; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index d5937bd013..2939322925 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1407,7 +1407,7 @@ static int server_parse_proc_cmdline(Server *s) { } p = line; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&p, &word, NULL, 0); diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 3ba4981cd4..ac75e39312 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1063,7 +1063,7 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { if (r < 0) return r; - for(;;) { + for (;;) { _cleanup_free_ char *item = NULL; unsigned long long ll; sd_id128_t id; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index abf3b157d0..cb7252bbeb 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -482,7 +482,7 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t return -ENOMEM; entry = strndup(word, len); - if(!entry) + if (!entry) return -ENOMEM; tok = entry; diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 8a26cb8770..cc7436db6b 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -456,7 +456,7 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *user return 0; } -int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){ +int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address) { assert_return(ll, -EINVAL); assert_return(address, -EINVAL); assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index aca393aa5e..2a06418c53 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -181,7 +181,7 @@ int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdat return 0; } -int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){ +int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) { assert_return(ll, -EINVAL); assert_return(address, -EINVAL); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 3c189b30ec..9bd07ffcab 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -145,7 +145,7 @@ static int add_enumerated_to_set( continue; } - if (!object_path_is_valid(*k)){ + if (!object_path_is_valid(*k)) { free(*k); r = -EINVAL; continue; diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 2ce50edc7e..3924300817 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -528,7 +528,7 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t attribute = &m->containers[m->n_containers].attributes[type]; - if(!attribute->offset) + if (!attribute->offset) return -ENODATA; rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset); @@ -735,7 +735,7 @@ static int netlink_container_parse(sd_netlink_message *m, _cleanup_free_ struct netlink_attribute *attributes = NULL; attributes = new0(struct netlink_attribute, count); - if(!attributes) + if (!attributes) return -ENOMEM; for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) { diff --git a/src/machine/machine.c b/src/machine/machine.c index 7a7a1bb42b..7d4270a8ff 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -310,7 +310,7 @@ int machine_load(Machine *m) { int *ni = NULL; p = netif; - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; int ifi; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index b933099330..20894433e7 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -1212,7 +1212,7 @@ int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_err r = unit_name_from_dbus_path(path, &unit); if (r == -EINVAL) /* not for a unit */ return 0; - if (r < 0){ + if (r < 0) { log_oom(); return 0; } diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 1538caa204..241f486211 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -37,7 +37,7 @@ int fdb_entry_new_static(Network *const network, assert(network); /* search entry in hashmap first. */ - if(section) { + if (section) { fdb_entry = hashmap_get(network->fdb_entries_by_section, UINT_TO_PTR(section)); if (fdb_entry) { *ret = fdb_entry; @@ -141,10 +141,10 @@ int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) { /* remove and FDB entry. */ void fdb_entry_free(FdbEntry *fdb_entry) { - if(!fdb_entry) + if (!fdb_entry) return; - if(fdb_entry->network) { + if (fdb_entry->network) { LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry); diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 949c75337c..e05fd3eea7 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -165,7 +165,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { return 0; } -static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){ +static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) { Link *link = userdata; int r; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a4652ba9c9..ff4bd76554 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1031,7 +1031,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) { + if (r < 0) { log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m"); break; } @@ -1836,7 +1836,7 @@ static int link_joined(Link *link) { } } - if(link->network->bridge) { + if (link->network->bridge) { r = link_set_bridge(link); if (r < 0) log_link_error_errno(link, r, "Could not set bridge message: %m"); diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index cdf443862d..32917fe6d5 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -88,7 +88,7 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) { assert(t); - if(t->user_name) { + if (t->user_name) { user = t->user_name; @@ -127,7 +127,7 @@ static int netdev_create_tuntap(NetDev *netdev) { int r; r = netdev_fill_tuntap_message(netdev, &ifr); - if(r < 0) + if (r < 0) return r; return netdev_tuntap_add(netdev, &ifr); diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index eb9a2c06b3..dabbd97c87 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -54,13 +54,13 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m"); - if(v->ttl) { + if (v->ttl) { r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m"); } - if(v->tos) { + if (v->tos) { r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m"); @@ -86,7 +86,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m"); - if(v->fdb_ageing) { + if (v->fdb_ageing) { r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m"); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ce3695eaf6..4851c439c9 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -561,7 +561,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_CAPABILITY: case ARG_DROP_CAPABILITY: { p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *t = NULL; r = extract_first_word(&p, &t, ",", 0); @@ -3618,7 +3618,7 @@ int main(int argc, char *argv[]) { /* We failed to wait for the container, or the * container exited abnormally */ goto finish; - else if (r > 0 || container_status == CONTAINER_TERMINATED){ + else if (r > 0 || container_status == CONTAINER_TERMINATED) { /* The container exited with a non-zero * status, or with zero status and no reboot * was requested. */ diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index bb93fbfda2..990dc03b60 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -59,7 +59,7 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con assert(m); assert(string); - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&string, &word, NULL, 0); @@ -114,7 +114,7 @@ int manager_parse_search_domains_and_warn(Manager *m, const char *string) { assert(m); assert(string); - for(;;) { + for (;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 64913da573..b7907bb511 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -38,8 +38,8 @@ static void rewind_dns_packet(DnsPacketRewinder *rewinder) { dns_packet_rewind(rewinder->packet, rewinder->saved_rindex); } -#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while(0) -#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while(0) +#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while (0) +#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while (0) int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 0776311837..b102a79da8 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -843,7 +843,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) { + while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) { _cleanup_free_ char *escaped = NULL; if (first) diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index a91c94c322..73fb132413 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -178,7 +178,7 @@ int config_parse_personality(const char *unit, const char *filename, unsigned li assert(data); \ \ xs = new0(type, 1); \ - if(!xs) \ + if (!xs) \ return -ENOMEM; \ \ *xs = invalid; \ diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index a0aef66bc8..35aa60101f 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -37,7 +37,7 @@ #include "string-util.h" #include "strv.h" -#define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0) +#define USE(x, y) do { (x) = (y); (y) = NULL; } while (0) int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 7774506a1e..b3060d4650 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1484,7 +1484,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); } - if (arg_full){ + if (arg_full) { printf("%s\n", name); return 0; } @@ -6550,7 +6550,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *type = NULL; r = extract_first_word(&p, &type, ",", 0); @@ -6600,7 +6600,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return log_oom(); } else { p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *prop = NULL; r = extract_first_word(&p, &prop, ",", 0); @@ -6785,7 +6785,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } p = optarg; - for(;;) { + for (;;) { _cleanup_free_ char *s = NULL; r = extract_first_word(&p, &s, ",", 0); diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index b5925a47dc..59e1a3e921 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -864,7 +864,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic } service = hashmap_get(all_services, name); - if (!service){ + if (!service) { log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name); continue; } diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c index 79ff6ae74d..bc6dd0926c 100644 --- a/src/test/test-netlink-manual.c +++ b/src/test/test-netlink-manual.c @@ -68,10 +68,10 @@ static int test_tunnel_configure(sd_netlink *rtnl) { /* skip test if module cannot be loaded */ r = load_module("ipip"); - if(r < 0) + if (r < 0) return EXIT_TEST_SKIP; - if(getuid() != 0) + if (getuid() != 0) return EXIT_TEST_SKIP; /* IPIP tunnel */ @@ -99,7 +99,7 @@ static int test_tunnel_configure(sd_netlink *rtnl) { assert_se((m = sd_netlink_message_unref(m)) == NULL); r = load_module("sit"); - if(r < 0) + if (r < 0) return EXIT_TEST_SKIP; /* sit */ diff --git a/src/test/test-path.c b/src/test/test-path.c index 7a3b145414..1e704a03dc 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -93,7 +93,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con ts = now(CLOCK_MONOTONIC); /* We process events until the service related to the path has been successfully started */ - while(service->result != SERVICE_SUCCESS || service->state != SERVICE_START) { + while (service->result != SERVICE_SUCCESS || service->state != SERVICE_START) { usec_t n; int r; diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index b0c343590d..cc6c61ba63 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -606,7 +606,7 @@ static void test_install_printf(void) { } else assert_se(t == NULL); \ strcpy(i.name, d1); \ strcpy(i.path, d2); \ - } while(false) + } while (false) expect(i, "%n", "name.service"); expect(i, "%N", "name"); diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c index 6a6c5522a7..2a7ba17637 100644 --- a/src/udev/mtd_probe/probe_smartmedia.c +++ b/src/udev/mtd_probe/probe_smartmedia.c @@ -73,7 +73,7 @@ void probe_smart_media(int mtd_fd, mtd_info_t* info) for (offset = 0 ; offset < block_size * spare_count ; offset += sector_size) { lseek(mtd_fd, SEEK_SET, offset); - if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE){ + if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE) { cis_found = 1; break; } diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index 3a3d8a1770..51a55cdbc4 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -177,7 +177,7 @@ static bool test_pointers(struct udev_device *dev, 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)) + 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); diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index f9cb5e63a2..b5f7f0d512 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -100,7 +100,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) { udev_list_init(udev, &subsystem_match_list, true); udev_list_init(udev, &tag_match_list, true); - while((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0) switch (c) { case 'p': case 'e': diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index ff427cf292..702dbe5282 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -61,7 +61,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) { log_debug("version %s", VERSION); - while((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0) switch (c) { case 'a': action = optarg; -- cgit v1.2.3-54-g00ecf From a915abf35a6e43d2a0cacf62f2b4a8432a2358d8 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Tue, 23 Feb 2016 20:15:23 -0800 Subject: dnssec: only run tests that require gcrypt if we have it --- src/resolve/test-dnssec.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index a093d86a91..c9b5ffa62b 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -327,10 +327,12 @@ static void test_dnssec_nsec3_hash(void) { int main(int argc, char*argv[]) { test_dnssec_canonicalize(); +#ifdef HAVE_GCRYPT test_dnssec_verify_dns_key(); test_dnssec_verify_rrset(); test_dnssec_verify_rrset2(); test_dnssec_nsec3_hash(); +#endif return 0; } -- cgit v1.2.3-54-g00ecf From 96d490114900686b4d17f9b751fab6e39cfcc560 Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Mon, 8 Feb 2016 13:27:22 +0100 Subject: treewide: fix typos and then/that use --- CODING_STYLE | 2 +- NEWS | 2 +- man/systemd.netdev.xml | 2 +- src/basic/socket-util.c | 2 +- src/libsystemd/sd-daemon/sd-daemon.c | 2 +- src/resolve/resolved-dns-answer.c | 2 +- src/resolve/resolved-dns-rr.h | 2 +- src/shared/condition.c | 2 +- src/shared/gcrypt-util.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/CODING_STYLE b/CODING_STYLE index 46e366898e..e5ba396368 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -163,7 +163,7 @@ programming error with assert_return() and return a sensible return code. In all other calls, it is recommended to check for programming errors with a more brutal assert(). We are more forgiving to public - users then for ourselves! Note that assert() and assert_return() + users than for ourselves! Note that assert() and assert_return() really only should be used for detecting programming errors, not for runtime errors. assert() and assert_return() by usage of _likely_() inform the compiler that he should not expect these checks to fail, diff --git a/NEWS b/NEWS index 0cce79443b..8b30bee6b7 100644 --- a/NEWS +++ b/NEWS @@ -11,7 +11,7 @@ CHANGES WITH 230 in spe: interested in collecting feedback about the DNSSEC validator and its limitations in the wild. Note however, that DNSSEC support is probably nothing downstreams should turn on in stable distros just - yet, as it might create incompabilities with a few DNS servers and + yet, as it might create incompatibilities with a few DNS servers and networks. We tried hard to make sure we downgrade to non-DNSSEC mode automatically whenever we detect such incompatible setups, but there might be systems we do not cover yet. Hence: please help us testing diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index b697d0c9a6..c5fb2fa7fb 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -361,7 +361,7 @@ The [MACVTAP] section applies for netdevs of kind macvtap and accepts the - same key as [MACVLAN]. + same key as [MACVLAN]. diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 58512686e3..0f38f9a0f3 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -942,7 +942,7 @@ ssize_t next_datagram_size_fd(int fd) { int k; /* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will - * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD dosn't + * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD doesn't * do. This difference is actually of major importance as we need to be sure that the size returned here * actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of * the wrong size. */ diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 4e50b61979..bd1c7f15ff 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -465,7 +465,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char have_pid = pid != 0 && pid != getpid(); if (n_fds > 0 || have_pid) { - /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */ + /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */ msghdr.msg_controllen = (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0); diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 5d7b4b4b5c..0dadf8b1dd 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -757,7 +757,7 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free) { assert(a); /* Tries to extend the DnsAnswer object. And if that's not - * possibly, since we are not the sole owner, then allocate a + * possible, since we are not the sole owner, then allocate a * new, appropriately sized one. Either way, after this call * the object will only have a single reference, and has room * for at least the specified number of RRs. */ diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 646e34598d..020a2abd77 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -82,7 +82,7 @@ enum { struct DnsResourceKey { unsigned n_ref; /* (unsigned -1) for const keys, see below */ uint16_t class, type; - char *_name; /* don't access directy, use dns_resource_key_name()! */ + char *_name; /* don't access directly, use dns_resource_key_name()! */ }; /* Creates a temporary resource key. This is only useful to quickly diff --git a/src/shared/condition.c b/src/shared/condition.c index f93785865e..3a45ed265c 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -295,7 +295,7 @@ static int condition_test_needs_update(Condition *c) { return false; /* Any other failure means we should allow the condition to be true, - * so that we rather invoke too many update tools then too + * so that we rather invoke too many update tools than too * few. */ if (!path_is_absolute(c->parameter)) diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c index b887243849..4ff94520c3 100644 --- a/src/shared/gcrypt-util.c +++ b/src/shared/gcrypt-util.c @@ -32,7 +32,7 @@ void initialize_libgcrypt(bool secmem) { p = gcry_check_version("1.4.5"); assert(p); - /* Turn off "secmem". Clients which whish to make use of this + /* Turn off "secmem". Clients which wish to make use of this * feature should initialize the library manually */ if (!secmem) gcry_control(GCRYCTL_DISABLE_SECMEM); -- cgit v1.2.3-54-g00ecf From 8eb7b6a595752b1ef1029717444bd4edccf878a8 Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Thu, 25 Feb 2016 15:36:40 +0200 Subject: sd-dhcp-server: Send replies to BOOTP relay server port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RFC 2131 Section 4.1 says that "If the ’giaddr’ field in a DHCP message from a client is non-zero, the server sends any return messages to the ’DHCP server’ port on the BOOTP relay agent whose address appears in ’giaddr’." Fix this by adding a destination port when sending unicast UDP packets and provide the server port when a BOOTP relay agent is being used. --- src/libsystemd-network/sd-dhcp-server.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 1c408aaaac..9adf8ec19d 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -280,10 +280,11 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server, } static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination, + uint16_t destination_port, DHCPMessage *message, size_t len) { union sockaddr_union dest = { .in.sin_family = AF_INET, - .in.sin_port = htobe16(DHCP_PORT_CLIENT), + .in.sin_port = htobe16(destination_port), .in.sin_addr.s_addr = destination, }; struct iovec iov = { @@ -342,6 +343,7 @@ int dhcp_server_send_packet(sd_dhcp_server *server, DHCPRequest *req, DHCPPacket *packet, int type, size_t optoffset) { be32_t destination = INADDR_ANY; + uint16_t destination_port = DHCP_PORT_CLIENT; int r; assert(server); @@ -386,17 +388,19 @@ int dhcp_server_send_packet(sd_dhcp_server *server, */ if (req->message->giaddr) { destination = req->message->giaddr; + destination_port = DHCP_PORT_SERVER; if (type == DHCP_NAK) packet->dhcp.flags = htobe16(0x8000); } else if (req->message->ciaddr && type != DHCP_NAK) destination = req->message->ciaddr; if (destination != INADDR_ANY) - return dhcp_server_send_udp(server, destination, &packet->dhcp, + return dhcp_server_send_udp(server, destination, + destination_port, &packet->dhcp, sizeof(DHCPMessage) + optoffset); else if (requested_broadcast(req) || type == DHCP_NAK) return dhcp_server_send_udp(server, INADDR_BROADCAST, - &packet->dhcp, + destination_port, &packet->dhcp, sizeof(DHCPMessage) + optoffset); else /* we cannot send UDP packet to specific MAC address when the @@ -579,7 +583,8 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN); - r = dhcp_server_send_udp(server, address, &packet->dhcp, + r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT, + &packet->dhcp, sizeof(DHCPMessage) + optoffset); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From ea4b98e6577ad4311e4eb4d2384c82f0d870b5ba Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sat, 20 Feb 2016 00:25:13 +0600 Subject: tree-wide: merge pager_open_if_enabled() to the pager_open() Many subsystems define own pager_open_if_enabled() function which checks '--no-pager' command line argument and open pager depends on its value. All implementations of pager_open_if_enabled() are the same. Let's merger this function with pager_open() from the shared/pager.c and remove pager_open_if_enabled() from all subsytems to prevent code duplication. --- src/analyze/analyze.c | 16 ++++------------ src/cgls/cgls.c | 2 +- src/core/main.c | 17 +++-------------- src/coredump/coredumpctl.c | 6 ++---- src/delta/delta.c | 10 +--------- src/journal/journalctl.c | 16 ++++------------ src/libsystemd/sd-bus/busctl.c | 25 ++++++++----------------- src/locale/localectl.c | 14 +++----------- src/login/loginctl.c | 20 ++++++-------------- src/machine/machinectl.c | 18 +++++------------- src/network/networkctl.c | 14 +++----------- src/shared/pager.c | 5 ++++- src/shared/pager.h | 2 +- src/systemctl/systemctl.c | 36 ++++++++++++++---------------------- src/timedate/timedatectl.c | 10 +--------- 15 files changed, 60 insertions(+), 151 deletions(-) (limited to 'src') diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index a847084781..9479d4584d 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -123,14 +123,6 @@ struct host_info { char *architecture; }; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -965,7 +957,7 @@ static int analyze_critical_chain(sd_bus *bus, char *names[]) { } unit_times_hashmap = h; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); puts("The time after the unit is active or started is printed after the \"@\" character.\n" "The time the unit takes to start is printed after the \"+\" character.\n"); @@ -993,7 +985,7 @@ static int analyze_blame(sd_bus *bus) { qsort(times, n, sizeof(struct unit_times), compare_unit_time); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); for (i = 0; i < (unsigned) n; i++) { char ts[FORMAT_TIMESPAN_MAX]; @@ -1206,7 +1198,7 @@ static int dump(sd_bus *bus, char **args) { return -E2BIG; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -1284,7 +1276,7 @@ static int set_log_target(sd_bus *bus, char **args) { static void help(void) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); printf("%s [OPTIONS...] {COMMAND} ...\n\n" "Profile systemd, show unit dependencies, check unit files.\n\n" diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index b839fadd04..d6fb10cac5 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) { goto finish; if (!arg_no_pager) { - r = pager_open(false); + r = pager_open(arg_no_pager, false); if (r > 0 && arg_full < 0) arg_full = true; } diff --git a/src/core/main.c b/src/core/main.c index c725a686f1..3499c2a3d0 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -102,7 +102,7 @@ static bool arg_crash_reboot = false; static bool arg_confirm_spawn = false; static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; static bool arg_switched_root = false; -static int arg_no_pager = -1; +static bool arg_no_pager = false; static char ***arg_join_controllers = NULL; static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL; static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT; @@ -127,14 +127,6 @@ static bool arg_default_tasks_accounting = true; static uint64_t arg_default_tasks_max = UINT64_C(512); static sd_id128_t arg_machine_id = {}; -static void pager_open_if_enabled(void) { - - if (arg_no_pager <= 0) - return; - - pager_open(false); -} - noreturn static void freeze_or_reboot(void) { if (arg_crash_reboot) { @@ -883,8 +875,6 @@ static int parse_argv(int argc, char *argv[]) { case ARG_TEST: arg_action = ACTION_TEST; - if (arg_no_pager < 0) - arg_no_pager = true; break; case ARG_NO_PAGER: @@ -994,8 +984,6 @@ static int parse_argv(int argc, char *argv[]) { case 'h': arg_action = ACTION_HELP; - if (arg_no_pager < 0) - arg_no_pager = true; break; case 'D': @@ -1548,7 +1536,8 @@ int main(int argc, char *argv[]) { if (arg_action == ACTION_TEST) skip_setup = true; - pager_open_if_enabled(); + if (arg_action == ACTION_TEST || arg_action == ACTION_HELP) + pager_open(arg_no_pager, false); if (arg_action == ACTION_HELP) { retval = help(); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 0034a1a0ac..dac800ebef 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -54,7 +54,7 @@ static enum { } arg_action = ACTION_LIST; static const char* arg_field = NULL; static const char *arg_directory = NULL; -static int arg_no_pager = false; +static bool arg_no_pager = false; static int arg_no_legend = false; static int arg_one = false; static FILE* arg_output = NULL; @@ -852,9 +852,7 @@ int main(int argc, char *argv[]) { case ACTION_LIST: case ACTION_INFO: - if (!arg_no_pager) - pager_open(false); - + pager_open(arg_no_pager, false); r = dump_list(j); break; diff --git a/src/delta/delta.c b/src/delta/delta.c index a54fc89de6..b055075e55 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -85,14 +85,6 @@ static enum { (SHOW_MASKED | SHOW_EQUIVALENT | SHOW_REDIRECTED | SHOW_OVERRIDDEN | SHOW_EXTENDED) } arg_flags = 0; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static int equivalent(const char *a, const char *b) { _cleanup_free_ char *x = NULL, *y = NULL; @@ -610,7 +602,7 @@ int main(int argc, char *argv[]) { else if (arg_diff) arg_flags |= SHOW_OVERRIDDEN; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (optind < argc) { int i; diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 273242bea6..c111b1f0e1 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -225,14 +225,6 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) { return 0; } -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(arg_pager_end); -} - static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) { if (arg_utc) @@ -278,7 +270,7 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset static void help(void) { - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); printf("%s [OPTIONS...] [MATCHES...]\n\n" "Query the journal.\n\n" @@ -1183,7 +1175,7 @@ static int list_boots(sd_journal *j) { if (count == 0) return count; - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); /* numbers are one less, but we need an extra char for the sign */ w = DECIMAL_STR_WIDTH(count - 1) + 1; @@ -2061,7 +2053,7 @@ int main(int argc, char *argv[]) { } else { bool oneline = arg_action == ACTION_LIST_CATALOG; - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); if (optind < argc) r = catalog_list_items(stdout, database, oneline, argv + optind); @@ -2368,7 +2360,7 @@ int main(int argc, char *argv[]) { } if (!arg_follow) - pager_open_if_enabled(); + pager_open(arg_no_pager, arg_pager_end); if (!arg_quiet) { usec_t start, end; diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 772ab62d5b..56bd5863a8 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -62,15 +62,6 @@ static bool arg_allow_interactive_authorization = true; static bool arg_augment_creds = true; static usec_t arg_timeout = 0; -static void pager_open_if_enabled(void) { - - /* Cache result before we open the pager */ - if (arg_no_pager) - return; - - pager_open(false); -} - #define NAME_IS_ACQUIRED INT_TO_PTR(1) #define NAME_IS_ACTIVATABLE INT_TO_PTR(2) @@ -95,7 +86,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { if (r < 0) return log_error_errno(r, "Failed to list names: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); names = hashmap_new(&string_hash_ops); if (!names) @@ -289,7 +280,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) { static void print_tree(const char *prefix, char **l) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); prefix = strempty(prefix); @@ -409,7 +400,7 @@ static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool m p = NULL; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); l = set_get_strv(done); if (!l) @@ -438,7 +429,7 @@ static int tree(sd_bus *bus, char **argv) { if (r < 0) return log_error_errno(r, "Failed to get name list: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); STRV_FOREACH(i, names) { int q; @@ -468,7 +459,7 @@ static int tree(sd_bus *bus, char **argv) { printf("\n"); if (argv[2]) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); } @@ -992,7 +983,7 @@ static int introspect(sd_bus *bus, char **argv) { return bus_log_parse_error(r); } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); name_width = strlen("NAME"); type_width = strlen("TYPE"); @@ -1559,7 +1550,7 @@ static int call(sd_bus *bus, char *argv[]) { if (r == 0 && !arg_quiet) { if (arg_verbose) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = bus_message_dump(reply, stdout, 0); if (r < 0) @@ -1614,7 +1605,7 @@ static int get_property(sd_bus *bus, char *argv[]) { return bus_log_parse_error(r); if (arg_verbose) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY); if (r < 0) diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 365c79aa51..cde33bdf41 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -46,14 +46,6 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; static char *arg_host = NULL; static bool arg_convert = true; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -239,7 +231,7 @@ static int list_locales(sd_bus *bus, char **args, unsigned n) { if (r < 0) return log_error_errno(r, "Failed to read list of locales: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(l); return 0; @@ -341,7 +333,7 @@ static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) { strv_sort(l); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(l); @@ -479,7 +471,7 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) { strv_sort(list); strv_uniq(list); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(list); return 0; diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 6ad3d089bd..c9a5cd796b 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -59,14 +59,6 @@ static bool arg_ask_password = true; static unsigned arg_lines = 10; static OutputMode arg_output = OUTPUT_SHORT; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -101,7 +93,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) { assert(bus); assert(argv); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -148,7 +140,7 @@ static int list_users(int argc, char *argv[], void *userdata) { assert(bus); assert(argv); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -194,7 +186,7 @@ static int list_seats(int argc, char *argv[], void *userdata) { assert(bus); assert(argv); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -858,7 +850,7 @@ static int show_session(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { /* If not argument is specified inspect the manager @@ -914,7 +906,7 @@ static int show_user(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { /* If not argument is specified inspect the manager @@ -974,7 +966,7 @@ static int show_seat(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { /* If not argument is specified inspect the manager diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 4853139321..b756603f3d 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -80,14 +80,6 @@ static const char* arg_format = NULL; static const char *arg_uid = NULL; static char **arg_setenv = NULL; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -135,7 +127,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { assert(bus); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -238,7 +230,7 @@ static int list_images(int argc, char *argv[], void *userdata) { assert(bus); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -707,7 +699,7 @@ static int show_machine(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (properties && argc <= 1) { @@ -956,7 +948,7 @@ static int show_image(int argc, char *argv[], void *userdata) { properties = !strstr(argv[0], "status"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (argc <= 1) { @@ -2189,7 +2181,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { double progress; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, diff --git a/src/network/networkctl.c b/src/network/networkctl.c index d1aec9a7dc..1eaaeb6009 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -53,14 +53,6 @@ static bool arg_no_pager = false; static bool arg_legend = true; static bool arg_all = false; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) { const char *t; char *p; @@ -300,7 +292,7 @@ static int list_links(int argc, char *argv[], void *userdata) { if (c < 0) return c; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (arg_legend) printf("%3s %-16s %-18s %-11s %-10s\n", @@ -854,7 +846,7 @@ static int link_status(int argc, char *argv[], void *userdata) { _cleanup_free_ LinkInfo *links = NULL; int r, c, i; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_netlink_open(&rtnl); if (r < 0) @@ -917,7 +909,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { if (c < 0) return c; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (arg_legend) printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", diff --git a/src/shared/pager.c b/src/shared/pager.c index 05b2b15e40..c16bc027be 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -52,11 +52,14 @@ noreturn static void pager_fallback(void) { _exit(EXIT_SUCCESS); } -int pager_open(bool jump_to_end) { +int pager_open(bool no_pager, bool jump_to_end) { _cleanup_close_pair_ int fd[2] = { -1, -1 }; const char *pager; pid_t parent_pid; + if (no_pager) + return 0; + if (pager_pid > 0) return 1; diff --git a/src/shared/pager.h b/src/shared/pager.h index 9fb05796bb..893e1d2bb6 100644 --- a/src/shared/pager.h +++ b/src/shared/pager.h @@ -23,7 +23,7 @@ #include "macro.h" -int pager_open(bool jump_to_end); +int pager_open(bool no_pager, bool jump_to_end); void pager_close(void); bool pager_have(void) _pure_; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c75d12c136..4ef4dc280e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -200,14 +200,6 @@ static void release_busses(void) { busses[w] = sd_bus_flush_close_unref(busses[w]); } -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void ask_password_agent_open_if_enabled(void) { /* Open the password agent as a child process if necessary */ @@ -678,7 +670,7 @@ static int list_units(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -890,7 +882,7 @@ static int list_sockets(int argc, char *argv[], void *userdata) { int r = 0, n; sd_bus *bus; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -1197,7 +1189,7 @@ static int list_timers(int argc, char *argv[], void *userdata) { sd_bus *bus; int r = 0; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -1365,7 +1357,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { char *path; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (install_client_side()) { Hashmap *h; @@ -1679,7 +1671,7 @@ static int list_dependencies(int argc, char *argv[], void *userdata) { } else u = SPECIAL_DEFAULT_TARGET; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -1910,7 +1902,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { return -EPERM; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -2067,7 +2059,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp return; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); id_len = strlen("JOB"); unit_len = strlen("UNIT"); @@ -2137,7 +2129,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) { int r; bool skipped = false; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -4559,7 +4551,7 @@ static int show_all( if (r < 0) return r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); c = (unsigned) r; @@ -4654,7 +4646,7 @@ static int show(int argc, char *argv[], void *userdata) { return -EINVAL; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); if (show_status) /* Increase max number of open files to 16K if we can, we @@ -4672,7 +4664,7 @@ static int show(int argc, char *argv[], void *userdata) { if (show_status && argc <= 1) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); show_system_status(bus); new_line = true; @@ -4813,7 +4805,7 @@ static int cat(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to expand names: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); STRV_FOREACH(name, names) { _cleanup_free_ char *fragment_path = NULL; @@ -5003,7 +4995,7 @@ static int show_environment(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -6178,7 +6170,7 @@ end: static void systemctl_help(void) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); printf("%s [OPTIONS...] {COMMAND} ...\n\n" "Query or send control commands to the systemd manager.\n\n" diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 097963b41b..a2270aff46 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -40,14 +40,6 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; static char *arg_host = NULL; static bool arg_adjust_system_clock = false; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static void polkit_agent_open_if_enabled(void) { /* Open the polkit agent as a child process if necessary */ @@ -313,7 +305,7 @@ static int list_timezones(sd_bus *bus, char **args, unsigned n) { if (r < 0) return log_error_errno(r, "Failed to read list of time zones: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); strv_print(zones); return 0; -- cgit v1.2.3-54-g00ecf From 6369641d6f594557114b78fe740544ecf69a6d37 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 26 Feb 2016 11:25:22 +0100 Subject: clock-util: make clock_is_localtime() testable and add initial tests Add path argument to clock_is_localtime() and default to "/etc/adjtime" if it's NULL. This makes the function testable. Add test-clock: initial test cases for some scenarios, using a temporary file. This also checks the behaviour with a NULL (i. e. the system's /etc/adjtime) file. --- .gitignore | 1 + Makefile.am | 7 ++++ src/basic/clock-util.c | 7 ++-- src/basic/clock-util.h | 2 +- src/core/dbus-manager.c | 2 +- src/core/main.c | 2 +- src/test/test-clock.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ src/timedate/timedated.c | 2 +- src/timesync/timesyncd.c | 2 +- 9 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 src/test/test-clock.c (limited to 'src') diff --git a/.gitignore b/.gitignore index eab660e859..56a60ba726 100644 --- a/.gitignore +++ b/.gitignore @@ -158,6 +158,7 @@ /test-cgroup /test-cgroup-mask /test-cgroup-util +/test-clock /test-compress /test-compress-benchmark /test-condition diff --git a/Makefile.am b/Makefile.am index 7bd98dddf6..4f9072c0ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1448,6 +1448,7 @@ tests += \ test-prioq \ test-fileio \ test-time \ + test-clock \ test-hashmap \ test-set \ test-bitmap \ @@ -1961,6 +1962,12 @@ test_time_SOURCES = \ test_time_LDADD = \ libshared.la +test_clock_SOURCES = \ + src/test/test-clock.c + +test_clock_LDADD = \ + libshared.la + test_architecture_SOURCES = \ src/test/test-architecture.c diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 507e757ff0..dd6c043af9 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -69,9 +69,12 @@ int clock_set_hwclock(const struct tm *tm) { return 0; } -int clock_is_localtime(void) { +int clock_is_localtime(const char* adjtime_path) { _cleanup_fclose_ FILE *f; + if (adjtime_path == NULL) + adjtime_path = "/etc/adjtime"; + /* * The third line of adjtime is "UTC" or "LOCAL" or nothing. * # /etc/adjtime @@ -79,7 +82,7 @@ int clock_is_localtime(void) { * 0 * UTC */ - f = fopen("/etc/adjtime", "re"); + f = fopen(adjtime_path, "re"); if (f) { char line[LINE_MAX]; bool b; diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index f471f2abcf..8830cd2f38 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -21,7 +21,7 @@ #include -int clock_is_localtime(void); +int clock_is_localtime(const char* adjtime_path); int clock_set_timezone(int *min); int clock_reset_timewarp(void); int clock_get_hwclock(struct tm *tm); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index f939196397..00372b92b4 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -139,7 +139,7 @@ static int property_get_tainted( if (access("/proc/cgroups", F_OK) < 0) e = stpcpy(e, "cgroups-missing:"); - if (clock_is_localtime() > 0) + if (clock_is_localtime(NULL) > 0) e = stpcpy(e, "local-hwclock:"); /* remove the last ':' */ diff --git a/src/core/main.c b/src/core/main.c index b4e96fd6f4..2c315930ed 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1375,7 +1375,7 @@ int main(int argc, char *argv[]) { } if (!skip_setup) { - if (clock_is_localtime() > 0) { + if (clock_is_localtime(NULL) > 0) { int min; /* diff --git a/src/test/test-clock.c b/src/test/test-clock.c new file mode 100644 index 0000000000..27f6b8cfd2 --- /dev/null +++ b/src/test/test-clock.c @@ -0,0 +1,93 @@ +/*** + This file is part of systemd. + + Copyright (C) 2016 Canonical Ltd. + + 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 . +***/ + +#include +#include + +#include "macro.h" +#include "fileio.h" +#include "log.h" +#include "clock-util.h" + +static void test_clock_is_localtime(void) { + char adjtime[] = "/tmp/test-adjtime.XXXXXX"; + int fd; + FILE* f; + + const struct scenario { + const char* contents; + int expected_result; + } scenarios[] = { + /* adjtime configures UTC */ + {"0.0 0 0\n0\nUTC\n", 0}, + /* adjtime configures local time */ + {"0.0 0 0\n0\nLOCAL\n", 1}, + /* no final EOL */ + {"0.0 0 0\n0\nUTC", 0}, + {"0.0 0 0\n0\nLOCAL", 1}, + /* unknown value -> defaults to UTC */ + {"0.0 0 0\n0\nFOO\n", 0}, + /* gibberish */ + {"br0ken", -EIO}, + }; + + /* without an adjtime file we default to UTC */ + assert_se(clock_is_localtime("/nonexisting/adjtime") == 0); + + fd = mkostemp_safe(adjtime, O_WRONLY|O_CLOEXEC); + assert(fd > 0); + log_info("adjtime test file: %s", adjtime); + f = fdopen(fd, "w"); + assert(f); + + for (size_t i = 0; i < ELEMENTSOF(scenarios); ++i) { + log_info("scenario #%zu:, expected result %i", i, scenarios[i].expected_result); + log_info("%s", scenarios[i].contents); + rewind(f); + ftruncate(fd, 0); + assert_se(write_string_stream(f, scenarios[i].contents, false) == 0); + assert_se(clock_is_localtime(adjtime) == scenarios[i].expected_result); + } + + unlink(adjtime); +} + +/* Test with the real /etc/adjtime */ +static void test_clock_is_localtime_system(void) { + int r; + r = clock_is_localtime(NULL); + + if (access("/etc/adjtime", F_OK) == 0) { + log_info("/etc/adjtime exists, clock_is_localtime() == %i", r); + /* we cannot assert much if /etc/adjtime exists, just that we + * expect either an answer, or an EIO if the local file really + * is badly malformed. I. e. we don't expect any other error + * code or crash. */ + assert(r == 0 || r == 1 || r == -EIO); + } else + /* default is UTC if there is no /etc/adjtime */ + assert(r == 0); +} + +int main(int argc, char *argv[]) { + test_clock_is_localtime(); + test_clock_is_localtime_system(); + + return 0; +} diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 2a10135fba..55c24ac4f0 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -78,7 +78,7 @@ static int context_read_data(Context *c) { c->zone = t; t = NULL; - c->local_rtc = clock_is_localtime() > 0; + c->local_rtc = clock_is_localtime(NULL) > 0; return 0; } diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 23e19159e0..b67d672a6a 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (clock_is_localtime() > 0) { + if (clock_is_localtime(NULL) > 0) { log_info("The system is configured to read the RTC time in the local time zone. " "This mode can not be fully supported. All system time to RTC updates are disabled."); m->rtc_local_time = true; -- cgit v1.2.3-54-g00ecf From 35f7216f968047be26a922dc09ca588ebca71bb0 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 26 Feb 2016 12:33:41 +0100 Subject: clock-util: be more tolerant in parsing /etc/adjtime As we default to "hardware clock is in UTC" if /etc/adjtime is not present, it also makes sense to have that default if /etc/adjtime contains only one or two lines. Drop the "gibberish" test case, as this was just EIO because of not containing three lines, which is already contained in other tests. clock_is_localtime() never actually validated the format of the first two lines, and there is little point in doing that. This addresses the reading half of issue #2638. --- src/basic/clock-util.c | 4 +++- src/test/test-clock.c | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index dd6c043af9..7fe8d35ea5 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -91,7 +91,8 @@ int clock_is_localtime(const char* adjtime_path) { fgets(line, sizeof(line), f) && fgets(line, sizeof(line), f); if (!b) - return -EIO; + /* less than three lines -> default to UTC */ + return 0; truncate_nl(line); return streq(line, "LOCAL"); @@ -99,6 +100,7 @@ int clock_is_localtime(const char* adjtime_path) { } else if (errno != ENOENT) return -errno; + /* adjtime not present -> default to UTC */ return 0; } diff --git a/src/test/test-clock.c b/src/test/test-clock.c index 27f6b8cfd2..92c4f79b98 100644 --- a/src/test/test-clock.c +++ b/src/test/test-clock.c @@ -41,10 +41,14 @@ static void test_clock_is_localtime(void) { /* no final EOL */ {"0.0 0 0\n0\nUTC", 0}, {"0.0 0 0\n0\nLOCAL", 1}, + /* empty value -> defaults to UTC */ + {"0.0 0 0\n0\n", 0}, /* unknown value -> defaults to UTC */ {"0.0 0 0\n0\nFOO\n", 0}, - /* gibberish */ - {"br0ken", -EIO}, + /* no third line */ + {"0.0 0 0", 0}, + {"0.0 0 0\n", 0}, + {"0.0 0 0\n0", 0}, }; /* without an adjtime file we default to UTC */ @@ -75,11 +79,9 @@ static void test_clock_is_localtime_system(void) { if (access("/etc/adjtime", F_OK) == 0) { log_info("/etc/adjtime exists, clock_is_localtime() == %i", r); - /* we cannot assert much if /etc/adjtime exists, just that we - * expect either an answer, or an EIO if the local file really - * is badly malformed. I. e. we don't expect any other error - * code or crash. */ - assert(r == 0 || r == 1 || r == -EIO); + /* if /etc/adjtime exists we expect some answer, no error or + * crash */ + assert(r == 0 || r == 1); } else /* default is UTC if there is no /etc/adjtime */ assert(r == 0); -- cgit v1.2.3-54-g00ecf From c9410dd47f4e9ba204f489dc9812a19617af020f Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 26 Feb 2016 15:54:05 +0100 Subject: timedated: be more tolerant in parsing /etc/adjtime Similarly to the previous commit, make context_write_data_local_rtc() understand /etc/adjtime files with just one or two lines, with or without a final newline. Normalize the file to the current definition in hwclock(8), in the spirit of "be liberal what you accept and strict what you produce": Add line terminators, and set the second line to "0" if missing. Fixes: #2638 --- src/timedate/timedated.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 55c24ac4f0..4e120564c0 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -125,30 +125,44 @@ static int context_write_data_local_rtc(Context *c) { if (!w) return -ENOMEM; } else { - char *p, *e; + char *p; + char *e = (char*) "\n"; /* default if there are not 3 lines with \n terminator */ + const char *prepend = ""; size_t a, b; - p = strchr(s, '\n'); - if (!p) - return -EIO; - - p = strchr(p+1, '\n'); - if (!p) - return -EIO; - - p++; - e = strchr(p, '\n'); - if (!e) - return -EIO; + p = strchrnul(s, '\n'); + if (*p == '\0') { + /* only one line, no \n terminator */ + prepend = "\n0\n"; + } else if (p[1] == '\0') { + /* only one line, with \n terminator */ + ++p; + prepend = "0\n"; + } else { + p = strchr(p+1, '\n'); + if (!p) { + /* only two lines, no \n terminator */ + prepend = "\n"; + p = s + strlen(s); + } else { + char *end; + /* third line might have a \n terminator or not */ + p++; + end = strchr(p, '\n'); + /* if we actually have a fourth line, use that as suffix "e", otherwise the default \n */ + if (end) + e = end; + } + } a = p - s; b = strlen(e); - w = new(char, a + (c->local_rtc ? 5 : 3) + b + 1); + w = new(char, a + (c->local_rtc ? 5 : 3) + strlen(prepend) + b + 1); if (!w) return -ENOMEM; - *(char*) mempcpy(stpcpy(mempcpy(w, s, a), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; + *(char*) mempcpy(stpcpy(stpcpy(mempcpy(w, s, a), prepend), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; if (streq(w, NULL_ADJTIME_UTC)) { if (unlink("/etc/adjtime") < 0) -- cgit v1.2.3-54-g00ecf From 7f508f2c7468a6469c4db92bb3b9f0e799246eb8 Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Thu, 25 Feb 2016 00:27:56 +0100 Subject: tree-wide: indentation fixes --- src/core/execute.c | 2 +- src/core/smack-setup.c | 2 +- src/stdio-bridge/stdio-bridge.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/execute.c b/src/core/execute.c index 8ede9e9afb..517c2fb45b 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1876,7 +1876,7 @@ static int exec_child( * also to the context secure_bits so that we don't try to * drop the bit away next. */ - secure_bits |= 1< Date: Thu, 25 Feb 2016 00:29:09 +0100 Subject: stdio-bridge: remove dead code --- src/stdio-bridge/stdio-bridge.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c index c38b43b0f0..85b99ce161 100644 --- a/src/stdio-bridge/stdio-bridge.c +++ b/src/stdio-bridge/stdio-bridge.c @@ -294,8 +294,6 @@ int main(int argc, char *argv[]) { } } - r = 0; - finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From 3587161ade40a4f093175217d87d6323b3aba168 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 27 Feb 2016 13:40:50 +0100 Subject: core: avoid compiler warning when compiling with -fexceptions Initialize auto variables with cleanup attribute, otherwise we get a compiler warning with -fexceptions. ./configure CFLAGS='-Wmaybe-uninitialized -fexceptions -O2' --- src/basic/fileio.c | 6 +++--- src/libsystemd-network/sd-dhcp-client.c | 2 +- src/libsystemd-network/sd-dhcp-lease.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 2c454e8ea2..69590941e5 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -588,7 +588,7 @@ static int parse_env_file_push( va_list aq, *ap = userdata; if (!utf8_is_valid(key)) { - _cleanup_free_ char *p; + _cleanup_free_ char *p = NULL; p = utf8_escape_invalid(key); log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p); @@ -596,7 +596,7 @@ static int parse_env_file_push( } if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *p; + _cleanup_free_ char *p = NULL; p = utf8_escape_invalid(value); log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p); @@ -1069,7 +1069,7 @@ int fflush_and_check(FILE *f) { /* This is much like like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern, int flags) { - _cleanup_umask_ mode_t u; + _cleanup_umask_ mode_t u = 0; int fd; assert(pattern); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index d484c37a73..1188b31500 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -408,7 +408,7 @@ static void client_stop(sd_dhcp_client *client, int error) { static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, uint8_t type, size_t *_optlen, size_t *_optoffset) { - _cleanup_free_ DHCPPacket *packet; + _cleanup_free_ DHCPPacket *packet = NULL; size_t optlen, optoffset, size; be16_t max_size; usec_t time_now; diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 7a119fd488..ef50ed17a1 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -825,7 +825,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); if (r >= 0) { - _cleanup_free_ char *client_id_hex; + _cleanup_free_ char *client_id_hex = NULL; client_id_hex = hexmem(client_id, client_id_len); if (!client_id_hex) { -- cgit v1.2.3-54-g00ecf From 19c0b0b9a5039b842cf9e6c3e7ece75fb8725602 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Sat, 30 Jan 2016 17:26:39 +0100 Subject: core: set NoNewPrivileges for seccomp if we don't have CAP_SYS_ADMIN The manpage of seccomp specify that using seccomp with SECCOMP_SET_MODE_FILTER will return EACCES if the caller do not have CAP_SYS_ADMIN set, or if the no_new_privileges bit is not set. Hence, without NoNewPrivilege set, it is impossible to use a SystemCall* directive with a User directive set in system mode. Now, NoNewPrivileges is set if we are in user mode, or if we are in system mode and we don't have CAP_SYS_ADMIN, and SystemCall* directives are used. --- Makefile.am | 1 + man/systemd.exec.xml | 16 ++++-- src/core/execute.c | 16 +++--- src/test/test-execute.c | 57 ++++++++++++++++------ .../exec-systemcallfilter-system-user.service | 11 +++++ 5 files changed, 74 insertions(+), 27 deletions(-) create mode 100644 test/test-execute/exec-systemcallfilter-system-user.service (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 7bd98dddf6..02557ef46a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1556,6 +1556,7 @@ EXTRA_DIST += \ test/test-execute/exec-systemcallfilter-failing.service \ test/test-execute/exec-systemcallfilter-not-failing2.service \ test/test-execute/exec-systemcallfilter-not-failing.service \ + test/test-execute/exec-systemcallfilter-system-user.service \ test/test-execute/exec-user.service \ test/test-execute/exec-workingdirectory.service \ test/test-execute/exec-umask-0177.service \ diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index c1f47e84e6..3e1a2cb224 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1155,7 +1155,9 @@ first character of the list is ~, the effect is inverted: only the listed system calls will result in immediate process termination (blacklisting). If running in - user mode and this option is used, + user mode, or in system mode, but without the + CAP_SYS_ADMIN capabiblity (e.g. setting + User=nobody), NoNewPrivileges=yes is implied. This feature makes use of the Secure Computing Mode 2 interfaces of the kernel ('seccomp filtering') and is useful for enforcing a @@ -1214,8 +1216,10 @@ systems. The special native identifier implicitly maps to the native architecture of the system (or more strictly: to the architecture the system manager is - compiled for). If running in user mode and this option is - used, NoNewPrivileges=yes is implied. Note + compiled for). If running in user mode, or in system mode, + but without the CAP_SYS_ADMIN + capabiblity (e.g. setting User=nobody), + NoNewPrivileges=yes is implied. Note that setting this option to a non-empty list implies that native is included too. By default, this option is set to the empty list, i.e. no architecture system @@ -1244,8 +1248,10 @@ socketpair() (which creates connected AF_UNIX sockets only) are unaffected. Note that this option has no effect on 32-bit x86 and is ignored (but works - correctly on x86-64). If running in user mode and this option - is used, NoNewPrivileges=yes is implied. By + correctly on x86-64). If running in user mode, or in system + mode, but without the CAP_SYS_ADMIN + capabiblity (e.g. setting User=nobody), + NoNewPrivileges=yes is implied. By default, no restriction applies, all address families are accessible to processes. If assigned the empty string, any previous list changes are undone. diff --git a/src/core/execute.c b/src/core/execute.c index 8ede9e9afb..0c311ec330 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1824,6 +1825,11 @@ static int exec_child( if (params->apply_permissions) { + bool use_address_families = context->address_families_whitelist || + !set_isempty(context->address_families); + bool use_syscall_filter = context->syscall_whitelist || + !set_isempty(context->syscall_filter) || + !set_isempty(context->syscall_archs); int secure_bits = context->secure_bits; for (i = 0; i < _RLIMIT_MAX; i++) { @@ -1890,15 +1896,15 @@ static int exec_child( return -errno; } - if (context->no_new_privileges) + if (context->no_new_privileges || + (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || use_syscall_filter))) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { *exit_status = EXIT_NO_NEW_PRIVILEGES; return -errno; } #ifdef HAVE_SECCOMP - if (context->address_families_whitelist || - !set_isempty(context->address_families)) { + if (use_address_families) { r = apply_address_families(context); if (r < 0) { *exit_status = EXIT_ADDRESS_FAMILIES; @@ -1906,9 +1912,7 @@ static int exec_child( } } - if (context->syscall_whitelist || - !set_isempty(context->syscall_filter) || - !set_isempty(context->syscall_archs)) { + if (use_syscall_filter) { r = apply_seccomp(context); if (r < 0) { *exit_status = EXIT_SECCOMP; diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 0d2e4bfc15..5645f5c086 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -130,6 +130,15 @@ static void test_exec_systemcallerrornumber(Manager *m) { #endif } +static void test_exec_systemcall_system_mode_with_user(Manager *m) { +#ifdef HAVE_SECCOMP + if (getpwnam("nobody")) + test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_systemcall_system_mode_with_user, could not find nobody user: %m"); +#endif +} + static void test_exec_user(Manager *m) { if (getpwnam("nobody")) test(m, "exec-user.service", 0, CLD_EXITED); @@ -267,8 +276,31 @@ static void test_exec_spec_interpolation(Manager *m) { test(m, "exec-spec-interpolation.service", 0, CLD_EXITED); } +static int run_tests(ManagerRunningAs running_as, test_function_t *tests) { + test_function_t *test = NULL; + Manager *m = NULL; + int r; + + assert_se(tests); + + r = manager_new(running_as, true, &m); + if (MANAGER_SKIP_TEST(r)) { + printf("Skipping test: manager_new: %s\n", strerror(-r)); + return EXIT_TEST_SKIP; + } + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + for (test = tests; test && *test; test++) + (*test)(m); + + manager_free(m); + + return 0; +} + int main(int argc, char *argv[]) { - test_function_t tests[] = { + test_function_t user_tests[] = { test_exec_workingdirectory, test_exec_personality, test_exec_ignoresigpipe, @@ -291,8 +323,10 @@ int main(int argc, char *argv[]) { test_exec_spec_interpolation, NULL, }; - test_function_t *test = NULL; - Manager *m = NULL; + test_function_t system_tests[] = { + test_exec_systemcall_system_mode_with_user, + NULL, + }; int r; log_parse_environment(); @@ -317,18 +351,9 @@ int main(int argc, char *argv[]) { assert_se(unsetenv("VAR2") == 0); assert_se(unsetenv("VAR3") == 0); - r = manager_new(MANAGER_USER, true, &m); - if (MANAGER_SKIP_TEST(r)) { - printf("Skipping test: manager_new: %s\n", strerror(-r)); - return EXIT_TEST_SKIP; - } - assert_se(r >= 0); - assert_se(manager_startup(m, NULL, NULL) >= 0); - - for (test = tests; test && *test; test++) - (*test)(m); + r = run_tests(MANAGER_USER, user_tests); + if (r != 0) + return r; - manager_free(m); - - return 0; + return run_tests(MANAGER_SYSTEM, system_tests); } diff --git a/test/test-execute/exec-systemcallfilter-system-user.service b/test/test-execute/exec-systemcallfilter-system-user.service new file mode 100644 index 0000000000..462f94133d --- /dev/null +++ b/test/test-execute/exec-systemcallfilter-system-user.service @@ -0,0 +1,11 @@ +[Unit] +Description=Test for SystemCallFilter in system mode with User set + +[Service] +ExecStart=/bin/echo "Foo bar" +Type=oneshot +User=nobody +SystemCallFilter=~read write open execve ioperm +SystemCallFilter=ioctl +SystemCallFilter=read write open execve +SystemCallFilter=~ioperm -- cgit v1.2.3-54-g00ecf From 50f130c286c4a4cb87a94a0fc419a4462a98a7a1 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Sun, 28 Feb 2016 15:00:18 +0100 Subject: test-execute: add nfsnobody alternative as a nobody user --- Makefile.am | 6 +++++ src/test/test-execute.c | 28 ++++++++++++++++------ ...ec-capabilityambientset-merge-nfsnobody.service | 9 +++++++ .../exec-capabilityambientset-nfsnobody.service | 8 +++++++ test/test-execute/exec-group-nfsnobody.service | 7 ++++++ .../exec-runtimedirectory-owner-nfsnobody.service | 9 +++++++ ...-systemcallfilter-system-user-nfsnobody.service | 11 +++++++++ test/test-execute/exec-user-nfsnobody.service | 7 ++++++ 8 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 test/test-execute/exec-capabilityambientset-merge-nfsnobody.service create mode 100644 test/test-execute/exec-capabilityambientset-nfsnobody.service create mode 100644 test/test-execute/exec-group-nfsnobody.service create mode 100644 test/test-execute/exec-runtimedirectory-owner-nfsnobody.service create mode 100644 test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service create mode 100644 test/test-execute/exec-user-nfsnobody.service (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 02557ef46a..ae1cda4c72 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1541,6 +1541,7 @@ EXTRA_DIST += \ test/test-execute/exec-passenvironment-repeated.service \ test/test-execute/exec-passenvironment.service \ test/test-execute/exec-group.service \ + test/test-execute/exec-group-nfsnobody.service \ test/test-execute/exec-ignoresigpipe-no.service \ test/test-execute/exec-ignoresigpipe-yes.service \ test/test-execute/exec-personality-x86-64.service \ @@ -1557,7 +1558,9 @@ EXTRA_DIST += \ test/test-execute/exec-systemcallfilter-not-failing2.service \ test/test-execute/exec-systemcallfilter-not-failing.service \ test/test-execute/exec-systemcallfilter-system-user.service \ + test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service \ test/test-execute/exec-user.service \ + test/test-execute/exec-user-nfsnobody.service \ test/test-execute/exec-workingdirectory.service \ test/test-execute/exec-umask-0177.service \ test/test-execute/exec-umask-default.service \ @@ -1574,10 +1577,13 @@ EXTRA_DIST += \ test/test-execute/exec-capabilityboundingset-reset.service \ test/test-execute/exec-capabilityboundingset-simple.service \ test/test-execute/exec-capabilityambientset.service \ + test/test-execute/exec-capabilityambientset-nfsnobody.service \ test/test-execute/exec-capabilityambientset-merge.service \ + test/test-execute/exec-capabilityambientset-merge-nfsnobody.service \ test/test-execute/exec-runtimedirectory.service \ test/test-execute/exec-runtimedirectory-mode.service \ test/test-execute/exec-runtimedirectory-owner.service \ + test/test-execute/exec-runtimedirectory-owner-nfsnobody.service \ test/bus-policy/hello.conf \ test/bus-policy/methods.conf \ test/bus-policy/ownerships.conf \ diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 5645f5c086..3e91a5601e 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -134,23 +134,29 @@ static void test_exec_systemcall_system_mode_with_user(Manager *m) { #ifdef HAVE_SECCOMP if (getpwnam("nobody")) test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED); + else if (getpwnam("nfsnobody")) + test(m, "exec-systemcallfilter-system-user-nfsnobody.service", 0, CLD_EXITED); else - log_error_errno(errno, "Skipping test_exec_systemcall_system_mode_with_user, could not find nobody user: %m"); + log_error_errno(errno, "Skipping test_exec_systemcall_system_mode_with_user, could not find nobody/nfsnobody user: %m"); #endif } static void test_exec_user(Manager *m) { if (getpwnam("nobody")) test(m, "exec-user.service", 0, CLD_EXITED); + else if (getpwnam("nfsnobody")) + test(m, "exec-user-nfsnobody.service", 0, CLD_EXITED); else - log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m"); + log_error_errno(errno, "Skipping test_exec_user, could not find nobody/nfsnobody user: %m"); } static void test_exec_group(Manager *m) { if (getgrnam("nobody")) test(m, "exec-group.service", 0, CLD_EXITED); + else if (getgrnam("nfsnobody")) + test(m, "exec-group-nfsnobody.service", 0, CLD_EXITED); else - log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m"); + log_error_errno(errno, "Skipping test_exec_group, could not find nobody/nfsnobody group: %m"); } static void test_exec_environment(Manager *m) { @@ -213,8 +219,10 @@ static void test_exec_runtimedirectory(Manager *m) { test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); if (getgrnam("nobody")) test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + else if (getgrnam("nfsnobody")) + test(m, "exec-runtimedirectory-owner-nfsnobody.service", 0, CLD_EXITED); else - log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m"); + log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody/nfsnobody group: %m"); } static void test_exec_capabilityboundingset(Manager *m) { @@ -243,9 +251,15 @@ static void test_exec_capabilityambientset(Manager *m) { * in the first place for the tests. */ r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); if (r >= 0 || errno != EINVAL) { - test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); - test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); - } + if (getpwnam("nobody")) { + test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + } else if (getpwnam("nfsnobody")) { + test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); + test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); + } else + log_error_errno(errno, "Skipping test_exec_capabilityambientset, could not find nobody/nfsnobody user: %m"); + } else + log_error_errno(errno, "Skipping test_exec_capabilityambientset, the kernel does not support ambient capabilities: %m"); } static void test_exec_privatenetwork(Manager *m) { diff --git a/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service b/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service new file mode 100644 index 0000000000..00bec581b5 --- /dev/null +++ b/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nfsnobody +AmbientCapabilities=CAP_NET_ADMIN +AmbientCapabilities=CAP_NET_RAW diff --git a/test/test-execute/exec-capabilityambientset-nfsnobody.service b/test/test-execute/exec-capabilityambientset-nfsnobody.service new file mode 100644 index 0000000000..614cfdd584 --- /dev/null +++ b/test/test-execute/exec-capabilityambientset-nfsnobody.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nfsnobody +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW diff --git a/test/test-execute/exec-group-nfsnobody.service b/test/test-execute/exec-group-nfsnobody.service new file mode 100644 index 0000000000..e02100a869 --- /dev/null +++ b/test/test-execute/exec-group-nfsnobody.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Group + +[Service] +ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nfsnobody"' +Type=oneshot +Group=nfsnobody diff --git a/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service b/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service new file mode 100644 index 0000000000..e962af8a4b --- /dev/null +++ b/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set) + +[Service] +ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nfsnobody"' +Type=oneshot +Group=nfsnobody +User=root +RuntimeDirectory=test-exec_runtimedirectory-owner diff --git a/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service b/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service new file mode 100644 index 0000000000..9393e0a998 --- /dev/null +++ b/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service @@ -0,0 +1,11 @@ +[Unit] +Description=Test for SystemCallFilter in system mode with User set + +[Service] +ExecStart=/bin/echo "Foo bar" +Type=oneshot +User=nfsnobody +SystemCallFilter=~read write open execve ioperm +SystemCallFilter=ioctl +SystemCallFilter=read write open execve +SystemCallFilter=~ioperm diff --git a/test/test-execute/exec-user-nfsnobody.service b/test/test-execute/exec-user-nfsnobody.service new file mode 100644 index 0000000000..aafda3aa26 --- /dev/null +++ b/test/test-execute/exec-user-nfsnobody.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for User + +[Service] +ExecStart=/bin/sh -x -c 'test "$$USER" = "nfsnobody"' +Type=oneshot +User=nfsnobody -- cgit v1.2.3-54-g00ecf From 46e1a2278116e2f5067c35127ccbd8589335f734 Mon Sep 17 00:00:00 2001 From: Thomas Blume Date: Mon, 29 Feb 2016 10:19:01 +0100 Subject: shorten hostname before checking for trailing dot Shortening can lead to a hostname that has a trailing dot. Therefore it should be done before checking from trailing dots. --- src/basic/hostname-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 3cd2f2c872..5a7ee87a20 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -150,6 +150,8 @@ char* hostname_cleanup(char *s) { assert(s); + strshorten(s, HOST_NAME_MAX); + for (p = s, d = s, dot = true; *p; p++) { if (*p == '.') { if (dot) @@ -169,8 +171,6 @@ char* hostname_cleanup(char *s) { else *d = 0; - strshorten(s, HOST_NAME_MAX); - return s; } -- cgit v1.2.3-54-g00ecf From 20268e0c3e2bbba4160e444f23be83da4542e0f5 Mon Sep 17 00:00:00 2001 From: Benjamin Robin Date: Mon, 29 Feb 2016 10:36:11 +0100 Subject: stdio-bridge: Correctly propagate error Return EXIT_FAILURE and print the correct errno code if sd_bus_get_fd() or sd_bus_get_events() fail --- src/stdio-bridge/stdio-bridge.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c index 85b99ce161..ce8efce3d5 100644 --- a/src/stdio-bridge/stdio-bridge.c +++ b/src/stdio-bridge/stdio-bridge.c @@ -234,12 +234,14 @@ int main(int argc, char *argv[]) { fd = sd_bus_get_fd(a); if (fd < 0) { + r = fd; log_error_errno(r, "Failed to get fd: %m"); goto finish; } events_a = sd_bus_get_events(a); if (events_a < 0) { + r = events_a; log_error_errno(r, "Failed to get events mask: %m"); goto finish; } @@ -252,6 +254,7 @@ int main(int argc, char *argv[]) { events_b = sd_bus_get_events(b); if (events_b < 0) { + r = events_b; log_error_errno(r, "Failed to get events mask: %m"); goto finish; } -- cgit v1.2.3-54-g00ecf From 0f5f63c3282e90b33a61dc7f9bb7110e49685627 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Mon, 29 Feb 2016 18:56:57 +0600 Subject: core: use DUAL_TIMESTAMP_NULL to reset kernel_timestamp instead of direct reset of kernel_timestamp fields. --- src/core/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index b4e96fd6f4..00ec8dac03 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1435,9 +1435,7 @@ int main(int argc, char *argv[]) { /* clear the kernel timestamp, * because we are in a container */ - kernel_timestamp.monotonic = 0ULL; - kernel_timestamp.realtime = 0ULL; - + kernel_timestamp = DUAL_TIMESTAMP_NULL; } else { /* Running as user instance */ arg_running_as = MANAGER_USER; -- cgit v1.2.3-54-g00ecf From fe4f8fd1d94f32941722bc637811ad0a6ac32975 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 29 Feb 2016 08:03:32 -0500 Subject: test-clock: fix fd "leak" CID #1352301. --- src/test/test-clock.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/test/test-clock.c b/src/test/test-clock.c index 92c4f79b98..b049d97ce7 100644 --- a/src/test/test-clock.c +++ b/src/test/test-clock.c @@ -20,17 +20,18 @@ #include #include -#include "macro.h" +#include "clock-util.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" -#include "clock-util.h" +#include "macro.h" static void test_clock_is_localtime(void) { char adjtime[] = "/tmp/test-adjtime.XXXXXX"; - int fd; + _cleanup_close_ int fd = -1; FILE* f; - const struct scenario { + static const struct scenario { const char* contents; int expected_result; } scenarios[] = { -- cgit v1.2.3-54-g00ecf From fa0d5878c68a3f8d6a5612c4534471213c7e3d76 Mon Sep 17 00:00:00 2001 From: Benjamin ROBIN Date: Mon, 29 Feb 2016 14:25:16 +0100 Subject: systemctl: Replace check_one_unit() by get_state_one_unit() The get_state_one_unit returns the enum of the active state of the unit Do not rely on the string value of the active state. Fix #2718 since the refactoring allow to handle more case --- src/systemctl/systemctl.c | 84 +++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index a4491692a9..8e39b7a342 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -152,7 +152,7 @@ static bool arg_now = false; static int daemon_reload(int argc, char *argv[], void* userdata); static int halt_now(enum action a); -static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet); +static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state); static bool original_stdout_is_tty; @@ -1630,11 +1630,27 @@ static int list_dependencies_one( if (arg_plain) printf(" "); else { - int state; + UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID; const char *on; - state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true); - on = state > 0 ? ansi_highlight_green() : ansi_highlight_red(); + (void) get_state_one_unit(bus, *c, &active_state); + switch (active_state) { + case UNIT_ACTIVE: + case UNIT_RELOADING: + case UNIT_ACTIVATING: + on = ansi_highlight_green(); + break; + + case UNIT_INACTIVE: + case UNIT_DEACTIVATING: + on = ansi_normal(); + break; + + default: + on = ansi_highlight_red(); + break; + } + printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal()); } @@ -2399,18 +2415,19 @@ static int unit_find_paths( return r; } -static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) { +static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *buf = NULL; - const char *path, *state; + UnitActiveState state; + const char *path; int r; assert(name); + assert(active_state); /* We don't use unit_dbus_path_from_name() directly since we don't want to load the unit unnecessarily, if it * isn't loaded. */ - r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -2426,7 +2443,7 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states /* The unit is currently not loaded, hence say it's "inactive", since all units that aren't loaded are * considered inactive. */ - state = "inactive"; + state = UNIT_INACTIVE; } else { r = sd_bus_message_read(reply, "o", &path); @@ -2444,13 +2461,15 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states if (r < 0) return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r)); - state = buf; + state = unit_active_state_from_string(buf); + if (state == _UNIT_ACTIVE_STATE_INVALID) { + log_error("Invalid unit state '%s' for: %s", buf, name); + return -EINVAL; + } } - if (!quiet) - puts(state); - - return nulstr_contains(good_states, state); + *active_state = state; + return 0; } static int check_triggering_units( @@ -2458,9 +2477,10 @@ static int check_triggering_units( const char *name) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL; + _cleanup_free_ char *path = NULL, *n = NULL, *load_state = NULL; _cleanup_strv_free_ char **triggered_by = NULL; bool print_warning_label = true; + UnitActiveState active_state; char **i; int r; @@ -2479,11 +2499,11 @@ static int check_triggering_units( "org.freedesktop.systemd1.Unit", "LoadState", &error, - &state); + &load_state); if (r < 0) return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r)); - if (streq(state, "masked")) + if (streq(load_state, "masked")) return 0; r = sd_bus_get_property_strv( @@ -2498,11 +2518,11 @@ static int check_triggering_units( return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r)); STRV_FOREACH(i, triggered_by) { - r = check_one_unit(bus, *i, "active\0reloading\0", true); + r = get_state_one_unit(bus, *i, &active_state); if (r < 0) - return log_error_errno(r, "Failed to check unit: %m"); + return r; - if (r == 0) + if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING)) continue; if (print_warning_label) { @@ -3163,11 +3183,12 @@ static int start_special(int argc, char *argv[], void *userdata) { return start_unit(argc, argv, userdata); } -static int check_unit_generic(int code, const char *good_states, char **args) { +static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) { _cleanup_strv_free_ char **names = NULL; + UnitActiveState active_state; sd_bus *bus; char **name; - int r; + int r, i; bool found = false; r = acquire_bus(BUS_MANAGER, &bus); @@ -3179,13 +3200,16 @@ static int check_unit_generic(int code, const char *good_states, char **args) { return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - int state; + r = get_state_one_unit(bus, *name, &active_state); + if (r < 0) + return r; + + if (!arg_quiet) + puts(unit_active_state_to_string(active_state)); - state = check_one_unit(bus, *name, good_states, arg_quiet); - if (state < 0) - return state; - if (state > 0) - found = true; + for (i = 0; i < nb_states; ++i) + if (good_states[i] == active_state) + found = true; } /* use the given return code for the case that we won't find @@ -3194,12 +3218,14 @@ static int check_unit_generic(int code, const char *good_states, char **args) { } static int check_unit_active(int argc, char *argv[], void *userdata) { + const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING }; /* According to LSB: 3, "program is not running" */ - return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1)); + return check_unit_generic(3, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int check_unit_failed(int argc, char *argv[], void *userdata) { - return check_unit_generic(1, "failed\0", strv_skip(argv, 1)); + const UnitActiveState states[] = { UNIT_FAILED }; + return check_unit_generic(1, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int kill_unit(int argc, char *argv[], void *userdata) { -- cgit v1.2.3-54-g00ecf From d2e796739d731c41b8206dbd61706dd5bdedd926 Mon Sep 17 00:00:00 2001 From: Benjamin ROBIN Date: Mon, 29 Feb 2016 15:07:09 +0100 Subject: systemctl: Fix warn: action_to_runlevel() is not used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If HAVE_SYSV_COMPAT is not defined: ‘action_to_runlevel’ defined but not used --- src/systemctl/systemctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index a4491692a9..11e26ce737 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -7263,6 +7263,7 @@ static int parse_argv(int argc, char *argv[]) { return systemctl_parse_argv(argc, argv); } +#ifdef HAVE_SYSV_COMPAT _pure_ static int action_to_runlevel(void) { static const char table[_ACTION_MAX] = { @@ -7280,6 +7281,7 @@ _pure_ static int action_to_runlevel(void) { return table[arg_action]; } +#endif static int talk_initctl(void) { #ifdef HAVE_SYSV_COMPAT -- cgit v1.2.3-54-g00ecf From cb971cc0317e6767a3394f721eac6efa99f51fed Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 29 Feb 2016 15:16:03 +0100 Subject: timedated: trivial stylistic fix Don't use {} for single-line "then" blocks. --- src/timedate/timedated.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 9406d28abe..0febc36af8 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -131,10 +131,10 @@ static int context_write_data_local_rtc(Context *c) { size_t a, b; p = strchrnul(s, '\n'); - if (*p == '\0') { + if (*p == '\0') /* only one line, no \n terminator */ prepend = "\n0\n"; - } else if (p[1] == '\0') { + else if (p[1] == '\0') { /* only one line, with \n terminator */ ++p; prepend = "0\n"; -- cgit v1.2.3-54-g00ecf From d69d951b11e80dbcc7f62938951832638119bdd9 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 29 Feb 2016 15:16:11 +0100 Subject: test-clock: fix assertions Use assert_se() to ensure that they don't get optimized away. --- src/test/test-clock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/test/test-clock.c b/src/test/test-clock.c index b049d97ce7..0949793e5f 100644 --- a/src/test/test-clock.c +++ b/src/test/test-clock.c @@ -56,10 +56,10 @@ static void test_clock_is_localtime(void) { assert_se(clock_is_localtime("/nonexisting/adjtime") == 0); fd = mkostemp_safe(adjtime, O_WRONLY|O_CLOEXEC); - assert(fd > 0); + assert_se(fd >= 0); log_info("adjtime test file: %s", adjtime); f = fdopen(fd, "w"); - assert(f); + assert_se(f); for (size_t i = 0; i < ELEMENTSOF(scenarios); ++i) { log_info("scenario #%zu:, expected result %i", i, scenarios[i].expected_result); @@ -82,10 +82,10 @@ static void test_clock_is_localtime_system(void) { log_info("/etc/adjtime exists, clock_is_localtime() == %i", r); /* if /etc/adjtime exists we expect some answer, no error or * crash */ - assert(r == 0 || r == 1); + assert_se(r == 0 || r == 1); } else /* default is UTC if there is no /etc/adjtime */ - assert(r == 0); + assert_se(r == 0); } int main(int argc, char *argv[]) { -- cgit v1.2.3-54-g00ecf From 07edd3b9e5855332a02ef7b91602c93aa12c1fd1 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 29 Feb 2016 17:40:08 +0100 Subject: test-clock: fix FILE* leak Close the FILE* instead of the underlying fd. --- src/test/test-clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/test/test-clock.c b/src/test/test-clock.c index 0949793e5f..84f775e5bc 100644 --- a/src/test/test-clock.c +++ b/src/test/test-clock.c @@ -28,8 +28,8 @@ static void test_clock_is_localtime(void) { char adjtime[] = "/tmp/test-adjtime.XXXXXX"; - _cleanup_close_ int fd = -1; - FILE* f; + int fd = -1; + _cleanup_fclose_ FILE* f = NULL; static const struct scenario { const char* contents; -- cgit v1.2.3-54-g00ecf From 82e24b0068feb0dbf6274d889d0368fe4212285f Mon Sep 17 00:00:00 2001 From: Elias Probst Date: Mon, 29 Feb 2016 22:42:43 +0100 Subject: Use `PRIu64` to print `uint64_t` in log msgs --- src/journal/compress.c | 5 +++-- src/journal/sd-journal.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/journal/compress.c b/src/journal/compress.c index 1933b87b00..c43849c46a 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -17,6 +17,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -498,7 +499,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { total_out += n; if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { - log_debug("Compressed stream longer than %zd bytes", max_bytes); + log_debug("Compressed stream longer than %"PRIu64" bytes", max_bytes); return -EFBIG; } @@ -649,7 +650,7 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) { total_out += produced; if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { - log_debug("Decompressed stream longer than %zd bytes", max_bytes); + log_debug("Decompressed stream longer than %"PRIu64" bytes", max_bytes); r = -EFBIG; goto cleanup; } diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index ac75e39312..3c21d4129e 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -1957,7 +1958,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** &f->compress_buffer, &f->compress_buffer_size, field, field_length, '='); if (r < 0) - log_debug_errno(r, "Cannot decompress %s object of length %zu at offset "OFSfmt": %m", + log_debug_errno(r, "Cannot decompress %s object of length %"PRIu64" at offset "OFSfmt": %m", object_compressed_to_string(compression), l, p); else if (r > 0) { -- cgit v1.2.3-54-g00ecf From a5a4e3658ddc0c9692057ce5288fa1bb6f53bacc Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 29 Feb 2016 21:04:02 +0100 Subject: ask-password: add option --no-output to not print password to stdout systemd-ask-password can store passwords in kernel keyring. However it uses to print the passwords to standard output nevertheless. Depending on where systemd-ask-password is called passwords may end on display or in log, leaking sensitive information. This allows to make systemd-ask-password quiet, effectively disabling printing passwords to standard output. --- man/systemd-ask-password.xml | 9 +++++++++ src/ask-password/ask-password.c | 11 ++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml index 2a4d24349b..e84a15c554 100644 --- a/man/systemd-ask-password.xml +++ b/man/systemd-ask-password.xml @@ -192,6 +192,15 @@ This will output one password per line. + + + + Do not print passwords to standard output. + This is useful if you want to store a password in kernel + keyring with but do not want it + to show up on screen or in logs. + + diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index adc9286612..6d53dd982c 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -34,6 +34,7 @@ static const char *arg_keyname = NULL; static char *arg_message = NULL; static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; static bool arg_multiple = false; +static bool arg_no_output = false; static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE; static void help(void) { @@ -48,6 +49,7 @@ static void help(void) { " --no-tty Ask question via agent even on TTY\n" " --accept-cached Accept cached passwords\n" " --multiple List multiple passwords if available\n" + " --no-output Do not print password to standard output\n" , program_invocation_short_name); } @@ -62,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_MULTIPLE, ARG_ID, ARG_KEYNAME, + ARG_NO_OUTPUT, }; static const struct option options[] = { @@ -74,6 +77,7 @@ static int parse_argv(int argc, char *argv[]) { { "multiple", no_argument, NULL, ARG_MULTIPLE }, { "id", required_argument, NULL, ARG_ID }, { "keyname", required_argument, NULL, ARG_KEYNAME }, + { "no-output", no_argument, NULL, ARG_NO_OUTPUT }, {} }; @@ -125,6 +129,10 @@ static int parse_argv(int argc, char *argv[]) { arg_keyname = optarg; break; + case ARG_NO_OUTPUT: + arg_no_output = true; + break; + case '?': return -EINVAL; @@ -166,7 +174,8 @@ int main(int argc, char *argv[]) { } STRV_FOREACH(p, l) { - puts(*p); + if (!arg_no_output) + puts(*p); if (!arg_multiple) break; -- cgit v1.2.3-54-g00ecf From c4b6915670ded7384795705ca9bb131da4763bac Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Wed, 2 Mar 2016 00:25:09 +0600 Subject: tree-wide: no need to pass excess flags to open()/openat() if O_PATH is passed As described in the documentation: When O_PATH is specified in flags, flag bits other than O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. So, we can remove unnecessary flags in a case when O_PATH is passed to the open() or openat(). --- src/basic/mount-util.c | 4 ++-- src/basic/xattr-util.c | 2 +- src/tmpfiles/tmpfiles.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 33f2ee96d8..5faa2eba05 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -47,7 +47,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id 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); + subfd = openat(fd, filename, O_CLOEXEC|O_PATH); if (subfd < 0) return -errno; @@ -230,7 +230,7 @@ int path_is_mount_point(const char *t, int flags) { if (!parent) return -ENOMEM; - fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); + fd = openat(AT_FDCWD, parent, O_DIRECTORY|O_CLOEXEC|O_PATH); if (fd < 0) return -errno; diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index 8d7f14f382..8256899eda 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -110,7 +110,7 @@ ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ - fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); + fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); if (fd < 0) return -errno; diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 7b105a6bd4..2ab0468c12 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -613,7 +613,7 @@ static int path_set_perms(Item *i, const char *path) { * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via * O_PATH. */ - fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); if (fd < 0) return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path); @@ -804,7 +804,7 @@ static int path_set_acls(Item *item, const char *path) { assert(item); assert(path); - fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); if (fd < 0) return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); -- cgit v1.2.3-54-g00ecf From c3dacc8bbf2dc2f5d498072418289c3ba79160ac Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 1 Mar 2016 20:35:55 -0500 Subject: selinux: always try to load the full selinux db https://github.com/systemd/systemd/pull/2508#issuecomment-190901170 Maybe fixes https://bugzilla.redhat.com/show_bug.cgi?id=1308771. --- src/basic/selinux-util.c | 16 ++++------------ src/basic/selinux-util.h | 2 +- src/core/main.c | 2 +- src/hostname/hostnamed.c | 2 +- src/locale/localed.c | 2 +- src/login/logind.c | 2 +- src/resolve/resolved.c | 2 +- src/sysusers/sysusers.c | 2 +- src/test/test-udev.c | 2 +- src/timedate/timedated.c | 2 +- src/tmpfiles/tmpfiles.c | 2 +- src/udev/udevadm.c | 2 +- src/udev/udevd.c | 2 +- src/update-done/update-done.c | 2 +- src/user-sessions/user-sessions.c | 2 +- 15 files changed, 18 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 6c63b9d652..71ceac1bcd 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -80,31 +80,23 @@ void mac_selinux_retest(void) { #endif } -int mac_selinux_init(const char *prefix) { +int mac_selinux_init(void) { int r = 0; #ifdef HAVE_SELINUX usec_t before_timestamp, after_timestamp; struct mallinfo before_mallinfo, after_mallinfo; - if (!mac_selinux_use()) + if (label_hnd) return 0; - if (label_hnd) + if (!mac_selinux_use()) return 0; before_mallinfo = mallinfo(); before_timestamp = now(CLOCK_MONOTONIC); - if (prefix) { - struct selinux_opt options[] = { - { .type = SELABEL_OPT_SUBSET, .value = prefix }, - }; - - label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); - } else - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); if (!label_hnd) { log_enforcing("Failed to initialize SELinux context: %m"); r = security_getenforce() == 1 ? -errno : 0; diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 27e8edb41b..ce6bc8e44c 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -29,7 +29,7 @@ bool mac_selinux_use(void); bool mac_selinux_have(void); void mac_selinux_retest(void); -int mac_selinux_init(const char *prefix); +int mac_selinux_init(void); void mac_selinux_finish(void); int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs); diff --git a/src/core/main.c b/src/core/main.c index 02c0488208..1783b9c7af 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1369,7 +1369,7 @@ int main(int argc, char *argv[]) { dual_timestamp_get(&security_finish_timestamp); } - if (mac_selinux_init(NULL) < 0) { + if (mac_selinux_init() < 0) { error_message = "Failed to initialize SELinux policy"; goto finish; } diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index c37e32e96b..d11756e615 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -706,7 +706,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); - mac_selinux_init("/etc"); + mac_selinux_init(); if (argc != 1) { log_error("This program takes no arguments."); diff --git a/src/locale/localed.c b/src/locale/localed.c index cc86c61edb..46405ca68a 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -1296,7 +1296,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); - mac_selinux_init("/etc"); + mac_selinux_init(); if (argc != 1) { log_error("This program takes no arguments."); diff --git a/src/login/logind.c b/src/login/logind.c index 933602eb08..d5f6757bd3 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1126,7 +1126,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = mac_selinux_init("/run"); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "Could not initialize labelling: %m"); goto finish; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index c7e2ab14d6..161ea03412 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 863c628323..4377f1b910 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1820,7 +1820,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 9cc64f7c68..d01789fe08 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; log_debug("version %s", VERSION); - mac_selinux_init("/dev"); + mac_selinux_init(); action = argv[1]; if (action == NULL) { diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 0febc36af8..ffec609c69 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -173,7 +173,7 @@ static int context_write_data_local_rtc(Context *c) { } } - mac_selinux_init("/etc"); + mac_selinux_init(); return write_string_file_atomic_label("/etc/adjtime", w); } diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 7b105a6bd4..f3487013cf 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2288,7 +2288,7 @@ int main(int argc, char *argv[]) { umask(0022); - mac_selinux_init(NULL); + mac_selinux_init(); items = ordered_hashmap_new(&string_hash_ops); globs = ordered_hashmap_new(&string_hash_ops); diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 7bd2c1ea42..a6a873e5de 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - mac_selinux_init("/dev"); + mac_selinux_init(); while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0) switch (c) { diff --git a/src/udev/udevd.c b/src/udev/udevd.c index bb92f16352..243df7386f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1695,7 +1695,7 @@ int main(int argc, char *argv[]) { umask(022); - r = mac_selinux_init("/dev"); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "could not initialize labelling: %m"); goto exit; diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 931e583785..da306a4444 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 8bf44e2100..9b29b5ba1d 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -40,7 +40,7 @@ int main(int argc, char*argv[]) { umask(0022); - mac_selinux_init(NULL); + mac_selinux_init(); if (streq(argv[1], "start")) { int r = 0; -- cgit v1.2.3-54-g00ecf From 5c5433ad32c3d911f0c66cc124d190d40a2b5f5b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 2 Mar 2016 10:16:39 -0500 Subject: selinux: use raw variants of security_compute_create and setfscreatecon As suggested by Evgeny Vereshchagin as a follow up for https://github.com/systemd/systemd/pull/2781#issuecomment-191043402. --- src/basic/selinux-util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 71ceac1bcd..5e6181f662 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -217,7 +217,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { return -errno; sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); if (r < 0) return -errno; #endif @@ -296,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * return -ENOMEM; sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); if (r < 0) return -errno; #endif @@ -350,7 +350,7 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) { log_enforcing("Failed to determine SELinux security context for %s: %m", path); } else { - if (setfscreatecon(filecon) >= 0) + if (setfscreatecon_raw(filecon) >= 0) return 0; /* Success! */ log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); -- cgit v1.2.3-54-g00ecf From ada94e69cd42f436eb1122c22eab092dcc042c6b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 1 Mar 2016 09:17:03 -0500 Subject: test-selinux: add some simple tests which call functions and print the results and timings --- .gitignore | 1 + Makefile.am | 9 +++- src/test/test-selinux.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/test/test-selinux.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 56a60ba726..539daadce0 100644 --- a/.gitignore +++ b/.gitignore @@ -246,6 +246,7 @@ /test-ring /test-rlimit-util /test-sched-prio +/test-selinux /test-set /test-sigbus /test-signal-util diff --git a/Makefile.am b/Makefile.am index 4f9072c0ff..9f64836f50 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1479,7 +1479,8 @@ tests += \ test-dns-domain \ test-install-root \ test-rlimit-util \ - test-signal-util + test-signal-util \ + test-selinux if HAVE_ACL tests += \ @@ -1873,6 +1874,12 @@ test_signal_util_SOURCES = \ test_signal_util_LDADD = \ libshared.la +test_selinux_SOURCES = \ + src/test/test-selinux.c + +test_selinux_LDADD = \ + libshared.la + BUILT_SOURCES += \ src/test/test-hashmap-ordered.c diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c new file mode 100644 index 0000000000..c2152269f8 --- /dev/null +++ b/src/test/test-selinux.c @@ -0,0 +1,117 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +#include "alloc-util.h" +#include "fd-util.h" +#include "log.h" +#include "selinux-util.h" +#include "time-util.h" + +static void test_testing(void) { + bool b; + + log_info("============ %s ==========", __func__); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %d", b); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %d", b); + + mac_selinux_retest(); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %d", b); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %d", b); +} + +static void test_loading(void) { + usec_t n1, n2; + int r; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + r = mac_selinux_init(); + n2 = now(CLOCK_MONOTONIC); + log_info_errno(r, "mac_selinux_init → %d (%m) %.2fs", r, (n2 - n1)/1e6); +} + +static void test_cleanup(void) { + usec_t n1, n2; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + mac_selinux_finish(); + n2 = now(CLOCK_MONOTONIC); + log_info("mac_selinux_finish → %.2fs", (n2 - n1)/1e6); +} + +static void test_misc(const char* fname) { + _cleanup_(mac_selinux_freep) char *label = NULL, *label2 = NULL, *label3 = NULL; + int r; + _cleanup_close_ int fd = -1; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_get_our_label(&label); + log_info_errno(r, "mac_selinux_get_our_label → %d (%m), \"%s\"", r, label); + + r = mac_selinux_get_create_label_from_exe(fname, &label2); + log_info_errno(r, "mac_selinux_create_label_from_exe → %d (%m), \"%s\"", r, label2); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + assert_se(fd >= 0); + + r = mac_selinux_get_child_mls_label(fd, fname, label2, &label3); + log_info_errno(r, "mac_selinux_get_child_mls_label → %d (%m), \"%s\"", r, label3); +} + +static void test_create_file_prepare(const char* fname) { + int r; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_create_file_prepare(fname, S_IRWXU); + log_info_errno(r, "mac_selinux_create_file_prepare → %d (%m)", r); + + mac_selinux_create_file_clear(); +} + +int main(int argc, char **argv) { + const char *path = SYSTEMD_BINARY_PATH; + if (argc >= 2) + path = argv[1]; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + test_testing(); + test_loading(); + test_misc(path); + test_create_file_prepare(path); + test_cleanup(); + + return 0; +} -- cgit v1.2.3-54-g00ecf From fed527aa5b1bf6855de2f76c22689b99a810122b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 1 Mar 2016 11:52:03 -0500 Subject: test-sizeof: add a helper which prints variable sizes and signedness This helps to understand misleading gcc warnings about type mismatches. --- .gitignore | 1 + Makefile.am | 9 ++++++++- src/test/test-sizeof.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/test/test-sizeof.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 539daadce0..18db046cac 100644 --- a/.gitignore +++ b/.gitignore @@ -248,6 +248,7 @@ /test-sched-prio /test-selinux /test-set +/test-sizeof /test-sigbus /test-signal-util /test-siphash24 diff --git a/Makefile.am b/Makefile.am index 9f64836f50..0f17bad8b1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1480,7 +1480,8 @@ tests += \ test-install-root \ test-rlimit-util \ test-signal-util \ - test-selinux + test-selinux \ + test-sizeof if HAVE_ACL tests += \ @@ -1880,6 +1881,12 @@ test_selinux_SOURCES = \ test_selinux_LDADD = \ libshared.la +test_sizeof_SOURCES = \ + src/test/test-sizeof.c + +test_sizeof_LDADD = \ + libshared.la + BUILT_SOURCES += \ src/test/test-hashmap-ordered.c diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c new file mode 100644 index 0000000000..8f99a13772 --- /dev/null +++ b/src/test/test-sizeof.c @@ -0,0 +1,53 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "log.h" +#include "time-util.h" + +/* Print information about various types. Useful when diagnosing + * gcc diagnostics on an unfamiliar architecture. */ + +#pragma GCC diagnostic ignored "-Wtype-limits" + +#define info(t) \ + log_info("%s → %zu bits%s", STRINGIFY(t), \ + sizeof(t)*CHAR_BIT, \ + strstr(STRINGIFY(t), "signed") ? "" : \ + ((t)-1 < (t)0 ? ", signed" : ", unsigned")); + +int main(void) { + info(char); + info(signed char); + info(unsigned char); + info(short unsigned); + info(unsigned); + info(long unsigned); + info(long long unsigned); + + info(float); + info(double); + info(long double); + + info(size_t); + info(ssize_t); + info(time_t); + info(usec_t); + + return 0; +} -- cgit v1.2.3-54-g00ecf From 6307c39b94344b901c1d6e0df7ee58644a8809bf Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 1 Mar 2016 12:08:02 -0500 Subject: Redefine 32bit time_t format to signed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems that it is signed both on i386 and arm. Avoids a stupid gcc warning on arm: src/udev/udevadm-monitor.c: In function ‘print_device’: src/udev/udevadm-monitor.c:44:16: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 3 has type ‘__time_t {aka long int}’ [-Wformat=] printf("%-6s[%"PRI_TIME".%06ld] %-8s %s (%s)\n", ^ --- src/basic/formats-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/formats-util.h b/src/basic/formats-util.h index ce516b117d..9b4e8e98fa 100644 --- a/src/basic/formats-util.h +++ b/src/basic/formats-util.h @@ -49,7 +49,7 @@ #if SIZEOF_TIME_T == 8 # define PRI_TIME PRIi64 #elif SIZEOF_TIME_T == 4 -# define PRI_TIME PRIu32 +# define PRI_TIME "li" #else # error Unknown time_t size #endif -- cgit v1.2.3-54-g00ecf From 5f18271ec100b3035bb65c17d08f04f0d94022d6 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 22:06:47 +0100 Subject: systemctl: rm empty dropin dirs after cancelled edit Fixes #2734 --- src/systemctl/systemctl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 11e26ce737..c741baf58a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6162,9 +6162,19 @@ static int edit(int argc, char *argv[], void *userdata) { r = daemon_reload(argc, argv, userdata); end: - STRV_FOREACH_PAIR(original, tmp, paths) + STRV_FOREACH_PAIR(original, tmp, paths) { (void) unlink(*tmp); + /* Removing empty dropin dirs */ + if (!arg_full) { + _cleanup_free_ char *dir = dirname_malloc(*original); + /* no need to check if the dir is empty, rmdir + * does nothing if it is not the case. + */ + (void) rmdir(dir); + } + } + return r; } -- cgit v1.2.3-54-g00ecf From 043717f9d3c75e0ac2621f76362f6025443f0de9 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 18:15:24 +0100 Subject: systemctl: add missing OOM check --- src/systemctl/systemctl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c741baf58a..a62f4bf2f5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6167,7 +6167,12 @@ end: /* Removing empty dropin dirs */ if (!arg_full) { - _cleanup_free_ char *dir = dirname_malloc(*original); + _cleanup_free_ char *dir; + + dir = dirname_malloc(*original); + if (!dir) + return log_oom(); + /* no need to check if the dir is empty, rmdir * does nothing if it is not the case. */ -- cgit v1.2.3-54-g00ecf From 134714368eed920d5bd814da02b651b77c8fa73e Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 22:44:04 +0100 Subject: tests: move hexdecoct tests to test-hexdecoct.c --- .gitignore | 1 + Makefile.am | 7 + src/test/test-hexdecoct.c | 387 ++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 360 ------------------------------------------ 4 files changed, 395 insertions(+), 360 deletions(-) create mode 100644 src/test/test-hexdecoct.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 18db046cac..36bad5c3fb 100644 --- a/.gitignore +++ b/.gitignore @@ -189,6 +189,7 @@ /test-firewall-util /test-fstab-util /test-hashmap +/test-hexdecoct /test-hostname /test-hostname-util /test-id128 diff --git a/Makefile.am b/Makefile.am index 0f17bad8b1..ab46b3f376 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1426,6 +1426,7 @@ tests += \ test-utf8 \ test-ellipsize \ test-util \ + test-hexdecoct \ test-string-util \ test-extract-word \ test-parse-util \ @@ -1755,6 +1756,12 @@ test_util_SOURCES = \ test_util_LDADD = \ libshared.la +test_hexdecoct_SOURCES = \ + src/test/test-hexdecoct.c + +test_hexdecoct_LDADD = \ + libbasic.la + test_string_util_SOURCES = \ src/test/test-string-util.c diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c new file mode 100644 index 0000000000..276f25d091 --- /dev/null +++ b/src/test/test-hexdecoct.c @@ -0,0 +1,387 @@ +/*** + 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 . +***/ + +#include "alloc-util.h" +#include "hexdecoct.h" +#include "macro.h" +#include "string-util.h" + +static void test_hexchar(void) { + assert_se(hexchar(0xa) == 'a'); + assert_se(hexchar(0x0) == '0'); +} + +static void test_unhexchar(void) { + assert_se(unhexchar('a') == 0xA); + assert_se(unhexchar('A') == 0xA); + assert_se(unhexchar('0') == 0x0); +} + +static void test_base32hexchar(void) { + assert_se(base32hexchar(0) == '0'); + assert_se(base32hexchar(9) == '9'); + assert_se(base32hexchar(10) == 'A'); + assert_se(base32hexchar(31) == 'V'); +} + +static void test_unbase32hexchar(void) { + assert_se(unbase32hexchar('0') == 0); + assert_se(unbase32hexchar('9') == 9); + assert_se(unbase32hexchar('A') == 10); + assert_se(unbase32hexchar('V') == 31); + assert_se(unbase32hexchar('=') == -EINVAL); +} + +static void test_base64char(void) { + assert_se(base64char(0) == 'A'); + assert_se(base64char(26) == 'a'); + assert_se(base64char(63) == '/'); +} + +static void test_unbase64char(void) { + assert_se(unbase64char('A') == 0); + assert_se(unbase64char('Z') == 25); + assert_se(unbase64char('a') == 26); + assert_se(unbase64char('z') == 51); + assert_se(unbase64char('0') == 52); + assert_se(unbase64char('9') == 61); + assert_se(unbase64char('+') == 62); + assert_se(unbase64char('/') == 63); + assert_se(unbase64char('=') == -EINVAL); +} + +static void test_octchar(void) { + assert_se(octchar(00) == '0'); + assert_se(octchar(07) == '7'); +} + +static void test_unoctchar(void) { + assert_se(unoctchar('0') == 00); + assert_se(unoctchar('7') == 07); +} + +static void test_decchar(void) { + assert_se(decchar(0) == '0'); + assert_se(decchar(9) == '9'); +} + +static void test_undecchar(void) { + assert_se(undecchar('0') == 0); + assert_se(undecchar('9') == 9); +} + +static void test_unhexmem(void) { + const char *hex = "efa214921"; + const char *hex_invalid = "efa214921o"; + _cleanup_free_ char *hex2 = NULL; + _cleanup_free_ void *mem = NULL; + size_t len; + + assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); + assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); + assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); + + assert_se((hex2 = hexmem(mem, len))); + + free(mem); + + assert_se(memcmp(hex, hex2, strlen(hex)) == 0); + + free(hex2); + + assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); + assert_se((hex2 = hexmem(mem, len))); + assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base32hexmem(void) { + char *b32; + + b32 = base32hexmem("", strlen(""), true); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), true); + assert_se(b32); + assert_se(streq(b32, "CO======")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNG====")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMU===")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG=")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8======")); + free(b32); + + b32 = base32hexmem("", strlen(""), false); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), false); + assert_se(b32); + assert_se(streq(b32, "CO")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNG")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMU")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8")); + free(b32); +} + +static void test_unbase32hexmem(void) { + void *mem; + size_t len; + + assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base64mem(void) { + char *b64; + + assert_se(base64mem("", strlen(""), &b64) == 0); + assert_se(streq(b64, "")); + free(b64); + + assert_se(base64mem("f", strlen("f"), &b64) == 4); + assert_se(streq(b64, "Zg==")); + free(b64); + + assert_se(base64mem("fo", strlen("fo"), &b64) == 4); + assert_se(streq(b64, "Zm8=")); + free(b64); + + assert_se(base64mem("foo", strlen("foo"), &b64) == 4); + assert_se(streq(b64, "Zm9v")); + free(b64); + + assert_se(base64mem("foob", strlen("foob"), &b64) == 8); + assert_se(streq(b64, "Zm9vYg==")); + free(b64); + + assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmE=")); + free(b64); + + assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmFy")); + free(b64); +} + +static void test_unbase64mem(void) { + void *mem; + size_t len; + + assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); + assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); +} + +static void test_hexdump(void) { + uint8_t data[146]; + unsigned i; + + hexdump(stdout, NULL, 0); + hexdump(stdout, "", 0); + hexdump(stdout, "", 1); + hexdump(stdout, "x", 1); + hexdump(stdout, "x", 2); + hexdump(stdout, "foobar", 7); + hexdump(stdout, "f\nobar", 7); + hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); + + for (i = 0; i < ELEMENTSOF(data); i++) + data[i] = i*2; + + hexdump(stdout, data, sizeof(data)); +} + +int main(int argc, char *argv[]) { + test_hexchar(); + test_unhexchar(); + test_base32hexchar(); + test_unbase32hexchar(); + test_base64char(); + test_unbase64char(); + test_octchar(); + test_unoctchar(); + test_decchar(); + test_undecchar(); + test_unhexmem(); + test_base32hexmem(); + test_unbase32hexmem(); + test_base64mem(); + test_unbase64mem(); + test_hexdump(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 9a8a265790..2f1464d360 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -37,7 +37,6 @@ #include "fs-util.h" #include "fstab-util.h" #include "glob-util.h" -#include "hexdecoct.h" #include "io-util.h" #include "mkdir.h" #include "parse-util.h" @@ -286,330 +285,6 @@ static void test_in_charset(void) { assert_se(!in_charset("dddaaabbbcccc", "abc f")); } -static void test_hexchar(void) { - assert_se(hexchar(0xa) == 'a'); - assert_se(hexchar(0x0) == '0'); -} - -static void test_unhexchar(void) { - assert_se(unhexchar('a') == 0xA); - assert_se(unhexchar('A') == 0xA); - assert_se(unhexchar('0') == 0x0); -} - -static void test_base32hexchar(void) { - assert_se(base32hexchar(0) == '0'); - assert_se(base32hexchar(9) == '9'); - assert_se(base32hexchar(10) == 'A'); - assert_se(base32hexchar(31) == 'V'); -} - -static void test_unbase32hexchar(void) { - assert_se(unbase32hexchar('0') == 0); - assert_se(unbase32hexchar('9') == 9); - assert_se(unbase32hexchar('A') == 10); - assert_se(unbase32hexchar('V') == 31); - assert_se(unbase32hexchar('=') == -EINVAL); -} - -static void test_base64char(void) { - assert_se(base64char(0) == 'A'); - assert_se(base64char(26) == 'a'); - assert_se(base64char(63) == '/'); -} - -static void test_unbase64char(void) { - assert_se(unbase64char('A') == 0); - assert_se(unbase64char('Z') == 25); - assert_se(unbase64char('a') == 26); - assert_se(unbase64char('z') == 51); - assert_se(unbase64char('0') == 52); - assert_se(unbase64char('9') == 61); - assert_se(unbase64char('+') == 62); - assert_se(unbase64char('/') == 63); - assert_se(unbase64char('=') == -EINVAL); -} - -static void test_octchar(void) { - assert_se(octchar(00) == '0'); - assert_se(octchar(07) == '7'); -} - -static void test_unoctchar(void) { - assert_se(unoctchar('0') == 00); - assert_se(unoctchar('7') == 07); -} - -static void test_decchar(void) { - assert_se(decchar(0) == '0'); - assert_se(decchar(9) == '9'); -} - -static void test_undecchar(void) { - assert_se(undecchar('0') == 0); - assert_se(undecchar('9') == 9); -} - -static void test_unhexmem(void) { - const char *hex = "efa214921"; - const char *hex_invalid = "efa214921o"; - _cleanup_free_ char *hex2 = NULL; - _cleanup_free_ void *mem = NULL; - size_t len; - - assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); - assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); - assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); - - assert_se((hex2 = hexmem(mem, len))); - - free(mem); - - assert_se(memcmp(hex, hex2, strlen(hex)) == 0); - - free(hex2); - - assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); - assert_se((hex2 = hexmem(mem, len))); - assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base32hexmem(void) { - char *b32; - - b32 = base32hexmem("", strlen(""), true); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), true); - assert_se(b32); - assert_se(streq(b32, "CO======")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNG====")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMU===")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG=")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8======")); - free(b32); - - b32 = base32hexmem("", strlen(""), false); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), false); - assert_se(b32); - assert_se(streq(b32, "CO")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNG")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMU")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8")); - free(b32); -} - -static void test_unbase32hexmem(void) { - void *mem; - size_t len; - - assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); - - assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - - assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base64mem(void) { - char *b64; - - assert_se(base64mem("", strlen(""), &b64) == 0); - assert_se(streq(b64, "")); - free(b64); - - assert_se(base64mem("f", strlen("f"), &b64) == 4); - assert_se(streq(b64, "Zg==")); - free(b64); - - assert_se(base64mem("fo", strlen("fo"), &b64) == 4); - assert_se(streq(b64, "Zm8=")); - free(b64); - - assert_se(base64mem("foo", strlen("foo"), &b64) == 4); - assert_se(streq(b64, "Zm9v")); - free(b64); - - assert_se(base64mem("foob", strlen("foob"), &b64) == 8); - assert_se(streq(b64, "Zm9vYg==")); - free(b64); - - assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); - assert_se(streq(b64, "Zm9vYmE=")); - free(b64); - - assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); - assert_se(streq(b64, "Zm9vYmFy")); - free(b64); -} - -static void test_unbase64mem(void) { - void *mem; - size_t len; - - assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); - assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); -} - static void test_cescape(void) { _cleanup_free_ char *escaped; @@ -993,25 +668,6 @@ static void test_writing_tmpfile(void) { unlink(name); } -static void test_hexdump(void) { - uint8_t data[146]; - unsigned i; - - hexdump(stdout, NULL, 0); - hexdump(stdout, "", 0); - hexdump(stdout, "", 1); - hexdump(stdout, "x", 1); - hexdump(stdout, "x", 2); - hexdump(stdout, "foobar", 7); - hexdump(stdout, "f\nobar", 7); - hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); - - for (i = 0; i < ELEMENTSOF(data); i++) - data[i] = i*2; - - hexdump(stdout, data, sizeof(data)); -} - static void test_log2i(void) { assert_se(log2i(1) == 0); assert_se(log2i(2) == 1); @@ -1653,21 +1309,6 @@ int main(int argc, char *argv[]) { test_strstrip(); test_delete_chars(); test_in_charset(); - test_hexchar(); - test_unhexchar(); - test_base32hexchar(); - test_unbase32hexchar(); - test_base64char(); - test_unbase64char(); - test_octchar(); - test_unoctchar(); - test_decchar(); - test_undecchar(); - test_unhexmem(); - test_base32hexmem(); - test_unbase32hexmem(); - test_base64mem(); - test_unbase64mem(); test_cescape(); test_cunescape(); test_foreach_word(); @@ -1684,7 +1325,6 @@ int main(int argc, char *argv[]) { test_get_files_in_directory(); test_in_set(); test_writing_tmpfile(); - test_hexdump(); test_log2i(); test_foreach_string(); test_filename_is_valid(); -- cgit v1.2.3-54-g00ecf From 6571a64ec9f4a1fc979644999d52958726d924bc Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 22:57:20 +0100 Subject: tests: move string related tests to test-string-util.c --- src/test/test-string-util.c | 265 ++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 260 ------------------------------------------- 2 files changed, 265 insertions(+), 260 deletions(-) (limited to 'src') diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 9b48e95998..d0f84d70bc 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -17,7 +17,10 @@ along with systemd; If not, see . ***/ +#include "alloc-util.h" +#include "macro.h" #include "string-util.h" +#include "strv.h" static void test_string_erase(void) { char *x; @@ -97,9 +100,271 @@ static void test_ascii_strcasecmp_nn(void) { assert_se(ascii_strcasecmp_nn("BBbb", 4, "aaaa", 4) > 0); } +static void test_streq_ptr(void) { + assert_se(streq_ptr(NULL, NULL)); + assert_se(!streq_ptr("abc", "cdef")); +} + +static void test_strstrip(void) { + char *r; + char input[] = " hello, waldo. "; + + r = strstrip(input); + assert_se(streq(r, "hello, waldo.")); +} + +static void test_strextend(void) { + _cleanup_free_ char *str = strdup("0123"); + strextend(&str, "456", "78", "9", NULL); + assert_se(streq(str, "0123456789")); +} + +static void test_strrep(void) { + _cleanup_free_ char *one, *three, *zero; + one = strrep("waldo", 1); + three = strrep("waldo", 3); + zero = strrep("waldo", 0); + + assert_se(streq(one, "waldo")); + assert_se(streq(three, "waldowaldowaldo")); + assert_se(streq(zero, "")); +} + + +static void test_strappend(void) { + _cleanup_free_ char *t1, *t2, *t3, *t4; + + t1 = strappend(NULL, NULL); + assert_se(streq(t1, "")); + + t2 = strappend(NULL, "suf"); + assert_se(streq(t2, "suf")); + + t3 = strappend("pre", NULL); + assert_se(streq(t3, "pre")); + + t4 = strappend("pre", "suf"); + assert_se(streq(t4, "presuf")); +} + +static void test_string_has_cc(void) { + assert_se(string_has_cc("abc\1", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t\a")); + + assert_se(!string_has_cc("abc\t\t", "\t")); + assert_se(!string_has_cc("abc\t\t\a", "\t\a")); + assert_se(!string_has_cc("a\ab\tc", "\t\a")); +} + +static void test_ascii_strlower(void) { + char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; + assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); +} + +static void test_strshorten(void) { + char s[] = "foobar"; + + assert_se(strlen(strshorten(s, 6)) == 6); + assert_se(strlen(strshorten(s, 12)) == 6); + assert_se(strlen(strshorten(s, 2)) == 2); + assert_se(strlen(strshorten(s, 0)) == 0); +} + +static void test_strjoina(void) { + char *actual; + + actual = strjoina("", "foo", "bar"); + assert_se(streq(actual, "foobar")); + + actual = strjoina("foo", "bar", "baz"); + assert_se(streq(actual, "foobarbaz")); + + actual = strjoina("foo", "", "bar", "baz"); + assert_se(streq(actual, "foobarbaz")); + + actual = strjoina("foo"); + assert_se(streq(actual, "foo")); + + actual = strjoina(NULL); + assert_se(streq(actual, "")); + + actual = strjoina(NULL, "foo"); + assert_se(streq(actual, "")); + + actual = strjoina("foo", NULL, "bar"); + assert_se(streq(actual, "foo")); +} + +static void test_strcmp_ptr(void) { + assert_se(strcmp_ptr(NULL, NULL) == 0); + assert_se(strcmp_ptr("", NULL) > 0); + assert_se(strcmp_ptr("foo", NULL) > 0); + assert_se(strcmp_ptr(NULL, "") < 0); + assert_se(strcmp_ptr(NULL, "bar") < 0); + assert_se(strcmp_ptr("foo", "bar") > 0); + assert_se(strcmp_ptr("bar", "baz") < 0); + assert_se(strcmp_ptr("foo", "foo") == 0); + assert_se(strcmp_ptr("", "") == 0); +} + +static void test_foreach_word(void) { + const char *word, *state; + size_t l; + int i = 0; + const char test[] = "test abc d\te f "; + const char * const expected[] = { + "test", + "abc", + "d", + "e", + "f", + "", + NULL + }; + + FOREACH_WORD(word, l, test, state) + assert_se(strneq(expected[i++], word, l)); +} + +static void check(const char *test, char** expected, bool trailing) { + const char *word, *state; + size_t l; + int i = 0; + + printf("<<<%s>>>\n", test); + FOREACH_WORD_QUOTED(word, l, test, state) { + _cleanup_free_ char *t = NULL; + + assert_se(t = strndup(word, l)); + assert_se(strneq(expected[i++], word, l)); + printf("<%s>\n", t); + } + printf("<<<%s>>>\n", state); + assert_se(expected[i] == NULL); + assert_se(isempty(state) == !trailing); +} + +static void test_foreach_word_quoted(void) { + check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", + STRV_MAKE("test", + "a", + "b", + "c", + "d", + "e", + "", + "", + "hhh", + "", + "", + "a b c"), + false); + + check("test \"xxx", + STRV_MAKE("test"), + true); + + check("test\\", + STRV_MAKE_EMPTY, + true); +} + +static void test_endswith(void) { + assert_se(endswith("foobar", "bar")); + assert_se(endswith("foobar", "")); + assert_se(endswith("foobar", "foobar")); + assert_se(endswith("", "")); + + assert_se(!endswith("foobar", "foo")); + assert_se(!endswith("foobar", "foobarfoofoo")); +} + +static void test_endswith_no_case(void) { + assert_se(endswith_no_case("fooBAR", "bar")); + assert_se(endswith_no_case("foobar", "")); + assert_se(endswith_no_case("foobar", "FOOBAR")); + assert_se(endswith_no_case("", "")); + + assert_se(!endswith_no_case("foobar", "FOO")); + assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO")); +} + +static void test_delete_chars(void) { + char *r; + char input[] = " hello, waldo. abc"; + + r = delete_chars(input, WHITESPACE); + assert_se(streq(r, "hello,waldo.abc")); +} + +static void test_in_charset(void) { + assert_se(in_charset("dddaaabbbcccc", "abcd")); + assert_se(!in_charset("dddaaabbbcccc", "abc f")); +} + +static void test_split_pair(void) { + _cleanup_free_ char *a = NULL, *b = NULL; + + assert_se(split_pair("", "", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); + assert_se(split_pair("", "=", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); + assert_se(streq(a, "foo")); + assert_se(streq(b, "bar")); + free(a); + free(b); + assert_se(split_pair("==", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "")); + free(a); + free(b); + + assert_se(split_pair("===", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "=")); +} + +static void test_first_word(void) { + assert_se(first_word("Hello", "")); + assert_se(first_word("Hello", "Hello")); + assert_se(first_word("Hello world", "Hello")); + assert_se(first_word("Hello\tworld", "Hello")); + assert_se(first_word("Hello\nworld", "Hello")); + assert_se(first_word("Hello\rworld", "Hello")); + assert_se(first_word("Hello ", "Hello")); + + assert_se(!first_word("Hello", "Hellooo")); + assert_se(!first_word("Hello", "xxxxx")); + assert_se(!first_word("Hellooo", "Hello")); +} + int main(int argc, char *argv[]) { test_string_erase(); test_ascii_strcasecmp_n(); test_ascii_strcasecmp_nn(); + test_streq_ptr(); + test_strstrip(); + test_strextend(); + test_strrep(); + test_strappend(); + test_string_has_cc(); + test_ascii_strlower(); + test_strshorten(); + test_strjoina(); + test_strcmp_ptr(); + test_foreach_word(); + test_foreach_word_quoted(); + test_endswith(); + test_endswith_no_case(); + test_delete_chars(); + test_in_charset(); + test_split_pair(); + test_first_word(); + return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 2f1464d360..3d764eac66 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -55,11 +55,6 @@ #include "web-util.h" #include "xattr-util.h" -static void test_streq_ptr(void) { - assert_se(streq_ptr(NULL, NULL)); - assert_se(!streq_ptr("abc", "cdef")); -} - static void test_align_power2(void) { unsigned long i, p2; @@ -196,20 +191,6 @@ static void test_div_round_up(void) { assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); } -static void test_first_word(void) { - assert_se(first_word("Hello", "")); - assert_se(first_word("Hello", "Hello")); - assert_se(first_word("Hello world", "Hello")); - assert_se(first_word("Hello\tworld", "Hello")); - assert_se(first_word("Hello\nworld", "Hello")); - assert_se(first_word("Hello\rworld", "Hello")); - assert_se(first_word("Hello ", "Hello")); - - assert_se(!first_word("Hello", "Hellooo")); - assert_se(!first_word("Hello", "xxxxx")); - assert_se(!first_word("Hellooo", "Hello")); -} - static void test_close_many(void) { int fds[3]; char name0[] = "/tmp/test-close-many.XXXXXX"; @@ -248,43 +229,6 @@ static void test_parse_uid(void) { assert_se(r == -EINVAL); } -static void test_strappend(void) { - _cleanup_free_ char *t1, *t2, *t3, *t4; - - t1 = strappend(NULL, NULL); - assert_se(streq(t1, "")); - - t2 = strappend(NULL, "suf"); - assert_se(streq(t2, "suf")); - - t3 = strappend("pre", NULL); - assert_se(streq(t3, "pre")); - - t4 = strappend("pre", "suf"); - assert_se(streq(t4, "presuf")); -} - -static void test_strstrip(void) { - char *r; - char input[] = " hello, waldo. "; - - r = strstrip(input); - assert_se(streq(r, "hello, waldo.")); -} - -static void test_delete_chars(void) { - char *r; - char input[] = " hello, waldo. abc"; - - r = delete_chars(input, WHITESPACE); - assert_se(streq(r, "hello,waldo.abc")); -} - -static void test_in_charset(void) { - assert_se(in_charset("dddaaabbbcccc", "abcd")); - assert_se(!in_charset("dddaaabbbcccc", "abc f")); -} - static void test_cescape(void) { _cleanup_free_ char *escaped; @@ -335,68 +279,6 @@ static void test_cunescape(void) { assert_se(streq_ptr(unescaped, ";")); } -static void test_foreach_word(void) { - const char *word, *state; - size_t l; - int i = 0; - const char test[] = "test abc d\te f "; - const char * const expected[] = { - "test", - "abc", - "d", - "e", - "f", - "", - NULL - }; - - FOREACH_WORD(word, l, test, state) - assert_se(strneq(expected[i++], word, l)); -} - -static void check(const char *test, char** expected, bool trailing) { - const char *word, *state; - size_t l; - int i = 0; - - printf("<<<%s>>>\n", test); - FOREACH_WORD_QUOTED(word, l, test, state) { - _cleanup_free_ char *t = NULL; - - assert_se(t = strndup(word, l)); - assert_se(strneq(expected[i++], word, l)); - printf("<%s>\n", t); - } - printf("<<<%s>>>\n", state); - assert_se(expected[i] == NULL); - assert_se(isempty(state) == !trailing); -} - -static void test_foreach_word_quoted(void) { - check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", - STRV_MAKE("test", - "a", - "b", - "c", - "d", - "e", - "", - "", - "hhh", - "", - "", - "a b c"), - false); - - check("test \"xxx", - STRV_MAKE("test"), - true); - - check("test\\", - STRV_MAKE_EMPTY, - true); -} - static void test_memdup_multiply(void) { int org[] = {1, 2, 3}; int *dup; @@ -552,45 +434,6 @@ static void test_config_parse_iec_uint64(void) { assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); } -static void test_strextend(void) { - _cleanup_free_ char *str = strdup("0123"); - strextend(&str, "456", "78", "9", NULL); - assert_se(streq(str, "0123456789")); -} - -static void test_strrep(void) { - _cleanup_free_ char *one, *three, *zero; - one = strrep("waldo", 1); - three = strrep("waldo", 3); - zero = strrep("waldo", 0); - - assert_se(streq(one, "waldo")); - assert_se(streq(three, "waldowaldowaldo")); - assert_se(streq(zero, "")); -} - -static void test_split_pair(void) { - _cleanup_free_ char *a = NULL, *b = NULL; - - assert_se(split_pair("", "", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); - assert_se(split_pair("", "=", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); - assert_se(streq(a, "foo")); - assert_se(streq(b, "bar")); - free(a); - free(b); - assert_se(split_pair("==", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "")); - free(a); - free(b); - - assert_se(split_pair("===", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "=")); -} - static void test_fstab_node_to_udev_node(void) { char *n; @@ -718,25 +561,6 @@ static void test_filename_is_valid(void) { assert_se(filename_is_valid("o.o")); } -static void test_string_has_cc(void) { - assert_se(string_has_cc("abc\1", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t\a")); - - assert_se(!string_has_cc("abc\t\t", "\t")); - assert_se(!string_has_cc("abc\t\t\a", "\t\a")); - assert_se(!string_has_cc("a\ab\tc", "\t\a")); -} - -static void test_ascii_strlower(void) { - char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; - assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); -} - static void test_files_same(void) { _cleanup_close_ int fd = -1; char name[] = "/tmp/test-files_same.XXXXXX"; @@ -789,26 +613,6 @@ static void test_file_in_same_dir(void) { free(t); } -static void test_endswith(void) { - assert_se(endswith("foobar", "bar")); - assert_se(endswith("foobar", "")); - assert_se(endswith("foobar", "foobar")); - assert_se(endswith("", "")); - - assert_se(!endswith("foobar", "foo")); - assert_se(!endswith("foobar", "foobarfoofoo")); -} - -static void test_endswith_no_case(void) { - assert_se(endswith_no_case("fooBAR", "bar")); - assert_se(endswith_no_case("foobar", "")); - assert_se(endswith_no_case("foobar", "FOOBAR")); - assert_se(endswith_no_case("", "")); - - assert_se(!endswith_no_case("foobar", "FOO")); - assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO")); -} - static void test_close_nointr(void) { char name[] = "/tmp/test-test-close_nointr.XXXXXX"; int fd; @@ -877,40 +681,6 @@ static void test_ignore_signals(void) { assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); } -static void test_strshorten(void) { - char s[] = "foobar"; - - assert_se(strlen(strshorten(s, 6)) == 6); - assert_se(strlen(strshorten(s, 12)) == 6); - assert_se(strlen(strshorten(s, 2)) == 2); - assert_se(strlen(strshorten(s, 0)) == 0); -} - -static void test_strjoina(void) { - char *actual; - - actual = strjoina("", "foo", "bar"); - assert_se(streq(actual, "foobar")); - - actual = strjoina("foo", "bar", "baz"); - assert_se(streq(actual, "foobarbaz")); - - actual = strjoina("foo", "", "bar", "baz"); - assert_se(streq(actual, "foobarbaz")); - - actual = strjoina("foo"); - assert_se(streq(actual, "foo")); - - actual = strjoina(NULL); - assert_se(streq(actual, "")); - - actual = strjoina(NULL, "foo"); - assert_se(streq(actual, "")); - - actual = strjoina("foo", NULL, "bar"); - assert_se(streq(actual, "foo")); -} - static void test_is_symlink(void) { char name[] = "/tmp/test-is_symlink.XXXXXX"; char name_link[] = "/tmp/test-is_symlink.link"; @@ -1242,18 +1012,6 @@ static void test_tempfn(void) { free(ret); } -static void test_strcmp_ptr(void) { - assert_se(strcmp_ptr(NULL, NULL) == 0); - assert_se(strcmp_ptr("", NULL) > 0); - assert_se(strcmp_ptr("foo", NULL) > 0); - assert_se(strcmp_ptr(NULL, "") < 0); - assert_se(strcmp_ptr(NULL, "bar") < 0); - assert_se(strcmp_ptr("foo", "bar") > 0); - assert_se(strcmp_ptr("bar", "baz") < 0); - assert_se(strcmp_ptr("foo", "foo") == 0); - assert_se(strcmp_ptr("", "") == 0); -} - static void test_fgetxattrat_fake(void) { char t[] = "/var/tmp/xattrtestXXXXXX"; _cleanup_close_ int fd = -1; @@ -1296,31 +1054,20 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_streq_ptr(); test_align_power2(); test_max(); test_container_of(); test_alloca(); test_div_round_up(); - test_first_word(); test_close_many(); test_parse_uid(); - test_strappend(); - test_strstrip(); - test_delete_chars(); - test_in_charset(); test_cescape(); test_cunescape(); - test_foreach_word(); - test_foreach_word_quoted(); test_memdup_multiply(); test_u64log2(); test_protect_errno(); test_parse_cpu_set(); test_config_parse_iec_uint64(); - test_strextend(); - test_strrep(); - test_split_pair(); test_fstab_node_to_udev_node(); test_get_files_in_directory(); test_in_set(); @@ -1328,19 +1075,13 @@ int main(int argc, char *argv[]) { test_log2i(); test_foreach_string(); test_filename_is_valid(); - test_string_has_cc(); - test_ascii_strlower(); test_files_same(); test_is_valid_documentation_url(); test_file_in_same_dir(); - test_endswith(); - test_endswith_no_case(); test_close_nointr(); test_unlink_noerrno(); test_readlink_and_make_absolute(); test_ignore_signals(); - test_strshorten(); - test_strjoina(); test_is_symlink(); test_search_and_fopen(); test_search_and_fopen_nulstr(); @@ -1354,7 +1095,6 @@ int main(int argc, char *argv[]) { test_shell_escape(); test_shell_maybe_quote(); test_tempfn(); - test_strcmp_ptr(); test_fgetxattrat_fake(); test_runlevel_to_target(); -- cgit v1.2.3-54-g00ecf From ebde5cb26179bf1518501891d2d2bc7d1f59ecc5 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:01:38 +0100 Subject: tests: move strv related tests to test-strv.c --- src/test/test-strv.c | 21 +++++++++++++++++++++ src/test/test-util.c | 20 -------------------- 2 files changed, 21 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/test/test-strv.c b/src/test/test-strv.c index ef451c6abf..fea1f848cd 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -660,6 +660,25 @@ static void test_strv_make_nulstr(void) { test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux")); } +static void test_foreach_string(void) { + const char * const t[] = { + "foo", + "bar", + "waldo", + NULL + }; + const char *x; + unsigned i = 0; + + FOREACH_STRING(x, "foo", "bar", "waldo") + assert_se(streq_ptr(t[i++], x)); + + assert_se(i == 3); + + FOREACH_STRING(x, "zzz") + assert_se(streq(x, "zzz")); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -724,5 +743,7 @@ int main(int argc, char *argv[]) { test_strv_extend_n(); test_strv_make_nulstr(); + test_foreach_string(); + return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 3d764eac66..2b44b91170 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -522,25 +522,6 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } -static void test_foreach_string(void) { - const char * const t[] = { - "foo", - "bar", - "waldo", - NULL - }; - const char *x; - unsigned i = 0; - - FOREACH_STRING(x, "foo", "bar", "waldo") - assert_se(streq_ptr(t[i++], x)); - - assert_se(i == 3); - - FOREACH_STRING(x, "zzz") - assert_se(streq(x, "zzz")); -} - static void test_filename_is_valid(void) { char foo[FILENAME_MAX+2]; int i; @@ -1073,7 +1054,6 @@ int main(int argc, char *argv[]) { test_in_set(); test_writing_tmpfile(); test_log2i(); - test_foreach_string(); test_filename_is_valid(); test_files_same(); test_is_valid_documentation_url(); -- cgit v1.2.3-54-g00ecf From 45e0b1f68c1b3f850b9ca683db92c0c8d1f95ec2 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:10:11 +0100 Subject: tests: move escape related tests to test-escape.c --- .gitignore | 1 + Makefile.am | 7 +++ src/test/test-escape.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 88 -------------------------------------- 4 files changed, 122 insertions(+), 88 deletions(-) create mode 100644 src/test/test-escape.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 36bad5c3fb..713cc769d9 100644 --- a/.gitignore +++ b/.gitignore @@ -181,6 +181,7 @@ /test-ellipsize /test-engine /test-env-replace +/test-escape /test-event /test-execute /test-extract-word diff --git a/Makefile.am b/Makefile.am index ab46b3f376..4f058d55ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1427,6 +1427,7 @@ tests += \ test-ellipsize \ test-util \ test-hexdecoct \ + test-escape \ test-string-util \ test-extract-word \ test-parse-util \ @@ -1762,6 +1763,12 @@ test_hexdecoct_SOURCES = \ test_hexdecoct_LDADD = \ libbasic.la +test_escape_SOURCES = \ + src/test/test-escape.c + +test_escape_LDADD = \ + libbasic.la + test_string_util_SOURCES = \ src/test/test-string-util.c diff --git a/src/test/test-escape.c b/src/test/test-escape.c new file mode 100644 index 0000000000..6cbb8443fe --- /dev/null +++ b/src/test/test-escape.c @@ -0,0 +1,114 @@ +/*** + 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 . +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "macro.h" + +static void test_cescape(void) { + _cleanup_free_ char *escaped; + + assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); + assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); +} + +static void test_cunescape(void) { + _cleanup_free_ char *unescaped; + + 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")); + unescaped = mfree(unescaped); + + /* incomplete sequences */ + assert_se(cunescape("\\x0", 0, &unescaped) < 0); + assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x0")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\x", 0, &unescaped) < 0); + assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\", 0, &unescaped) < 0); + assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\11", 0, &unescaped) < 0); + assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\11")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\1", 0, &unescaped) < 0); + assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\1")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\u0000", 0, &unescaped) < 0); + assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "ßßΠA")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\073", 0, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, ";")); +} + +static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_escape(s, bad)); + assert_se(streq_ptr(r, expected)); +} + +static void test_shell_escape(void) { + test_shell_escape_one("", "", ""); + test_shell_escape_one("\\", "", "\\\\"); + test_shell_escape_one("foobar", "", "foobar"); + test_shell_escape_one("foobar", "o", "f\\o\\obar"); + test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); +} + +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\""); +} + +int main(int argc, char *argv[]) { + test_cescape(); + test_cunescape(); + test_shell_escape(); + test_shell_maybe_quote(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 2b44b91170..eb10f57b6e 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -31,7 +31,6 @@ #include "conf-parser.h" #include "cpu-set-util.h" #include "def.h" -#include "escape.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -229,56 +228,6 @@ static void test_parse_uid(void) { assert_se(r == -EINVAL); } -static void test_cescape(void) { - _cleanup_free_ char *escaped; - - assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); - assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); -} - -static void test_cunescape(void) { - _cleanup_free_ char *unescaped; - - 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")); - unescaped = mfree(unescaped); - - /* incomplete sequences */ - assert_se(cunescape("\\x0", 0, &unescaped) < 0); - assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x0")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\x", 0, &unescaped) < 0); - assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\", 0, &unescaped) < 0); - assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\11", 0, &unescaped) < 0); - assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\11")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\1", 0, &unescaped) < 0); - assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\1")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\u0000", 0, &unescaped) < 0); - assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "ßßΠA")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\073", 0, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, ";")); -} - static void test_memdup_multiply(void) { int org[] = {1, 2, 3}; int *dup; @@ -924,39 +873,6 @@ static void test_sparse_write(void) { test_sparse_write_one(fd, test_e, sizeof(test_e)); } -static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { - _cleanup_free_ char *r; - - assert_se(r = shell_escape(s, bad)); - assert_se(streq_ptr(r, expected)); -} - -static void test_shell_escape(void) { - test_shell_escape_one("", "", ""); - test_shell_escape_one("\\", "", "\\\\"); - test_shell_escape_one("foobar", "", "foobar"); - test_shell_escape_one("foobar", "o", "f\\o\\obar"); - test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); -} - -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_tempfn(void) { char *ret = NULL, *p; @@ -1042,8 +958,6 @@ int main(int argc, char *argv[]) { test_div_round_up(); test_close_many(); test_parse_uid(); - test_cescape(); - test_cunescape(); test_memdup_multiply(); test_u64log2(); test_protect_errno(); @@ -1072,8 +986,6 @@ int main(int argc, char *argv[]) { test_same_fd(); test_uid_ptr(); test_sparse_write(); - test_shell_escape(); - test_shell_maybe_quote(); test_tempfn(); test_fgetxattrat_fake(); test_runlevel_to_target(); -- cgit v1.2.3-54-g00ecf From b66de1f9d47426de5362d9e25704498c8a14b8a6 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:19:55 +0100 Subject: tests: move alloc related tests to test-alloc-util.c --- .gitignore | 1 + Makefile.am | 7 ++++++ src/test/test-alloc-util.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 28 ----------------------- 4 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 src/test/test-alloc-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 713cc769d9..224c24635c 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,7 @@ /test-acd /test-acl-util /test-af-list +/test-alloc-util /test-architecture /test-arphrd-list /test-ask-password-api diff --git a/Makefile.am b/Makefile.am index 4f058d55ce..11043d41b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1428,6 +1428,7 @@ tests += \ test-util \ test-hexdecoct \ test-escape \ + test-alloc-util \ test-string-util \ test-extract-word \ test-parse-util \ @@ -1763,6 +1764,12 @@ test_hexdecoct_SOURCES = \ test_hexdecoct_LDADD = \ libbasic.la +test_alloc_util_SOURCES = \ + src/test/test-alloc-util.c + +test_alloc_util_LDADD = \ + libbasic.la + test_escape_SOURCES = \ src/test/test-escape.c diff --git a/src/test/test-alloc-util.c b/src/test/test-alloc-util.c new file mode 100644 index 0000000000..cc4821eaf5 --- /dev/null +++ b/src/test/test-alloc-util.c @@ -0,0 +1,55 @@ +/*** + 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 . +***/ + +#include "alloc-util.h" +#include "macro.h" +#include "util.h" + +static void test_alloca(void) { + static const uint8_t zero[997] = { }; + char *t; + + t = alloca_align(17, 512); + assert_se(!((uintptr_t)t & 0xff)); + memzero(t, 17); + + t = alloca0_align(997, 1024); + assert_se(!((uintptr_t)t & 0x1ff)); + assert_se(!memcmp(t, zero, 997)); +} + +static void test_memdup_multiply(void) { + int org[] = {1, 2, 3}; + int *dup; + + dup = (int*)memdup_multiply(org, sizeof(int), 3); + + assert_se(dup); + assert_se(dup[0] == 1); + assert_se(dup[1] == 2); + assert_se(dup[2] == 3); + free(dup); +} + +int main(int argc, char *argv[]) { + test_alloca(); + test_memdup_multiply(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index eb10f57b6e..901898c29c 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -144,19 +144,6 @@ static void test_container_of(void) { v1) == &myval); } -static void test_alloca(void) { - static const uint8_t zero[997] = { }; - char *t; - - t = alloca_align(17, 512); - assert_se(!((uintptr_t)t & 0xff)); - memzero(t, 17); - - t = alloca0_align(997, 1024); - assert_se(!((uintptr_t)t & 0x1ff)); - assert_se(!memcmp(t, zero, 997)); -} - static void test_div_round_up(void) { int div; @@ -228,19 +215,6 @@ static void test_parse_uid(void) { assert_se(r == -EINVAL); } -static void test_memdup_multiply(void) { - int org[] = {1, 2, 3}; - int *dup; - - dup = (int*)memdup_multiply(org, sizeof(int), 3); - - assert_se(dup); - assert_se(dup[0] == 1); - assert_se(dup[1] == 2); - assert_se(dup[2] == 3); - free(dup); -} - static void test_u64log2(void) { assert_se(u64log2(0) == 0); assert_se(u64log2(8) == 3); @@ -954,11 +928,9 @@ int main(int argc, char *argv[]) { test_align_power2(); test_max(); test_container_of(); - test_alloca(); test_div_round_up(); test_close_many(); test_parse_uid(); - test_memdup_multiply(); test_u64log2(); test_protect_errno(); test_parse_cpu_set(); -- cgit v1.2.3-54-g00ecf From cd3510707af1f093dbd1b19172541be5b214779d Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:23:55 +0100 Subject: tests: move web-util related tests to test-web-util.c --- .gitignore | 1 + Makefile.am | 7 +++++++ src/test/test-util.c | 14 -------------- src/test/test-web-util.c | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 src/test/test-web-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 224c24635c..40685305ed 100644 --- a/.gitignore +++ b/.gitignore @@ -276,6 +276,7 @@ /test-util /test-verbs /test-watchdog +/test-web-util /test-xml /timedatectl /udevadm diff --git a/Makefile.am b/Makefile.am index 11043d41b8..7956264fb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1429,6 +1429,7 @@ tests += \ test-hexdecoct \ test-escape \ test-alloc-util \ + test-web-util \ test-string-util \ test-extract-word \ test-parse-util \ @@ -1770,6 +1771,12 @@ test_alloc_util_SOURCES = \ test_alloc_util_LDADD = \ libbasic.la +test_web_util_SOURCES = \ + src/test/test-web-util.c + +test_web_util_LDADD = \ + libbasic.la + test_escape_SOURCES = \ src/test/test-escape.c diff --git a/src/test/test-util.c b/src/test/test-util.c index 901898c29c..cd32892558 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -51,7 +51,6 @@ #include "user-util.h" #include "util.h" #include "virt.h" -#include "web-util.h" #include "xattr-util.h" static void test_align_power2(void) { @@ -481,18 +480,6 @@ static void test_files_same(void) { unlink(name_alias); } -static void test_is_valid_documentation_url(void) { - assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd")); - assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); - assert_se(documentation_url_is_valid("file:/foo/foo")); - assert_se(documentation_url_is_valid("man:systemd.special(7)")); - assert_se(documentation_url_is_valid("info:bar")); - - assert_se(!documentation_url_is_valid("foo:")); - assert_se(!documentation_url_is_valid("info:")); - assert_se(!documentation_url_is_valid("")); -} - static void test_file_in_same_dir(void) { char *t; @@ -942,7 +929,6 @@ int main(int argc, char *argv[]) { test_log2i(); test_filename_is_valid(); test_files_same(); - test_is_valid_documentation_url(); test_file_in_same_dir(); test_close_nointr(); test_unlink_noerrno(); diff --git a/src/test/test-web-util.c b/src/test/test-web-util.c new file mode 100644 index 0000000000..79a3a13af6 --- /dev/null +++ b/src/test/test-web-util.c @@ -0,0 +1,39 @@ +/*** + 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 . +***/ + +#include "macro.h" +#include "web-util.h" + +static void test_is_valid_documentation_url(void) { + assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd")); + assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); + assert_se(documentation_url_is_valid("file:/foo/foo")); + assert_se(documentation_url_is_valid("man:systemd.special(7)")); + assert_se(documentation_url_is_valid("info:bar")); + + assert_se(!documentation_url_is_valid("foo:")); + assert_se(!documentation_url_is_valid("info:")); + assert_se(!documentation_url_is_valid("")); +} + +int main(int argc, char *argv[]) { + test_is_valid_documentation_url(); + + return 0; +} -- cgit v1.2.3-54-g00ecf From 7ba365a9b202b49e16391a6e2ed80a8d92c01569 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:29:49 +0100 Subject: tests: move cpu-set-util related tests to test-cpu-set-util.c --- .gitignore | 1 + Makefile.am | 7 +++ src/test/test-cpu-set-util.c | 143 +++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 117 ----------------------------------- 4 files changed, 151 insertions(+), 117 deletions(-) create mode 100644 src/test/test-cpu-set-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 40685305ed..1475524699 100644 --- a/.gitignore +++ b/.gitignore @@ -167,6 +167,7 @@ /test-conf-parser /test-copy /test-coredump-vacuum +/test-cpu-set-util /test-daemon /test-date /test-device-nodes diff --git a/Makefile.am b/Makefile.am index 7956264fb1..2943f51d45 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1426,6 +1426,7 @@ tests += \ test-utf8 \ test-ellipsize \ test-util \ + test-cpu-set-util \ test-hexdecoct \ test-escape \ test-alloc-util \ @@ -1777,6 +1778,12 @@ test_web_util_SOURCES = \ test_web_util_LDADD = \ libbasic.la +test_cpu_set_util_SOURCES = \ + src/test/test-cpu-set-util.c + +test_cpu_set_util_LDADD = \ + libbasic.la + test_escape_SOURCES = \ src/test/test-escape.c diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c new file mode 100644 index 0000000000..8818d1ffb7 --- /dev/null +++ b/src/test/test-cpu-set-util.c @@ -0,0 +1,143 @@ +/*** + 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 . +***/ + +#include "alloc-util.h" +#include "cpu-set-util.h" +#include "macro.h" + +static void test_parse_cpu_set(void) { + cpu_set_t *c = NULL; + int ncpus; + int cpu; + + /* Simple range (from CPUAffinity example) */ + ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); + c = mfree(c); + + /* A more interesting range */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Quoted strings */ + ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Use commas as separators */ + ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Commas with spaces (and trailing comma, space) */ + ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges */ + ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges with trailing comma, space */ + ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Negative range (returns empty cpu_set) */ + ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); + c = mfree(c); + + /* Overlapping ranges */ + ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Mix ranges and individual CPUs */ + ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); + assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Garbage */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Range with garbage */ + ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Empty string */ + c = NULL; + ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus == 0); /* empty string returns 0 */ + assert_se(!c); + + /* Runnaway quoted string */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); +} + +int main(int argc, char *argv[]) { + test_parse_cpu_set(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index cd32892558..239064ed73 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -29,7 +29,6 @@ #include "alloc-util.h" #include "conf-parser.h" -#include "cpu-set-util.h" #include "def.h" #include "fd-util.h" #include "fileio.h" @@ -233,121 +232,6 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_parse_cpu_set(void) { - cpu_set_t *c = NULL; - int ncpus; - int cpu; - - /* Simple range (from CPUAffinity example) */ - ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); - c = mfree(c); - - /* A more interesting range */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Quoted strings */ - ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Use commas as separators */ - ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Commas with spaces (and trailing comma, space) */ - ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 8; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Ranges */ - ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Ranges with trailing comma, space */ - ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Negative range (returns empty cpu_set) */ - ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); - c = mfree(c); - - /* Overlapping ranges */ - ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); - for (cpu = 0; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Mix ranges and individual CPUs */ - ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); - assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 4; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Garbage */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); - - /* Range with garbage */ - ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); - - /* Empty string */ - c = NULL; - ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus == 0); /* empty string returns 0 */ - assert_se(!c); - - /* Runnaway quoted string */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); -} - static void test_config_parse_iec_uint64(void) { uint64_t offset = 0; assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); @@ -920,7 +804,6 @@ int main(int argc, char *argv[]) { test_parse_uid(); test_u64log2(); test_protect_errno(); - test_parse_cpu_set(); test_config_parse_iec_uint64(); test_fstab_node_to_udev_node(); test_get_files_in_directory(); -- cgit v1.2.3-54-g00ecf From ede4edd31e9aa84a9d7fd2aa3754d4c2ec0c448c Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:36:50 +0100 Subject: tests: move signal-util related tests to test-signal-util.c --- src/test/test-signal-util.c | 18 ++++++++++++++++++ src/test/test-util.c | 14 -------------- 2 files changed, 18 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c index 3083501ce9..671eb869cb 100644 --- a/src/test/test-signal-util.c +++ b/src/test/test-signal-util.c @@ -17,6 +17,10 @@ along with systemd; If not, see . ***/ +#include +#include + +#include "macro.h" #include "signal-util.h" static void test_block_signals(void) { @@ -44,6 +48,20 @@ static void test_block_signals(void) { assert_se(sigismember(&ss, SIGVTALRM) == 0); } +static void test_ignore_signals(void) { + assert_se(ignore_signals(SIGINT, -1) >= 0); + assert_se(kill(getpid(), SIGINT) >= 0); + assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); + assert_se(kill(getpid(), SIGUSR1) >= 0); + assert_se(kill(getpid(), SIGUSR2) >= 0); + assert_se(kill(getpid(), SIGTERM) >= 0); + assert_se(kill(getpid(), SIGPIPE) >= 0); + assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); +} + int main(int argc, char *argv[]) { test_block_signals(); + test_ignore_signals(); + + return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 239064ed73..60ed7f9aa0 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -42,7 +41,6 @@ #include "proc-cmdline.h" #include "process-util.h" #include "rm-rf.h" -#include "signal-util.h" #include "special.h" #include "stat-util.h" #include "string-util.h" @@ -445,17 +443,6 @@ static void test_readlink_and_make_absolute(void) { assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -static void test_ignore_signals(void) { - assert_se(ignore_signals(SIGINT, -1) >= 0); - assert_se(kill(getpid(), SIGINT) >= 0); - assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); - assert_se(kill(getpid(), SIGUSR1) >= 0); - assert_se(kill(getpid(), SIGUSR2) >= 0); - assert_se(kill(getpid(), SIGTERM) >= 0); - assert_se(kill(getpid(), SIGPIPE) >= 0); - assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); -} - static void test_is_symlink(void) { char name[] = "/tmp/test-is_symlink.XXXXXX"; char name_link[] = "/tmp/test-is_symlink.link"; @@ -816,7 +803,6 @@ int main(int argc, char *argv[]) { test_close_nointr(); test_unlink_noerrno(); test_readlink_and_make_absolute(); - test_ignore_signals(); test_is_symlink(); test_search_and_fopen(); test_search_and_fopen_nulstr(); -- cgit v1.2.3-54-g00ecf From f4c13ad76f1c0478346ac4d8751899d007a6c827 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:43:25 +0100 Subject: tests: move stat-util related tests to test-stat-util.c --- .gitignore | 1 + Makefile.am | 7 +++++ src/test/test-stat-util.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 37 -------------------------- 4 files changed, 76 insertions(+), 37 deletions(-) create mode 100644 src/test/test-stat-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 1475524699..f6139960cd 100644 --- a/.gitignore +++ b/.gitignore @@ -258,6 +258,7 @@ /test-siphash24 /test-sleep /test-socket-util +/test-stat-util /test-strbuf /test-string-util /test-strip-tab-ansi diff --git a/Makefile.am b/Makefile.am index 2943f51d45..1212b47873 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1431,6 +1431,7 @@ tests += \ test-escape \ test-alloc-util \ test-web-util \ + test-stat-util \ test-string-util \ test-extract-word \ test-parse-util \ @@ -1784,6 +1785,12 @@ test_cpu_set_util_SOURCES = \ test_cpu_set_util_LDADD = \ libbasic.la +test_stat_util_SOURCES = \ + src/test/test-stat-util.c + +test_stat_util_LDADD = \ + libbasic.la + test_escape_SOURCES = \ src/test/test-escape.c diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c new file mode 100644 index 0000000000..a10227f823 --- /dev/null +++ b/src/test/test-stat-util.c @@ -0,0 +1,68 @@ +/*** + 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 . +***/ + +#include +#include + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" +#include "stat-util.h" + +static void test_files_same(void) { + _cleanup_close_ int fd = -1; + char name[] = "/tmp/test-files_same.XXXXXX"; + char name_alias[] = "/tmp/test-files_same.alias"; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(symlink(name, name_alias) >= 0); + + assert_se(files_same(name, name)); + assert_se(files_same(name, name_alias)); + + unlink(name); + unlink(name_alias); +} + +static void test_is_symlink(void) { + char name[] = "/tmp/test-is_symlink.XXXXXX"; + char name_link[] = "/tmp/test-is_symlink.link"; + _cleanup_close_ int fd = -1; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(symlink(name, name_link) >= 0); + + assert_se(is_symlink(name) == 0); + assert_se(is_symlink(name_link) == 1); + assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); + + + unlink(name); + unlink(name_link); +} + +int main(int argc, char *argv[]) { + test_files_same(); + test_is_symlink(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 60ed7f9aa0..63ee614b2d 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -42,7 +42,6 @@ #include "process-util.h" #include "rm-rf.h" #include "special.h" -#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "user-util.h" @@ -346,22 +345,6 @@ static void test_filename_is_valid(void) { assert_se(filename_is_valid("o.o")); } -static void test_files_same(void) { - _cleanup_close_ int fd = -1; - char name[] = "/tmp/test-files_same.XXXXXX"; - char name_alias[] = "/tmp/test-files_same.alias"; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_alias) >= 0); - - assert_se(files_same(name, name)); - assert_se(files_same(name, name_alias)); - - unlink(name); - unlink(name_alias); -} - static void test_file_in_same_dir(void) { char *t; @@ -443,24 +426,6 @@ static void test_readlink_and_make_absolute(void) { assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -static void test_is_symlink(void) { - char name[] = "/tmp/test-is_symlink.XXXXXX"; - char name_link[] = "/tmp/test-is_symlink.link"; - _cleanup_close_ int fd = -1; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_link) >= 0); - - assert_se(is_symlink(name) == 0); - assert_se(is_symlink(name_link) == 1); - assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); - - - unlink(name); - unlink(name_link); -} - static void test_search_and_fopen(void) { const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL}; char name[] = "/tmp/test-search_and_fopen.XXXXXX"; @@ -798,12 +763,10 @@ int main(int argc, char *argv[]) { test_writing_tmpfile(); test_log2i(); test_filename_is_valid(); - test_files_same(); test_file_in_same_dir(); test_close_nointr(); test_unlink_noerrno(); test_readlink_and_make_absolute(); - test_is_symlink(); test_search_and_fopen(); test_search_and_fopen_nulstr(); test_glob_exists(); -- cgit v1.2.3-54-g00ecf From 897891f02e090bdcd60b0aec97d33fd4049fb500 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:50:21 +0100 Subject: tests: move fileio related tests to test-fileio.c --- src/test/test-fileio.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 133 ------------------------------------------------- 2 files changed, 133 insertions(+), 133 deletions(-) (limited to 'src') diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 5586a2d6c1..ec9f173da2 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -27,6 +27,7 @@ #include "env-util.h" #include "fd-util.h" #include "fileio.h" +#include "io-util.h" #include "parse-util.h" #include "process-util.h" #include "string-util.h" @@ -425,6 +426,134 @@ static void test_load_env_file_pairs(void) { unlink(fn); } +static void test_search_and_fopen(void) { + const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL}; + char name[] = "/tmp/test-search_and_fopen.XXXXXX"; + int fd = -1; + int r; + FILE *f; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = search_and_fopen(basename(name), "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen(name, "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen(basename(name), "r", "/", dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); + assert_se(r < 0); + r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); + assert_se(r < 0); + + r = unlink(name); + assert_se(r == 0); + + r = search_and_fopen(basename(name), "r", NULL, dirs, &f); + assert_se(r < 0); +} + + +static void test_search_and_fopen_nulstr(void) { + const char dirs[] = "/tmp/foo/bar\0/tmp\0"; + char name[] = "/tmp/test-search_and_fopen.XXXXXX"; + int fd = -1; + int r; + FILE *f; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); + assert_se(r < 0); + r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); + assert_se(r < 0); + + r = unlink(name); + assert_se(r == 0); + + r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); + assert_se(r < 0); +} + +static void test_writing_tmpfile(void) { + char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX"; + _cleanup_free_ char *contents = NULL; + size_t size; + int fd, r; + struct iovec iov[3]; + + IOVEC_SET_STRING(iov[0], "abc\n"); + IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n"); + IOVEC_SET_STRING(iov[2], ""); + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + printf("tmpfile: %s", name); + + r = writev(fd, iov, 3); + assert_se(r >= 0); + + r = read_full_file(name, &contents, &size); + assert_se(r == 0); + printf("contents: %s", contents); + assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n")); + + unlink(name); +} + +static void test_tempfn(void) { + char *ret = NULL, *p; + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX")); + free(ret); + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -439,6 +568,10 @@ int main(int argc, char *argv[]) { test_write_string_file_no_create(); test_write_string_file_verify(); test_load_env_file_pairs(); + test_search_and_fopen(); + test_search_and_fopen_nulstr(); + test_writing_tmpfile(); + test_tempfn(); return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 63ee614b2d..d16f8c591b 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -289,31 +289,6 @@ static void test_in_set(void) { assert_se(!IN_SET(0, 1, 2, 3, 4)); } -static void test_writing_tmpfile(void) { - char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX"; - _cleanup_free_ char *contents = NULL; - size_t size; - int fd, r; - struct iovec iov[3]; - - IOVEC_SET_STRING(iov[0], "abc\n"); - IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n"); - IOVEC_SET_STRING(iov[2], ""); - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - printf("tmpfile: %s", name); - - r = writev(fd, iov, 3); - assert_se(r >= 0); - - r = read_full_file(name, &contents, &size); - assert_se(r == 0); - printf("contents: %s", contents); - assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n")); - - unlink(name); -} - static void test_log2i(void) { assert_se(log2i(1) == 0); assert_se(log2i(2) == 1); @@ -381,7 +356,6 @@ static void test_close_nointr(void) { unlink(name); } - static void test_unlink_noerrno(void) { char name[] = "/tmp/test-close_nointr.XXXXXX"; int fd; @@ -426,73 +400,6 @@ static void test_readlink_and_make_absolute(void) { assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -static void test_search_and_fopen(void) { - const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL}; - char name[] = "/tmp/test-search_and_fopen.XXXXXX"; - int fd = -1; - int r; - FILE *f; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = search_and_fopen(basename(name), "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen(name, "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen(basename(name), "r", "/", dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); - assert_se(r < 0); - r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); - assert_se(r < 0); - - r = unlink(name); - assert_se(r == 0); - - r = search_and_fopen(basename(name), "r", NULL, dirs, &f); - assert_se(r < 0); -} - - -static void test_search_and_fopen_nulstr(void) { - const char dirs[] = "/tmp/foo/bar\0/tmp\0"; - char name[] = "/tmp/test-search_and_fopen.XXXXXX"; - int fd = -1; - int r; - FILE *f; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); - assert_se(r < 0); - r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); - assert_se(r < 0); - - r = unlink(name); - assert_se(r == 0); - - r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); - assert_se(r < 0); -} - static void test_glob_exists(void) { char name[] = "/tmp/test-glob_exists.XXXXXX"; int fd = -1; @@ -670,42 +577,6 @@ static void test_sparse_write(void) { test_sparse_write_one(fd, test_e, sizeof(test_e)); } -static void test_tempfn(void) { - char *ret = NULL, *p; - - assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX")); - free(ret); - - assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0); - assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX")); - free(ret); - - assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/.#waldo")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/waldo/.#")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); -} - static void test_fgetxattrat_fake(void) { char t[] = "/var/tmp/xattrtestXXXXXX"; _cleanup_close_ int fd = -1; @@ -760,15 +631,12 @@ int main(int argc, char *argv[]) { test_fstab_node_to_udev_node(); test_get_files_in_directory(); test_in_set(); - test_writing_tmpfile(); test_log2i(); test_filename_is_valid(); test_file_in_same_dir(); test_close_nointr(); test_unlink_noerrno(); test_readlink_and_make_absolute(); - test_search_and_fopen(); - test_search_and_fopen_nulstr(); test_glob_exists(); test_execute_directory(); test_parse_proc_cmdline(); @@ -776,7 +644,6 @@ int main(int argc, char *argv[]) { test_same_fd(); test_uid_ptr(); test_sparse_write(); - test_tempfn(); test_fgetxattrat_fake(); test_runlevel_to_target(); -- cgit v1.2.3-54-g00ecf From 6329266386f5cf5e1a8ae41b0693b03b63a5e81e Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Wed, 2 Mar 2016 23:54:35 +0100 Subject: tests: move path-util related tests to test-path-util.c --- src/test/test-path-util.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 46 ---------------------------------------------- 2 files changed, 46 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 53a585290a..d376dd56c5 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -433,6 +433,50 @@ static void test_path_is_mount_point(void) { assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); } +static void test_file_in_same_dir(void) { + char *t; + + t = file_in_same_dir("/", "a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("/", "/a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("", "a"); + assert_se(streq(t, "a")); + free(t); + + t = file_in_same_dir("a/", "a"); + assert_se(streq(t, "a/a")); + free(t); + + t = file_in_same_dir("bar/foo", "bar"); + assert_se(streq(t, "bar/bar")); + free(t); +} + +static void test_filename_is_valid(void) { + char foo[FILENAME_MAX+2]; + int i; + + assert_se(!filename_is_valid("")); + assert_se(!filename_is_valid("/bar/foo")); + assert_se(!filename_is_valid("/")); + assert_se(!filename_is_valid(".")); + assert_se(!filename_is_valid("..")); + + for (i=0; i Date: Wed, 2 Mar 2016 23:58:48 +0100 Subject: tests: move user-util related tests to test-user-util.c --- src/test/test-user-util.c | 27 +++++++++++++++++++++++++++ src/test/test-util.c | 27 --------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index 42c6a8d5e2..8d1ec19f17 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -37,6 +37,30 @@ static void test_gid_to_name_one(gid_t gid, const char *name) { assert_se(streq_ptr(t, name)); } +static void test_parse_uid(void) { + int r; + uid_t uid; + + r = parse_uid("100", &uid); + assert_se(r == 0); + assert_se(uid == 100); + + r = parse_uid("65535", &uid); + assert_se(r == -ENXIO); + + r = parse_uid("asdsdas", &uid); + assert_se(r == -EINVAL); +} + +static void test_uid_ptr(void) { + + assert_se(UID_TO_PTR(0) != NULL); + assert_se(UID_TO_PTR(1000) != NULL); + + assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); + assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); +} + int main(int argc, char*argv[]) { test_uid_to_name_one(0, "root"); @@ -48,5 +72,8 @@ int main(int argc, char*argv[]) { test_gid_to_name_one(0xFFFF, "65535"); test_gid_to_name_one(0xFFFFFFFF, "4294967295"); + test_parse_uid(); + test_uid_ptr(); + return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index d769c2191c..1ed6f48774 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -44,7 +44,6 @@ #include "special.h" #include "string-util.h" #include "strv.h" -#include "user-util.h" #include "util.h" #include "virt.h" #include "xattr-util.h" @@ -195,21 +194,6 @@ static void test_close_many(void) { unlink(name2); } -static void test_parse_uid(void) { - int r; - uid_t uid; - - r = parse_uid("100", &uid); - assert_se(r == 0); - assert_se(uid == 100); - - r = parse_uid("65535", &uid); - assert_se(r == -ENXIO); - - r = parse_uid("asdsdas", &uid); - assert_se(r == -EINVAL); -} - static void test_u64log2(void) { assert_se(u64log2(0) == 0); assert_se(u64log2(8) == 3); @@ -488,15 +472,6 @@ static void test_same_fd(void) { assert_se(same_fd(b, a) == 0); } -static void test_uid_ptr(void) { - - assert_se(UID_TO_PTR(0) != NULL); - assert_se(UID_TO_PTR(1000) != NULL); - - assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); - assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); -} - static void test_sparse_write_one(int fd, const char *buffer, size_t n) { char check[n]; @@ -580,7 +555,6 @@ int main(int argc, char *argv[]) { test_container_of(); test_div_round_up(); test_close_many(); - test_parse_uid(); test_u64log2(); test_protect_errno(); test_config_parse_iec_uint64(); @@ -596,7 +570,6 @@ int main(int argc, char *argv[]) { test_parse_proc_cmdline(); test_raw_clone(); test_same_fd(); - test_uid_ptr(); test_sparse_write(); test_fgetxattrat_fake(); test_runlevel_to_target(); -- cgit v1.2.3-54-g00ecf From 0999c8ade89727ade8dc943711e6d61bcc671ab7 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:06:17 +0100 Subject: tests: move fd-util related tests to test-fd-util.c --- .gitignore | 1 + Makefile.am | 7 ++++ src/test/test-fd-util.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 72 --------------------------------- 4 files changed, 111 insertions(+), 72 deletions(-) create mode 100644 src/test/test-fd-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index f6139960cd..993436fc31 100644 --- a/.gitignore +++ b/.gitignore @@ -187,6 +187,7 @@ /test-event /test-execute /test-extract-word +/test-fd-util /test-fdset /test-fileio /test-firewall-util diff --git a/Makefile.am b/Makefile.am index 1212b47873..7b4254c169 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1432,6 +1432,7 @@ tests += \ test-alloc-util \ test-web-util \ test-stat-util \ + test-fd-util \ test-string-util \ test-extract-word \ test-parse-util \ @@ -1773,6 +1774,12 @@ test_alloc_util_SOURCES = \ test_alloc_util_LDADD = \ libbasic.la +test_fd_util_SOURCES = \ + src/test/test-fd-util.c + +test_fd_util_LDADD = \ + libbasic.la + test_web_util_SOURCES = \ src/test/test-web-util.c diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c new file mode 100644 index 0000000000..421d3bdeb3 --- /dev/null +++ b/src/test/test-fd-util.c @@ -0,0 +1,103 @@ +/*** + 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 . +***/ + +#include +#include + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" + +static void test_close_many(void) { + int fds[3]; + char name0[] = "/tmp/test-close-many.XXXXXX"; + char name1[] = "/tmp/test-close-many.XXXXXX"; + char name2[] = "/tmp/test-close-many.XXXXXX"; + + fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); + fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); + fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); + + close_many(fds, 2); + + assert_se(fcntl(fds[0], F_GETFD) == -1); + assert_se(fcntl(fds[1], F_GETFD) == -1); + assert_se(fcntl(fds[2], F_GETFD) >= 0); + + safe_close(fds[2]); + + unlink(name0); + unlink(name1); + unlink(name2); +} + +static void test_close_nointr(void) { + char name[] = "/tmp/test-test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + assert_se(close_nointr(fd) < 0); + + unlink(name); +} + +static void test_same_fd(void) { + _cleanup_close_pair_ int p[2] = { -1, -1 }; + _cleanup_close_ int a = -1, b = -1, c = -1; + + assert_se(pipe2(p, O_CLOEXEC) >= 0); + assert_se((a = dup(p[0])) >= 0); + assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0); + assert_se((c = dup(a)) >= 0); + + assert_se(same_fd(p[0], p[0]) > 0); + assert_se(same_fd(p[1], p[1]) > 0); + assert_se(same_fd(a, a) > 0); + assert_se(same_fd(b, b) > 0); + + assert_se(same_fd(a, p[0]) > 0); + assert_se(same_fd(p[0], a) > 0); + assert_se(same_fd(c, p[0]) > 0); + assert_se(same_fd(p[0], c) > 0); + assert_se(same_fd(a, c) > 0); + assert_se(same_fd(c, a) > 0); + + assert_se(same_fd(p[0], p[1]) == 0); + assert_se(same_fd(p[1], p[0]) == 0); + assert_se(same_fd(p[0], b) == 0); + assert_se(same_fd(b, p[0]) == 0); + assert_se(same_fd(p[1], a) == 0); + assert_se(same_fd(a, p[1]) == 0); + assert_se(same_fd(p[1], b) == 0); + assert_se(same_fd(b, p[1]) == 0); + + assert_se(same_fd(a, b) == 0); + assert_se(same_fd(b, a) == 0); +} + +int main(int argc, char *argv[]) { + test_close_many(); + test_close_nointr(); + test_same_fd(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 1ed6f48774..30444e122a 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -171,29 +171,6 @@ static void test_div_round_up(void) { assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); } -static void test_close_many(void) { - int fds[3]; - char name0[] = "/tmp/test-close-many.XXXXXX"; - char name1[] = "/tmp/test-close-many.XXXXXX"; - char name2[] = "/tmp/test-close-many.XXXXXX"; - - fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); - fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); - fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); - - close_many(fds, 2); - - assert_se(fcntl(fds[0], F_GETFD) == -1); - assert_se(fcntl(fds[1], F_GETFD) == -1); - assert_se(fcntl(fds[2], F_GETFD) >= 0); - - safe_close(fds[2]); - - unlink(name0); - unlink(name1); - unlink(name2); -} - static void test_u64log2(void) { assert_se(u64log2(0) == 0); assert_se(u64log2(8) == 3); @@ -284,18 +261,6 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } -static void test_close_nointr(void) { - char name[] = "/tmp/test-test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - assert_se(close_nointr(fd) < 0); - - unlink(name); -} - static void test_unlink_noerrno(void) { char name[] = "/tmp/test-close_nointr.XXXXXX"; int fd; @@ -438,40 +403,6 @@ static void test_raw_clone(void) { } } -static void test_same_fd(void) { - _cleanup_close_pair_ int p[2] = { -1, -1 }; - _cleanup_close_ int a = -1, b = -1, c = -1; - - assert_se(pipe2(p, O_CLOEXEC) >= 0); - assert_se((a = dup(p[0])) >= 0); - assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0); - assert_se((c = dup(a)) >= 0); - - assert_se(same_fd(p[0], p[0]) > 0); - assert_se(same_fd(p[1], p[1]) > 0); - assert_se(same_fd(a, a) > 0); - assert_se(same_fd(b, b) > 0); - - assert_se(same_fd(a, p[0]) > 0); - assert_se(same_fd(p[0], a) > 0); - assert_se(same_fd(c, p[0]) > 0); - assert_se(same_fd(p[0], c) > 0); - assert_se(same_fd(a, c) > 0); - assert_se(same_fd(c, a) > 0); - - assert_se(same_fd(p[0], p[1]) == 0); - assert_se(same_fd(p[1], p[0]) == 0); - assert_se(same_fd(p[0], b) == 0); - assert_se(same_fd(b, p[0]) == 0); - assert_se(same_fd(p[1], a) == 0); - assert_se(same_fd(a, p[1]) == 0); - assert_se(same_fd(p[1], b) == 0); - assert_se(same_fd(b, p[1]) == 0); - - assert_se(same_fd(a, b) == 0); - assert_se(same_fd(b, a) == 0); -} - static void test_sparse_write_one(int fd, const char *buffer, size_t n) { char check[n]; @@ -554,7 +485,6 @@ int main(int argc, char *argv[]) { test_max(); test_container_of(); test_div_round_up(); - test_close_many(); test_u64log2(); test_protect_errno(); test_config_parse_iec_uint64(); @@ -562,14 +492,12 @@ int main(int argc, char *argv[]) { test_get_files_in_directory(); test_in_set(); test_log2i(); - test_close_nointr(); test_unlink_noerrno(); test_readlink_and_make_absolute(); test_glob_exists(); test_execute_directory(); test_parse_proc_cmdline(); test_raw_clone(); - test_same_fd(); test_sparse_write(); test_fgetxattrat_fake(); test_runlevel_to_target(); -- cgit v1.2.3-54-g00ecf From f55211dbce00fad7cd16fa40d7f7b76448049a86 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:08:10 +0100 Subject: tests: move conf-parser related tests to test-conf-parser.c --- src/test/test-conf-parser.c | 9 +++++++++ src/test/test-util.c | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index b3a4c40339..be5d2611f8 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -215,6 +215,14 @@ static void test_config_parse_nsec(void) { test_config_parse_nsec_one("garbage", 0); } +static void test_config_parse_iec_uint64(void) { + uint64_t offset = 0; + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); + assert_se(offset == 4 * 1024 * 1024); + + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); +} + int main(int argc, char **argv) { log_parse_environment(); log_open(); @@ -230,6 +238,7 @@ int main(int argc, char **argv) { test_config_parse_mode(); test_config_parse_sec(); test_config_parse_nsec(); + test_config_parse_iec_uint64(); return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 30444e122a..7226e9b76f 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -27,7 +27,6 @@ #include #include "alloc-util.h" -#include "conf-parser.h" #include "def.h" #include "fd-util.h" #include "fileio.h" @@ -190,14 +189,6 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_config_parse_iec_uint64(void) { - uint64_t offset = 0; - assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); - assert_se(offset == 4 * 1024 * 1024); - - assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); -} - static void test_fstab_node_to_udev_node(void) { char *n; @@ -487,7 +478,6 @@ int main(int argc, char *argv[]) { test_div_round_up(); test_u64log2(); test_protect_errno(); - test_config_parse_iec_uint64(); test_fstab_node_to_udev_node(); test_get_files_in_directory(); test_in_set(); -- cgit v1.2.3-54-g00ecf From c270684afd19d0a321a6bac6b9f84cdf18b2ca6f Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:14:18 +0100 Subject: tests: move fs-util related tests to test-fs-util.c --- .gitignore | 1 + Makefile.am | 7 ++++ src/test/test-fs-util.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 55 ------------------------------ 4 files changed, 99 insertions(+), 55 deletions(-) create mode 100644 src/test/test-fs-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 993436fc31..569be9506a 100644 --- a/.gitignore +++ b/.gitignore @@ -191,6 +191,7 @@ /test-fdset /test-fileio /test-firewall-util +/test-fs-util /test-fstab-util /test-hashmap /test-hexdecoct diff --git a/Makefile.am b/Makefile.am index 7b4254c169..f18bc614a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1430,6 +1430,7 @@ tests += \ test-hexdecoct \ test-escape \ test-alloc-util \ + test-fs-util \ test-web-util \ test-stat-util \ test-fd-util \ @@ -1774,6 +1775,12 @@ test_alloc_util_SOURCES = \ test_alloc_util_LDADD = \ libbasic.la +test_fs_util_SOURCES = \ + src/test/test-fs-util.c + +test_fs_util_LDADD = \ + libbasic.la + test_fd_util_SOURCES = \ src/test/test-fd-util.c diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c new file mode 100644 index 0000000000..6db2c2b6f1 --- /dev/null +++ b/src/test/test-fs-util.c @@ -0,0 +1,91 @@ +/*** + 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 . +***/ + +#include + +#include "alloc-util.h" +#include "fileio.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "mkdir.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +static void test_unlink_noerrno(void) { + char name[] = "/tmp/test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + + { + PROTECT_ERRNO; + errno = -42; + assert_se(unlink_noerrno(name) >= 0); + assert_se(errno == -42); + assert_se(unlink_noerrno(name) < 0); + assert_se(errno == -42); + } +} + +static void test_readlink_and_make_absolute(void) { + char tempdir[] = "/tmp/test-readlink_and_make_absolute"; + char name[] = "/tmp/test-readlink_and_make_absolute/original"; + char name2[] = "test-readlink_and_make_absolute/original"; + char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; + char *r = NULL; + + assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); + assert_se(touch(name) >= 0); + + assert_se(symlink(name, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(chdir(tempdir) >= 0); + assert_se(symlink(name2, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); +} + +static void test_get_files_in_directory(void) { + _cleanup_strv_free_ char **l = NULL, **t = NULL; + + assert_se(get_files_in_directory("/tmp", &l) >= 0); + assert_se(get_files_in_directory(".", &t) >= 0); + assert_se(get_files_in_directory(".", NULL) >= 0); +} + +int main(int argc, char *argv[]) { + test_unlink_noerrno(); + test_readlink_and_make_absolute(); + test_get_files_in_directory(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 7226e9b76f..b787a5e5f0 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -223,14 +223,6 @@ static void test_fstab_node_to_udev_node(void) { free(n); } -static void test_get_files_in_directory(void) { - _cleanup_strv_free_ char **l = NULL, **t = NULL; - - assert_se(get_files_in_directory("/tmp", &l) >= 0); - assert_se(get_files_in_directory(".", &t) >= 0); - assert_se(get_files_in_directory(".", NULL) >= 0); -} - static void test_in_set(void) { assert_se(IN_SET(1, 1)); assert_se(IN_SET(1, 1, 2, 3, 4)); @@ -252,50 +244,6 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } -static void test_unlink_noerrno(void) { - char name[] = "/tmp/test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - - { - PROTECT_ERRNO; - errno = -42; - assert_se(unlink_noerrno(name) >= 0); - assert_se(errno == -42); - assert_se(unlink_noerrno(name) < 0); - assert_se(errno == -42); - } -} - -static void test_readlink_and_make_absolute(void) { - char tempdir[] = "/tmp/test-readlink_and_make_absolute"; - char name[] = "/tmp/test-readlink_and_make_absolute/original"; - char name2[] = "test-readlink_and_make_absolute/original"; - char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; - char *r = NULL; - - assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); - assert_se(touch(name) >= 0); - - assert_se(symlink(name, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(chdir(tempdir) >= 0); - assert_se(symlink(name2, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); -} - static void test_glob_exists(void) { char name[] = "/tmp/test-glob_exists.XXXXXX"; int fd = -1; @@ -479,11 +427,8 @@ int main(int argc, char *argv[]) { test_u64log2(); test_protect_errno(); test_fstab_node_to_udev_node(); - test_get_files_in_directory(); test_in_set(); test_log2i(); - test_unlink_noerrno(); - test_readlink_and_make_absolute(); test_glob_exists(); test_execute_directory(); test_parse_proc_cmdline(); -- cgit v1.2.3-54-g00ecf From 09c303ce5baab09836bcaf835d61d74bb92e450e Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:16:52 +0100 Subject: tests: move fstab-util related tests to test-fstab-util.c --- src/test/test-fstab-util.c | 37 +++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 36 ------------------------------------ 2 files changed, 37 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index ea3d1a6909..63a4b8c243 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -131,8 +131,45 @@ static void test_fstab_yes_no_option(void) { assert_se(fstab_test_yes_no_option("nofail,nofail=0,fail=0", "nofail\0fail\0") == false); } +static void test_fstab_node_to_udev_node(void) { + char *n; + + n = fstab_node_to_udev_node("LABEL=applé/jack"); + puts(n); + assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); + free(n); + + n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); + free(n); + + n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PONIES=awesome"); + puts(n); + assert_se(streq(n, "PONIES=awesome")); + free(n); + + n = fstab_node_to_udev_node("/dev/xda1"); + puts(n); + assert_se(streq(n, "/dev/xda1")); + free(n); +} + int main(void) { test_fstab_filter_options(); test_fstab_find_pri(); test_fstab_yes_no_option(); + test_fstab_node_to_udev_node(); + + return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index b787a5e5f0..06ea81df22 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -31,7 +31,6 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "fstab-util.h" #include "glob-util.h" #include "io-util.h" #include "mkdir.h" @@ -189,40 +188,6 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_fstab_node_to_udev_node(void) { - char *n; - - n = fstab_node_to_udev_node("LABEL=applé/jack"); - puts(n); - assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); - free(n); - - n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); - free(n); - - n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PONIES=awesome"); - puts(n); - assert_se(streq(n, "PONIES=awesome")); - free(n); - - n = fstab_node_to_udev_node("/dev/xda1"); - puts(n); - assert_se(streq(n, "/dev/xda1")); - free(n); -} - static void test_in_set(void) { assert_se(IN_SET(1, 1)); assert_se(IN_SET(1, 1, 2, 3, 4)); @@ -426,7 +391,6 @@ int main(int argc, char *argv[]) { test_div_round_up(); test_u64log2(); test_protect_errno(); - test_fstab_node_to_udev_node(); test_in_set(); test_log2i(); test_glob_exists(); -- cgit v1.2.3-54-g00ecf From d376cbb7b0aef14b4026d8fe58f65cec6835003d Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:23:30 +0100 Subject: tests: move proc-cmdline related tests to test-proc-cmdline.c --- .gitignore | 1 + Makefile.am | 7 ++++++ src/test/test-proc-cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 20 ----------------- 4 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 src/test/test-proc-cmdline.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 569be9506a..9dd125ced0 100644 --- a/.gitignore +++ b/.gitignore @@ -241,6 +241,7 @@ /test-path-lookup /test-path-util /test-prioq +/test-proc-cmdline /test-process-util /test-pty /test-qcow2 diff --git a/Makefile.am b/Makefile.am index f18bc614a8..b2a40ec46b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1430,6 +1430,7 @@ tests += \ test-hexdecoct \ test-escape \ test-alloc-util \ + test-proc-cmdline \ test-fs-util \ test-web-util \ test-stat-util \ @@ -1781,6 +1782,12 @@ test_fs_util_SOURCES = \ test_fs_util_LDADD = \ libbasic.la +test_proc_cmdline_SOURCES = \ + src/test/test-proc-cmdline.c + +test_proc_cmdline_LDADD = \ + libbasic.la + test_fd_util_SOURCES = \ src/test/test-fd-util.c diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c new file mode 100644 index 0000000000..a7a8f621a2 --- /dev/null +++ b/src/test/test-proc-cmdline.c @@ -0,0 +1,52 @@ +/*** + 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 . +***/ + +#include "alloc-util.h" +#include "log.h" +#include "macro.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" + +static int parse_item(const char *key, const char *value) { + assert_se(key); + + log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); + return 0; +} + +static void test_parse_proc_cmdline(void) { + assert_se(parse_proc_cmdline(parse_item) >= 0); +} + +static void test_runlevel_to_target(void) { + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); +} + +int main(void) { + log_parse_environment(); + log_open(); + + test_parse_proc_cmdline(); + test_runlevel_to_target(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 06ea81df22..50bb0211be 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -36,7 +36,6 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" -#include "proc-cmdline.h" #include "process-util.h" #include "rm-rf.h" #include "special.h" @@ -271,17 +270,6 @@ static void test_execute_directory(void) { (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL); } -static int parse_item(const char *key, const char *value) { - assert_se(key); - - log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); - return 0; -} - -static void test_parse_proc_cmdline(void) { - assert_se(parse_proc_cmdline(parse_item) >= 0); -} - static void test_raw_clone(void) { pid_t parent, pid, pid2; @@ -375,12 +363,6 @@ cleanup: assert_se(rmdir(t) >= 0); } -static void test_runlevel_to_target(void) { - assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); - assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); - assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); -} - int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -395,11 +377,9 @@ int main(int argc, char *argv[]) { test_log2i(); test_glob_exists(); test_execute_directory(); - test_parse_proc_cmdline(); test_raw_clone(); test_sparse_write(); test_fgetxattrat_fake(); - test_runlevel_to_target(); return 0; } -- cgit v1.2.3-54-g00ecf From ac933e8ec4eda7ba1fa387fce7bebdb3d4390b30 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:28:29 +0100 Subject: tests: move io-util related tests to test-io-util --- .gitignore | 1 + Makefile.am | 7 +++++ src/test/test-io-util.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 38 --------------------------- 4 files changed, 77 insertions(+), 38 deletions(-) create mode 100644 src/test/test-io-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 9dd125ced0..a17cbad004 100644 --- a/.gitignore +++ b/.gitignore @@ -201,6 +201,7 @@ /test-inhibit /test-install /test-install-root +/test-io-util /test-ipcrm /test-ipv4ll /test-ipv4ll-manual diff --git a/Makefile.am b/Makefile.am index b2a40ec46b..1b06ffb98c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1431,6 +1431,7 @@ tests += \ test-escape \ test-alloc-util \ test-proc-cmdline \ + test-io-util \ test-fs-util \ test-web-util \ test-stat-util \ @@ -1776,6 +1777,12 @@ test_alloc_util_SOURCES = \ test_alloc_util_LDADD = \ libbasic.la +test_io_util_SOURCES = \ + src/test/test-io-util.c + +test_io_util_LDADD = \ + libbasic.la + test_fs_util_SOURCES = \ src/test/test-fs-util.c diff --git a/src/test/test-io-util.c b/src/test/test-io-util.c new file mode 100644 index 0000000000..10bd3833bc --- /dev/null +++ b/src/test/test-io-util.c @@ -0,0 +1,69 @@ +/*** + 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 . +***/ + +#include +#include +#include + +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "macro.h" + +static void test_sparse_write_one(int fd, const char *buffer, size_t n) { + char check[n]; + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n); + + assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); + assert_se(ftruncate(fd, n) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(read(fd, check, n) == (ssize_t) n); + + assert_se(memcmp(buffer, check, n) == 0); +} + +static void test_sparse_write(void) { + const char test_a[] = "test"; + const char test_b[] = "\0\0\0\0test\0\0\0\0"; + const char test_c[] = "\0\0test\0\0\0\0"; + const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0"; + const char test_e[] = "test\0\0\0\0test"; + _cleanup_close_ int fd = -1; + char fn[] = "/tmp/sparseXXXXXX"; + + fd = mkostemp(fn, O_CLOEXEC); + assert_se(fd >= 0); + unlink(fn); + + test_sparse_write_one(fd, test_a, sizeof(test_a)); + test_sparse_write_one(fd, test_b, sizeof(test_b)); + test_sparse_write_one(fd, test_c, sizeof(test_c)); + test_sparse_write_one(fd, test_d, sizeof(test_d)); + test_sparse_write_one(fd, test_e, sizeof(test_e)); +} + +int main(void) { + test_sparse_write(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 50bb0211be..4eb17e47e5 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -32,7 +32,6 @@ #include "fileio.h" #include "fs-util.h" #include "glob-util.h" -#include "io-util.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" @@ -295,42 +294,6 @@ static void test_raw_clone(void) { } } -static void test_sparse_write_one(int fd, const char *buffer, size_t n) { - char check[n]; - - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(ftruncate(fd, 0) >= 0); - assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n); - - assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); - assert_se(ftruncate(fd, n) >= 0); - - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(read(fd, check, n) == (ssize_t) n); - - assert_se(memcmp(buffer, check, n) == 0); -} - -static void test_sparse_write(void) { - const char test_a[] = "test"; - const char test_b[] = "\0\0\0\0test\0\0\0\0"; - const char test_c[] = "\0\0test\0\0\0\0"; - const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0"; - const char test_e[] = "test\0\0\0\0test"; - _cleanup_close_ int fd = -1; - char fn[] = "/tmp/sparseXXXXXX"; - - fd = mkostemp(fn, O_CLOEXEC); - assert_se(fd >= 0); - unlink(fn); - - test_sparse_write_one(fd, test_a, sizeof(test_a)); - test_sparse_write_one(fd, test_b, sizeof(test_b)); - test_sparse_write_one(fd, test_c, sizeof(test_c)); - test_sparse_write_one(fd, test_d, sizeof(test_d)); - test_sparse_write_one(fd, test_e, sizeof(test_e)); -} - static void test_fgetxattrat_fake(void) { char t[] = "/var/tmp/xattrtestXXXXXX"; _cleanup_close_ int fd = -1; @@ -378,7 +341,6 @@ int main(int argc, char *argv[]) { test_glob_exists(); test_execute_directory(); test_raw_clone(); - test_sparse_write(); test_fgetxattrat_fake(); return 0; -- cgit v1.2.3-54-g00ecf From 6a4f4a0fa016a28bf0161d46034d2dc875c0f38f Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:31:23 +0100 Subject: tests: move glob-util related tests to test-glob-util.c --- .gitignore | 1 + Makefile.am | 7 +++++++ src/test/test-glob-util.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ src/test/test-util.c | 20 ------------------- 4 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 src/test/test-glob-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index a17cbad004..41162ab553 100644 --- a/.gitignore +++ b/.gitignore @@ -193,6 +193,7 @@ /test-firewall-util /test-fs-util /test-fstab-util +/test-glob-util /test-hashmap /test-hexdecoct /test-hostname diff --git a/Makefile.am b/Makefile.am index 1b06ffb98c..5e536dd9a2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1432,6 +1432,7 @@ tests += \ test-alloc-util \ test-proc-cmdline \ test-io-util \ + test-glob-util \ test-fs-util \ test-web-util \ test-stat-util \ @@ -1783,6 +1784,12 @@ test_io_util_SOURCES = \ test_io_util_LDADD = \ libbasic.la +test_glob_util_SOURCES = \ + src/test/test-glob-util.c + +test_glob_util_LDADD = \ + libbasic.la + test_fs_util_SOURCES = \ src/test/test-fs-util.c diff --git a/src/test/test-glob-util.c b/src/test/test-glob-util.c new file mode 100644 index 0000000000..227d4290f0 --- /dev/null +++ b/src/test/test-glob-util.c @@ -0,0 +1,50 @@ +/*** + 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 . +***/ + +#include +#include + +#include "alloc-util.h" +#include "fileio.h" +#include "glob-util.h" +#include "macro.h" + +static void test_glob_exists(void) { + char name[] = "/tmp/test-glob_exists.XXXXXX"; + int fd = -1; + int r; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 1); + + r = unlink(name); + assert_se(r == 0); + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 0); +} + +int main(void) { + test_glob_exists(); + + return 0; +} diff --git a/src/test/test-util.c b/src/test/test-util.c index 4eb17e47e5..3d876ab5e5 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -31,7 +31,6 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "glob-util.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" @@ -207,24 +206,6 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } -static void test_glob_exists(void) { - char name[] = "/tmp/test-glob_exists.XXXXXX"; - int fd = -1; - int r; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 1); - - r = unlink(name); - assert_se(r == 0); - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 0); -} - static void test_execute_directory(void) { char template_lo[] = "/tmp/test-readlink_and_make_absolute-lo.XXXXXXX"; char template_hi[] = "/tmp/test-readlink_and_make_absolute-hi.XXXXXXX"; @@ -338,7 +319,6 @@ int main(int argc, char *argv[]) { test_protect_errno(); test_in_set(); test_log2i(); - test_glob_exists(); test_execute_directory(); test_raw_clone(); test_fgetxattrat_fake(); -- cgit v1.2.3-54-g00ecf From ac229ed8901d487854e4db9ab884898b97d0cc7f Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:35:36 +0100 Subject: tests: move xattr-util related tests to test-xattr-util.c --- .gitignore | 1 + Makefile.am | 7 +++++ src/test/test-util.c | 34 ----------------------- src/test/test-xattr-util.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 34 deletions(-) create mode 100644 src/test/test-xattr-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 41162ab553..3c52e35f75 100644 --- a/.gitignore +++ b/.gitignore @@ -284,6 +284,7 @@ /test-verbs /test-watchdog /test-web-util +/test-xattr-util /test-xml /timedatectl /udevadm diff --git a/Makefile.am b/Makefile.am index 5e536dd9a2..6dbc085a4d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1433,6 +1433,7 @@ tests += \ test-proc-cmdline \ test-io-util \ test-glob-util \ + test-xattr-util \ test-fs-util \ test-web-util \ test-stat-util \ @@ -1778,6 +1779,12 @@ test_alloc_util_SOURCES = \ test_alloc_util_LDADD = \ libbasic.la +test_xattr_util_SOURCES = \ + src/test/test-xattr-util.c + +test_xattr_util_LDADD = \ + libbasic.la + test_io_util_SOURCES = \ src/test/test-io-util.c diff --git a/src/test/test-util.c b/src/test/test-util.c index 3d876ab5e5..77eac221f7 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -41,7 +41,6 @@ #include "strv.h" #include "util.h" #include "virt.h" -#include "xattr-util.h" static void test_align_power2(void) { unsigned long i, p2; @@ -275,38 +274,6 @@ static void test_raw_clone(void) { } } -static void test_fgetxattrat_fake(void) { - char t[] = "/var/tmp/xattrtestXXXXXX"; - _cleanup_close_ int fd = -1; - const char *x; - char v[3] = {}; - int r; - - assert_se(mkdtemp(t)); - x = strjoina(t, "/test"); - assert_se(touch(x) >= 0); - - r = setxattr(x, "user.foo", "bar", 3, 0); - if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ - goto cleanup; - assert_se(r >= 0); - - fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); - assert_se(fd >= 0); - - assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); - assert_se(memcmp(v, "bar", 3) == 0); - - safe_close(fd); - fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); - assert_se(fd >= 0); - assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); - -cleanup: - assert_se(unlink(x) >= 0); - assert_se(rmdir(t) >= 0); -} - int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -321,7 +288,6 @@ int main(int argc, char *argv[]) { test_log2i(); test_execute_directory(); test_raw_clone(); - test_fgetxattrat_fake(); return 0; } diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c new file mode 100644 index 0000000000..267f29426c --- /dev/null +++ b/src/test/test-xattr-util.c @@ -0,0 +1,69 @@ +/*** + 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 . +***/ + +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "string-util.h" +#include "xattr-util.h" + +static void test_fgetxattrat_fake(void) { + char t[] = "/var/tmp/xattrtestXXXXXX"; + _cleanup_close_ int fd = -1; + const char *x; + char v[3] = {}; + int r; + + assert_se(mkdtemp(t)); + x = strjoina(t, "/test"); + assert_se(touch(x) >= 0); + + r = setxattr(x, "user.foo", "bar", 3, 0); + if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ + goto cleanup; + assert_se(r >= 0); + + fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + + assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); + assert_se(memcmp(v, "bar", 3) == 0); + + safe_close(fd); + fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); + +cleanup: + assert_se(unlink(x) >= 0); + assert_se(rmdir(t) >= 0); +} + +int main(void) { + test_fgetxattrat_fake(); + + return 0; +} -- cgit v1.2.3-54-g00ecf From 31b5d9898129b6a1890ef5e004e5db5bbbf5f9e5 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Thu, 3 Mar 2016 00:39:47 +0100 Subject: test-util: remove now unused includes --- src/test/test-util.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src') diff --git a/src/test/test-util.c b/src/test/test-util.c index 77eac221f7..05cb1eae76 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -19,28 +19,16 @@ ***/ #include -#include #include -#include #include -#include #include -#include "alloc-util.h" #include "def.h" -#include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "mkdir.h" -#include "parse-util.h" -#include "path-util.h" -#include "process-util.h" #include "rm-rf.h" -#include "special.h" #include "string-util.h" -#include "strv.h" #include "util.h" -#include "virt.h" static void test_align_power2(void) { unsigned long i, p2; -- cgit v1.2.3-54-g00ecf From a1d2de078c910ccda89ea5ca25494aaa6fa8f3b5 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Fri, 4 Mar 2016 01:58:28 +0000 Subject: selinux: use *_raw API from libselinux This is a follow-up to 5c5433ad32 --- src/basic/selinux-util.c | 12 ++++++------ src/core/selinux-setup.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 5e6181f662..10c2f39369 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -152,7 +152,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { return 0; if (r >= 0) { - r = lsetfilecon(path, fcon); + r = lsetfilecon_raw(path, fcon); /* If the FS doesn't support labels, then exit without warning */ if (r < 0 && errno == EOPNOTSUPP) @@ -262,7 +262,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * if (r < 0) return -errno; - r = getpeercon(socket_fd, &peercon); + r = getpeercon_raw(socket_fd, &peercon); if (r < 0) return -errno; @@ -371,7 +371,7 @@ void mac_selinux_create_file_clear(void) { if (!mac_selinux_use()) return; - setfscreatecon(NULL); + setfscreatecon_raw(NULL); #endif } @@ -402,7 +402,7 @@ void mac_selinux_create_socket_clear(void) { if (!mac_selinux_use()) return; - setsockcreatecon(NULL); + setsockcreatecon_raw(NULL); #endif } @@ -461,7 +461,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { return -errno; } else { - if (setfscreatecon(fcon) < 0) { + if (setfscreatecon_raw(fcon) < 0) { log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); if (security_getenforce() > 0) return -errno; @@ -472,7 +472,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { r = bind(fd, addr, addrlen) < 0 ? -errno : 0; if (context_changed) - setfscreatecon(NULL); + setfscreatecon_raw(NULL); return r; diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index 9a115a4387..4072df58e6 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -88,7 +88,7 @@ int mac_selinux_setup(bool *loaded_policy) { log_open(); log_error("Failed to compute init label, ignoring."); } else { - r = setcon(label); + r = setcon_raw(label); log_open(); if (r < 0) -- cgit v1.2.3-54-g00ecf From 9c0d1c1cb5a06d5799c6874d9e284353b76f760e Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 3 Mar 2016 20:40:01 +0000 Subject: core/failure-action: Set job-modes to replace-irreversibly Up until now, the failure action has launched reboot.target and poweroff.target with a less aggressive job mode than "systemctl reboot" does. This has meant that the reboot and power- off operations can stall if there are any conflicts with the target during rebooting. --- src/core/failure-action.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/failure-action.c b/src/core/failure-action.c index 39f5519ca1..bb2bc3f399 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -62,7 +62,8 @@ int failure_action( log_and_status(m, "Rebooting as result of failure."); update_reboot_param_file(reboot_arg); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, + JOB_REPLACE_IRREVERSIBLY, NULL); break; @@ -89,7 +90,8 @@ int failure_action( case FAILURE_ACTION_POWEROFF: log_and_status(m, "Powering off as result of failure."); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, + JOB_REPLACE_IRREVERSIBLY, NULL); break; case FAILURE_ACTION_POWEROFF_FORCE: -- cgit v1.2.3-54-g00ecf From 04a9393122d79a3d14506459b0f2c5348673464c Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Thu, 3 Mar 2016 17:25:53 +0000 Subject: core/mount: Don't unmount initramfs mounts A mount within /run/initramfs is indicative that the mount was created by initramfs init and will be unmounted by initramfs shutdown. It is unlikely that such a mount point would even be unmountable by the the main system, for example in the case of the root file- system being loop-mounted from a file in a /run/initramfs mount. --- src/core/mount.c | 15 +++++++++------ src/core/umount.c | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/core/mount.c b/src/core/mount.c index 93d2bd595c..540ec5fdda 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -369,7 +369,8 @@ static bool should_umount(Mount *m) { MountParameters *p; if (path_equal(m->where, "/") || - path_equal(m->where, "/usr")) + path_equal(m->where, "/usr") || + path_startswith(m->where, "/run/initramfs")) return false; p = get_mount_parameters(m); @@ -393,13 +394,15 @@ static int mount_add_default_dependencies(Mount *m) { if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) return 0; - /* We do not add any default dependencies to / and /usr, since - * they are guaranteed to stay mounted the whole time, since - * our system is on it. Also, don't bother with anything - * mounted below virtual file systems, it's also going to be - * virtual, and hence not worth the effort. */ + /* We do not add any default dependencies to /, /usr or + * /run/initramfs/, since they are guaranteed to stay + * mounted the whole time, since our system is on it. + * Also, don't bother with anything mounted below virtual + * file systems, it's also going to be virtual, and hence + * not worth the effort. */ if (path_equal(m->where, "/") || path_equal(m->where, "/usr") || + path_startswith(m->where, "/run/initramfs") || path_startswith(m->where, "/proc") || path_startswith(m->where, "/sys") || path_startswith(m->where, "/dev")) diff --git a/src/core/umount.c b/src/core/umount.c index b953fcc152..c21a2be54e 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -412,6 +412,7 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e #ifndef HAVE_SPLIT_USR || path_equal(m->path, "/usr") #endif + || path_startswith(m->path, "/run/initramfs") ) continue; -- cgit v1.2.3-54-g00ecf From 2b14df4a9ae92623b584e61db6b5b37accd832c1 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Tue, 1 Dec 2015 18:01:44 +0100 Subject: fstab-generator: fix automount option and don't start associated mount unit at boot Without this patch applied the mount unit with 'automount' option was still pulled by local-fs.target and thus was activated during the boot process which defeats the purpose of the 'automount' option: $ grep /mnt /etc/fstab /dev/vdb1 /mnt ext2 defaults,x-systemd.automount 0 0 $ reboot ... $ mount | grep mnt systemd-1 on /mnt type autofs (rw,relatime,fd=34,pgrp=1,timeout=0,minproto=5,maxproto=5,direct) /dev/vdb1 on /mnt type ext2 (rw,relatime) $ systemctl status mnt.mount | grep Active Active: active (mounted) since Thu 2016-03-03 21:36:22 CET; 42s ago With the patch applied: $ reboot ... $ mount | grep mnt systemd-1 on /mnt type autofs (rw,relatime,fd=22,pgrp=1,timeout=0,minproto=5,maxproto=5,direct) $ systemctl status mnt.mount | grep Active Active: inactive (dead) $ ls /mnt lost+found $ systemctl status mnt.mount | grep Active Active: active (mounted) since Thu 2016-03-03 21:47:32 CET; 4s ago --- src/core/mount.c | 11 ++++++++++- src/fstab-generator/fstab-generator.c | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/mount.c b/src/core/mount.c index 93d2bd595c..c0026e09b3 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -104,6 +104,14 @@ static bool mount_is_auto(const MountParameters *p) { return !fstab_test_option(p->options, "noauto\0"); } +static bool mount_is_automount(const MountParameters *p) { + assert(p); + + return fstab_test_option(p->options, + "comment=systemd.automount\0" + "x-systemd.automount\0"); +} + static bool needs_quota(const MountParameters *p) { assert(p); @@ -328,7 +336,8 @@ static int mount_add_device_links(Mount *m) { if (path_equal(m->where, "/")) return 0; - if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM) + if (mount_is_auto(p) && !mount_is_automount(p) && + UNIT(m)->manager->running_as == MANAGER_SYSTEM) device_wants_mount = true; r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES); diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 97a48764ae..6f576b5ecf 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -336,8 +336,8 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", unit); - if (!noauto) { - lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL); + if (!noauto && !automount) { + lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", name, NULL); if (!lnk) return log_oom(); -- cgit v1.2.3-54-g00ecf From f26b57d12a2ea08a9b2622dfb2a5cc76988318b1 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Feb 2016 09:00:33 -0500 Subject: Move test-loopback to normal tests In the normal case lo should be already configured and this should be a noop, even when run under root. --- Makefile.am | 2 +- src/test/test-loopback.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 0f17bad8b1..5f5d9f0105 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1387,7 +1387,6 @@ EXTRA_DIST += \ manual_tests += \ test-ns \ - test-loopback \ test-hostname \ test-daemon \ test-cgroup \ @@ -1411,6 +1410,7 @@ manual_tests += \ endif tests += \ + test-loopback \ test-engine \ test-cgroup-mask \ test-job-type \ diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index 2748395ade..7b67337331 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -31,7 +31,7 @@ int main(int argc, char* argv[]) { r = loopback_setup(); if (r < 0) - fprintf(stderr, "loopback: %s\n", strerror(-r)); + log_error("loopback: %m"); - return 0; + return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- cgit v1.2.3-54-g00ecf From a4bfedec701fb4433923c338b623d1d3e21ed620 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Feb 2016 09:06:10 -0500 Subject: Rename test-boot-timestamp to test-boot-timestamps and enable by default The source file name and the binary name were mismatched. Rename binary to match. Make the test exit with TEST_SKIP if the data is missing or we have no permissions. Otherwise, the data will be printed, which should be safe to enable by default. --- .gitignore | 2 +- Makefile.am | 8 +++---- src/test/test-boot-timestamps.c | 51 +++++++++++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/.gitignore b/.gitignore index 18db046cac..162160ef21 100644 --- a/.gitignore +++ b/.gitignore @@ -133,7 +133,7 @@ /test-audit-type /test-barrier /test-bitmap -/test-boot-timestamp +/test-boot-timestamps /test-btrfs /test-bus-benchmark /test-bus-chat diff --git a/Makefile.am b/Makefile.am index 5f5d9f0105..0ee52324a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1651,13 +1651,13 @@ test_dns_domain_LDADD = \ if ENABLE_EFI -manual_tests += \ - test-boot-timestamp +tests += \ + test-boot-timestamps -test_boot_timestamp_SOURCES = \ +test_boot_timestamps_SOURCES = \ src/test/test-boot-timestamps.c -test_boot_timestamp_LDADD = \ +test_boot_timestamps_LDADD = \ libshared.la endif diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index d2add5880c..9fb6bbef93 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -34,17 +34,18 @@ static int test_acpi_fpdt(void) { r = acpi_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read ACPI FPDT: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read ACPI FPDT: %m"); + return ok ? 0 : r; } log_info("ACPI FPDT: loader start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } static int test_efi_loader(void) { @@ -57,33 +58,34 @@ static int test_efi_loader(void) { r = efi_loader_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read EFI loader data: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read EFI loader data: %m"); + return ok ? 0 : r; } log_info("EFI Loader: start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } -int main(int argc, char* argv[]) { +static int test_boot_timestamps(void) { char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)]; int r; dual_timestamp fw, l, k; - test_acpi_fpdt(); - test_efi_loader(); - dual_timestamp_from_monotonic(&k, 0); r = boot_timestamps(NULL, &fw, &l); if (r < 0) { - log_error_errno(r, "Failed to read variables: %m"); - return 1; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read variables: %m"); + return ok ? 0 : r; } log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0)); @@ -91,6 +93,21 @@ int main(int argc, char* argv[]) { log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime)); log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime)); log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime)); + return 1; +} + +int main(int argc, char* argv[]) { + int p, q, r; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + p = test_acpi_fpdt(); + assert(p >= 0); + q = test_efi_loader(); + assert(q >= 0); + r = test_boot_timestamps(); + assert(r >= 0); - return 0; + return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP; } -- cgit v1.2.3-54-g00ecf From 67a47c609683559dddba0c8e3875723010a088e1 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 27 Feb 2016 11:30:22 -0500 Subject: shared/acpi-fpdt: use ENODATA for missing data and skip test This data is simply missing on non-UEFI systems, and it is useful to distinguish that from corrupted data. --- src/shared/acpi-fpdt.c | 6 +++++- src/test/test-boot-timestamps.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 3cb9e781fd..6779691c28 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -119,7 +119,7 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { } if (ptr == 0) - return -EINVAL; + return -ENODATA; /* read Firmware Basic Boot Performance Data Record */ fd = open("/dev/mem", O_CLOEXEC|O_RDONLY); @@ -146,6 +146,10 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { if (brec.type != ACPI_FPDT_BOOT_REC) return -EINVAL; + if (brec.exit_services_exit == 0) + /* Non-UEFI compatible boot. */ + return -ENODATA; + if (brec.startup_start == 0 || brec.exit_services_exit < brec.startup_start) return -EINVAL; if (brec.exit_services_exit > NSEC_PER_HOUR) diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index 9fb6bbef93..8e68d6510d 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -34,7 +34,7 @@ static int test_acpi_fpdt(void) { r = acpi_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA; log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read ACPI FPDT: %m"); -- cgit v1.2.3-54-g00ecf From 134953c99c7441c4fa2d8000face10608f8832ec Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Feb 2016 09:10:48 -0500 Subject: Enable test-daemon, test-log, test-watchdog by default Those should be safe to run, resulting in some messages in logs. --- Makefile.am | 6 +++--- src/test/test-daemon.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 0ee52324a3..c6f6bc5d37 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1388,11 +1388,8 @@ EXTRA_DIST += \ manual_tests += \ test-ns \ test-hostname \ - test-daemon \ test-cgroup \ test-install \ - test-watchdog \ - test-log \ test-ipcrm \ test-btrfs \ test-acd \ @@ -1410,8 +1407,11 @@ manual_tests += \ endif tests += \ + test-daemon \ + test-log \ test-loopback \ test-engine \ + test-watchdog \ test-cgroup-mask \ test-job-type \ test-env-replace \ diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index 4ce00f4b1f..a7cb426282 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -38,27 +38,27 @@ int main(int argc, char*argv[]) { sd_notify(0, "STATUS=Starting up"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Reloading\n" "RELOADING=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Quitting\n" "STOPPING=1"); - sleep(5); + sleep(1); return EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From c1ab81916286747a1b466716188f05ae373dff6e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 26 Feb 2016 18:39:20 -0500 Subject: Enable test-ipcrm, test-hostname in unsafe tests --- Makefile.am | 12 +++++++++--- configure.ac | 6 ++++-- src/test/test-ipcrm.c | 11 ++++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index c6f6bc5d37..e2d5328c1b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -131,8 +131,12 @@ TEST_EXTENSIONS = .py PY_LOG_COMPILER = $(PYTHON) DISABLE_HARD_ERRORS = yes if ENABLE_TESTS -noinst_PROGRAMS = $(manual_tests) $(tests) +noinst_PROGRAMS = $(manual_tests) $(tests) $(unsafe_tests) TESTS = $(tests) +if ENABLE_UNSAFE_TESTS +TESTS += \ + $(unsafe_tests) +endif else noinst_PROGRAMS = TESTS = @@ -1387,15 +1391,17 @@ EXTRA_DIST += \ manual_tests += \ test-ns \ - test-hostname \ test-cgroup \ test-install \ - test-ipcrm \ test-btrfs \ test-acd \ test-ipv4ll-manual \ test-ask-password-api +unsafe_tests = \ + test-hostname \ + test-ipcrm + if HAVE_LIBIPTC manual_tests += \ test-firewall-util diff --git a/configure.ac b/configure.ac index e55d1a02a6..79340bcca9 100644 --- a/configure.ac +++ b/configure.ac @@ -1487,9 +1487,10 @@ AS_IF([test x"$cross_compiling" = "xyes"], [], [ ]) AC_ARG_ENABLE(tests, - [AC_HELP_STRING([--disable-tests], [disable tests])], + [AC_HELP_STRING([--disable-tests], [disable tests, or enable extra tests with =unsafe])], enable_tests=$enableval, enable_tests=yes) -AM_CONDITIONAL(ENABLE_TESTS, [test x$enable_tests = xyes]) +AM_CONDITIONAL(ENABLE_TESTS, [test x$enable_tests = xyes -o x$enable_tests = xunsafe]) +AM_CONDITIONAL(ENABLE_UNSAFE_TESTS, [test x$enable_tests = xunsafe]) AC_ARG_ENABLE(debug, [AC_HELP_STRING([--enable-debug@<:@=LIST@:>@], [enable extra debugging (hashmap,mmap-cache)])], @@ -1611,6 +1612,7 @@ AC_MSG_RESULT([ ldconfig support: ${enable_ldconfig} hibernate support: ${enable_hibernate} extra debugging: ${enable_debug} + tests: ${enable_tests} prefix: ${prefix} rootprefix: ${with_rootprefix} diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 2464d32458..47b1c4443d 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -23,9 +23,14 @@ int main(int argc, char *argv[]) { uid_t uid; - - assert_se(argc == 2); - assert_se(parse_uid(argv[1], &uid) >= 0); + int r; + const char* name = argv[1] ?: "nfsnobody"; + + r = get_user_creds(&name, &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Failed to resolve \"nobody\": %m"); + return EXIT_FAILURE; + } return clean_ipc(uid) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From cc4c1d22907fe0a69c23edb312fde2e2ac531112 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 1 Mar 2016 21:40:56 -0500 Subject: test-libudev: modernization --- src/test/test-libudev.c | 258 +++++++++++++++++++----------------------------- 1 file changed, 101 insertions(+), 157 deletions(-) (limited to 'src') diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index a7eb60e8cf..5ac513b013 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -24,170 +24,140 @@ #include "libudev.h" +#include "fd-util.h" +#include "log.h" #include "stdio-util.h" #include "string-util.h" #include "udev-util.h" #include "util.h" -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static void print_device(struct udev_device *device) { const char *str; dev_t devnum; int count; struct udev_list_entry *list_entry; - printf("*** device: %p ***\n", device); + log_info("*** device: %p ***", device); str = udev_device_get_action(device); if (str != NULL) - printf("action: '%s'\n", str); + log_info("action: '%s'", str); str = udev_device_get_syspath(device); - printf("syspath: '%s'\n", str); + log_info("syspath: '%s'", str); str = udev_device_get_sysname(device); - printf("sysname: '%s'\n", str); + log_info("sysname: '%s'", str); str = udev_device_get_sysnum(device); if (str != NULL) - printf("sysnum: '%s'\n", str); + log_info("sysnum: '%s'", str); str = udev_device_get_devpath(device); - printf("devpath: '%s'\n", str); + log_info("devpath: '%s'", str); str = udev_device_get_subsystem(device); if (str != NULL) - printf("subsystem: '%s'\n", str); + log_info("subsystem: '%s'", str); str = udev_device_get_devtype(device); if (str != NULL) - printf("devtype: '%s'\n", str); + log_info("devtype: '%s'", str); str = udev_device_get_driver(device); if (str != NULL) - printf("driver: '%s'\n", str); + log_info("driver: '%s'", str); str = udev_device_get_devnode(device); if (str != NULL) - printf("devname: '%s'\n", str); + log_info("devname: '%s'", str); devnum = udev_device_get_devnum(device); if (major(devnum) > 0) - printf("devnum: %u:%u\n", major(devnum), minor(devnum)); + log_info("devnum: %u:%u", major(devnum), minor(devnum)); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { - printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); + log_info("link: '%s'", udev_list_entry_get_name(list_entry)); count++; } if (count > 0) - printf("found %i links\n", count); + log_info("found %i links", count); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { - printf("property: '%s=%s'\n", + log_info("property: '%s=%s'", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); count++; } if (count > 0) - printf("found %i properties\n", count); + log_info("found %i properties", count); str = udev_device_get_property_value(device, "MAJOR"); if (str != NULL) - printf("MAJOR: '%s'\n", str); + log_info("MAJOR: '%s'", str); str = udev_device_get_sysattr_value(device, "dev"); if (str != NULL) - printf("attr{dev}: '%s'\n", str); - - printf("\n"); + log_info("attr{dev}: '%s'", str); } -static int test_device(struct udev *udev, const char *syspath) { +static void test_device(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); - if (device == NULL) { - printf("no device found\n"); - return -1; - } - print_device(device); - - return 0; + if (device == NULL) + log_warning_errno(errno, "udev_device_new_from_syspath: %m"); + else + print_device(device); } -static int test_device_parents(struct udev *udev, const char *syspath) { +static void test_device_parents(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; struct udev_device *device_parent; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); if (device == NULL) - return -1; + return; - printf("looking at parents\n"); + log_info("looking at parents"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - printf("looking at parents again\n"); + log_info("looking at parents again"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - - return 0; } -static int test_device_devnum(struct udev *udev) { +static void test_device_devnum(struct udev *udev) { dev_t devnum = makedev(1, 3); - struct udev_device *device; + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); + log_info("looking up device: %u:%u", major(devnum), minor(devnum)); device = udev_device_new_from_devnum(udev, 'c', devnum); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_devnum: %m"); + else + print_device(device); } -static int test_device_subsys_name(struct udev *udev) { - struct udev_device *device; - - printf("looking up device: 'block':'sda'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'subsystem':'pci'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'drivers':'scsi:sd'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); +static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) { + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: 'module':'printk'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); + log_info("looking up device: '%s:%s'", subsys, dev); + device = udev_device_new_from_subsystem_sysname(udev, subsys, dev); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m"); + else + print_device(device); } static int test_enumerate_print_list(struct udev_enumerate *enumerate) { @@ -200,63 +170,45 @@ static int test_enumerate_print_list(struct udev_enumerate *enumerate) { device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), udev_list_entry_get_name(list_entry)); if (device != NULL) { - printf("device: '%s' (%s)\n", - udev_device_get_syspath(device), - udev_device_get_subsystem(device)); + log_info("device: '%s' (%s)", + udev_device_get_syspath(device), + udev_device_get_subsystem(device)); udev_device_unref(device); count++; } } - printf("found %i devices\n\n", count); + log_info("found %i devices", count); return count; } -static int test_monitor(struct udev *udev) { - struct udev_monitor *udev_monitor = NULL; - int fd_ep; - int fd_udev = -1; - struct epoll_event ep_udev, ep_stdin; +static void test_monitor(struct udev *udev) { + _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor; + _cleanup_close_ int fd_ep; + int fd_udev; + struct epoll_event ep_udev = { + .events = EPOLLIN, + }, ep_stdin = { + .events = EPOLLIN, + .data.fd = STDIN_FILENO, + }; fd_ep = epoll_create1(EPOLL_CLOEXEC); - if (fd_ep < 0) { - printf("error creating epoll fd: %m\n"); - goto out; - } + assert_se(fd_ep >= 0); udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (udev_monitor == NULL) { - printf("no socket\n"); - goto out; - } - fd_udev = udev_monitor_get_fd(udev_monitor); + assert_se(udev_monitor != NULL); - if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { - printf("filter failed\n"); - goto out; - } + fd_udev = udev_monitor_get_fd(udev_monitor); + ep_udev.data.fd = fd_udev; - if (udev_monitor_enable_receiving(udev_monitor) < 0) { - printf("bind failed\n"); - goto out; - } + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") >= 0); - memzero(&ep_udev, sizeof(struct epoll_event)); - ep_udev.events = EPOLLIN; - ep_udev.data.fd = fd_udev; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } + assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0); - memzero(&ep_stdin, sizeof(struct epoll_event)); - ep_stdin.events = EPOLLIN; - ep_stdin.data.fd = STDIN_FILENO; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) >= 0); + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) >= 0); for (;;) { int fdcount; @@ -265,7 +217,7 @@ static int test_monitor(struct udev *udev) { int i; printf("waiting for events from udev, press ENTER to exit\n"); - fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); printf("epoll fd count: %i\n", fdcount); for (i = 0; i < fdcount; i++) { @@ -279,36 +231,29 @@ static int test_monitor(struct udev *udev) { udev_device_unref(device); } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { printf("exiting loop\n"); - goto out; + return; } } } -out: - if (fd_ep >= 0) - close(fd_ep); - udev_monitor_unref(udev_monitor); - return 0; } -static int test_queue(struct udev *udev) { +static void test_queue(struct udev *udev) { struct udev_queue *udev_queue; + bool empty; udev_queue = udev_queue_new(udev); - if (udev_queue == NULL) - return -1; - - if (udev_queue_get_queue_is_empty(udev_queue)) - printf("queue is empty\n"); + assert_se(udev_queue); + empty = udev_queue_get_queue_is_empty(udev_queue); + log_info("queue is %s", empty ? "empty" : "not empty"); udev_queue_unref(udev_queue); - return 0; } static int test_enumerate(struct udev *udev, const char *subsystem) { struct udev_enumerate *udev_enumerate; int r; - printf("enumerate '%s'\n", subsystem == NULL ? "" : subsystem); + log_info("enumerate '%s'", subsystem == NULL ? "" : subsystem); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -317,7 +262,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'net' + duplicated scan + null + zero\n"); + log_info("enumerate 'net' + duplicated scan + null + zero"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -337,7 +282,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'block'\n"); + log_info("enumerate 'block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -351,7 +296,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'not block'\n"); + log_info("enumerate 'not block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -360,7 +305,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'pci, mem, vc'\n"); + log_info("enumerate 'pci, mem, vc'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -371,7 +316,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'subsystem'\n"); + log_info("enumerate 'subsystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -379,7 +324,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'property IF_FS_*=filesystem'\n"); + log_info("enumerate 'property IF_FS_*=filesystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -397,32 +342,30 @@ static void test_hwdb(struct udev *udev, const char *modalias) { hwdb = udev_hwdb_new(udev); udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) - printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); - printf("\n"); + log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); hwdb = udev_hwdb_unref(hwdb); assert_se(hwdb == NULL); } int main(int argc, char *argv[]) { - struct udev *udev = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; static const struct option options[] = { - { "syspath", required_argument, NULL, 'p' }, + { "syspath", required_argument, NULL, 'p' }, { "subsystem", required_argument, NULL, 's' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, {} }; const char *syspath = "/devices/virtual/mem/null"; const char *subsystem = NULL; - char path[1024]; int c; udev = udev_new(); - printf("context: %p\n", udev); + log_info("context: %p", udev); if (udev == NULL) { - printf("no context\n"); + log_info("no context"); return 1; } @@ -444,14 +387,14 @@ int main(int argc, char *argv[]) { case 'h': printf("--debug --syspath= --subsystem= --help\n"); - goto out; + return EXIT_SUCCESS; case 'V': printf("%s\n", VERSION); - goto out; + return EXIT_SUCCESS; case '?': - goto out; + return EXIT_FAILURE; default: assert_not_reached("Unhandled option code."); @@ -459,14 +402,16 @@ int main(int argc, char *argv[]) { /* add sys path if needed */ - if (!startswith(syspath, "/sys")) { - xsprintf(path, "/sys/%s", syspath); - syspath = path; - } + if (!startswith(syspath, "/sys")) + syspath = strjoina("/sys/", syspath); test_device(udev, syspath); test_device_devnum(udev); - test_device_subsys_name(udev); + test_device_subsys_name(udev, "block", "sda"); + test_device_subsys_name(udev, "subsystem", "pci"); + test_device_subsys_name(udev, "drivers", "scsi:sd"); + test_device_subsys_name(udev, "module", "printk"); + test_device_parents(udev, syspath); test_enumerate(udev, subsystem); @@ -476,7 +421,6 @@ int main(int argc, char *argv[]) { test_hwdb(udev, "usb:v0D50p0011*"); test_monitor(udev); -out: - udev_unref(udev); - return 0; + + return EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From 301a9c67aaad103a5fb0cd06d775ded208220f49 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 1 Mar 2016 21:44:08 -0500 Subject: test-libudev: disable monitor mode by default and add to automatic tests --- Makefile.am | 4 +++- src/test/test-libudev.c | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index e2d5328c1b..270f09641b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3709,8 +3709,10 @@ endif endif endif +tests += \ + test-libudev + manual_tests += \ - test-libudev \ test-udev test_libudev_SOURCES = \ diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index 5ac513b013..e28de9b37b 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -350,12 +350,14 @@ static void test_hwdb(struct udev *udev, const char *modalias) { int main(int argc, char *argv[]) { _cleanup_udev_unref_ struct udev *udev = NULL; + bool arg_monitor = false; static const struct option options[] = { { "syspath", required_argument, NULL, 'p' }, { "subsystem", required_argument, NULL, 's' }, { "debug", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, + { "monitor", no_argument, NULL, 'm' }, {} }; const char *syspath = "/devices/virtual/mem/null"; @@ -393,6 +395,10 @@ int main(int argc, char *argv[]) { printf("%s\n", VERSION); return EXIT_SUCCESS; + case 'm': + arg_monitor = true; + break; + case '?': return EXIT_FAILURE; @@ -420,7 +426,8 @@ int main(int argc, char *argv[]) { test_hwdb(udev, "usb:v0D50p0011*"); - test_monitor(udev); + if (arg_monitor) + test_monitor(udev); return EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From b3ad5fa944245c8dd57980271aaf840acaf31881 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 2 Mar 2016 15:29:36 -0500 Subject: lldp: fix memleak in_addr_to_string returned 0, which was treated as error by the calling code, which expects 1 on success. CID #1351757, #1351758. --- src/libsystemd-network/lldp-neighbor.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index c61941cd70..190c9baece 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -446,7 +446,7 @@ static int format_mac_address(const void *data, size_t sz, char **ret) { static int format_network_address(const void *data, size_t sz, char **ret) { union in_addr_union a; - int family; + int family, r; if (sz == 6 && ((uint8_t*) data)[1] == 1) { memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in)); @@ -457,7 +457,10 @@ static int format_network_address(const void *data, size_t sz, char **ret) { } else return 0; - return in_addr_to_string(family, &a, ret); + r = in_addr_to_string(family, &a, ret); + if (r < 0) + return r; + return 1; } _public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) { -- cgit v1.2.3-54-g00ecf From 72e551f40b0bcc6f59b093b70424f3af32ed759b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 2 Mar 2016 15:43:30 -0500 Subject: networkctl: use ETHER_ADDR_NULL in one more place --- src/network/networkctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 0679114f74..e5b08d4826 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -147,7 +147,6 @@ static int link_info_compare(const void *a, const void *b) { } static int decode_link(sd_netlink_message *m, LinkInfo *info) { - static const struct ether_addr null_address = {}; const char *name; uint16_t type; int r; @@ -178,7 +177,7 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info) { info->has_mac_address = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 && - memcmp(&info->mac_address, &null_address, sizeof(struct ether_addr)) != 0; + memcmp(&info->mac_address, ÐER_ADDR_NULL, sizeof(struct ether_addr)) != 0; info->has_mtu = sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) && -- cgit v1.2.3-54-g00ecf From 2388b2f4d4481c69935abdc9c3ed9928d1f15a46 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 2 Mar 2016 15:43:41 -0500 Subject: networkctl: avoid reading past end of input buffer name is IFNAMSIZ bytes, but we would copy sizeof(info->name) bytes, which is IFNAMSIZ + 1. In effect we would go outside of the source buffer and possibly leave a non-null terminated string in info->name. CID #1351754. --- src/network/networkctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkctl.c b/src/network/networkctl.c index e5b08d4826..6ec7a911ca 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -45,6 +45,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "strxcpyx.h" #include "terminal-util.h" #include "util.h" #include "verbs.h" @@ -173,7 +174,7 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info) { if (r < 0) return r; - strncpy(info->name, name, sizeof(info->name)); + strscpy(info->name, sizeof info->name, name); info->has_mac_address = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 && -- cgit v1.2.3-54-g00ecf From b5ec6ada9cd03035c32b43d1df265d48cd6d168e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 3 Mar 2016 11:39:02 -0500 Subject: test-selinux: use yes_no() and strnull() --- src/test/test-selinux.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c index c2152269f8..7545ad3764 100644 --- a/src/test/test-selinux.c +++ b/src/test/test-selinux.c @@ -23,7 +23,9 @@ #include "fd-util.h" #include "log.h" #include "selinux-util.h" +#include "string-util.h" #include "time-util.h" +#include "util.h" static void test_testing(void) { bool b; @@ -31,18 +33,18 @@ static void test_testing(void) { log_info("============ %s ==========", __func__); b = mac_selinux_use(); - log_info("mac_selinux_use → %d", b); + log_info("mac_selinux_use → %s", yes_no(b)); b = mac_selinux_have(); - log_info("mac_selinux_have → %d", b); + log_info("mac_selinux_have → %s", yes_no(b)); mac_selinux_retest(); b = mac_selinux_use(); - log_info("mac_selinux_use → %d", b); + log_info("mac_selinux_use → %s", yes_no(b)); b = mac_selinux_have(); - log_info("mac_selinux_have → %d", b); + log_info("mac_selinux_have → %s", yes_no(b)); } static void test_loading(void) { @@ -76,16 +78,19 @@ static void test_misc(const char* fname) { log_info("============ %s ==========", __func__); r = mac_selinux_get_our_label(&label); - log_info_errno(r, "mac_selinux_get_our_label → %d (%m), \"%s\"", r, label); + log_info_errno(r, "mac_selinux_get_our_label → %d (%m), \"%s\"", + r, strnull(label)); r = mac_selinux_get_create_label_from_exe(fname, &label2); - log_info_errno(r, "mac_selinux_create_label_from_exe → %d (%m), \"%s\"", r, label2); + log_info_errno(r, "mac_selinux_create_label_from_exe → %d (%m), \"%s\"", + r, strnull(label2)); fd = socket(AF_INET, SOCK_DGRAM, 0); assert_se(fd >= 0); r = mac_selinux_get_child_mls_label(fd, fname, label2, &label3); - log_info_errno(r, "mac_selinux_get_child_mls_label → %d (%m), \"%s\"", r, label3); + log_info_errno(r, "mac_selinux_get_child_mls_label → %d (%m), \"%s\"", + r, strnull(label3)); } static void test_create_file_prepare(const char* fname) { -- cgit v1.2.3-54-g00ecf From 15b947fb798cd131355ba9935802d58e92bdba6e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 4 Mar 2016 21:46:47 -0500 Subject: test-compress-benchmark: skip loop iteration if size is 0 Otherwise we would hit an assert in the compression code. --- src/journal/test-compress-benchmark.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c index 5b2d130cd6..0ef6d36a50 100644 --- a/src/journal/test-compress-benchmark.c +++ b/src/journal/test-compress-benchmark.c @@ -105,6 +105,8 @@ static void test_compress_decompress(const char* label, const char* type, int r; size = permute(i); + if (size == 0) + continue; log_debug("%s %zu %zu", type, i, size); -- cgit v1.2.3-54-g00ecf From 0b8505b7c9b1d90a29013091bcce23540ae1c92c Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Sat, 5 Mar 2016 12:47:21 +0100 Subject: systemctl: improve error message when starting a unit failed Fixes #2798 --- src/systemctl/systemctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index a62f4bf2f5..19d4e2c6e5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2596,7 +2596,10 @@ static int start_unit_one( if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) && !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED)) - log_error("See system logs and 'systemctl status %s' for details.", name); + log_error("See %s logs and 'systemctl%s status %s' for details.", + arg_scope == UNIT_FILE_SYSTEM ? "system" : "user", + arg_scope == UNIT_FILE_SYSTEM ? "" : " --user", + name); return r; } -- cgit v1.2.3-54-g00ecf From 5883ff60179d01b55af8df27027be6a411881745 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Thu, 3 Mar 2016 23:30:37 +0600 Subject: tree-wide: use SET_FLAG() macro to make code more clear --- src/libsystemd/sd-bus/bus-message.c | 15 +++------------ src/libsystemd/sd-bus/sd-bus.c | 5 +---- src/libsystemd/sd-netlink/netlink-message.c | 5 +---- src/network/networkd-network.c | 5 +---- src/resolve/resolve-tool.c | 20 ++++---------------- src/shared/ptyfwd.c | 5 +---- src/tmpfiles/tmpfiles.c | 5 +---- 7 files changed, 12 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 542c37e41b..b8958ec7bb 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1131,10 +1131,7 @@ _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) { assert_return(!m->sealed, -EPERM); assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED; - else - m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b); return 0; } @@ -1143,10 +1140,7 @@ _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) { assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START; - else - m->header->flags |= BUS_MESSAGE_NO_AUTO_START; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b); return 0; } @@ -1155,10 +1149,7 @@ _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message * assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; - else - m->header->flags &= ~BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; + SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b); return 0; } diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index cc15afeb1c..862f26aad7 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -313,10 +313,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - if (b) - bus->creds_mask |= mask; - else - bus->creds_mask &= ~mask; + SET_FLAG(bus->creds_mask, mask, b); /* The well knowns we need unconditionally, so that matches can work */ bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 3924300817..f56798674c 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -107,10 +107,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) { m->hdr->nlmsg_type == RTM_GETNEIGH, -EINVAL); - if (dump) - m->hdr->nlmsg_flags |= NLM_F_DUMP; - else - m->hdr->nlmsg_flags &= ~NLM_F_DUMP; + SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump); return 0; } diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index f175788977..491b9a3efa 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -629,10 +629,7 @@ int config_parse_ipv4ll( * config_parse_address_family_boolean(), except that it * applies only to IPv4 */ - if (parse_boolean(rvalue)) - *link_local |= ADDRESS_FAMILY_IPV4; - else - *link_local &= ~ADDRESS_FAMILY_IPV4; + SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue)); return 0; } diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 484fbb4d92..009cc73aec 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -1280,40 +1280,28 @@ static int parse_argv(int argc, char *argv[]) { r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --cname= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_CNAME; - else - arg_flags &= ~SD_RESOLVED_NO_CNAME; + SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0); break; case ARG_SERVICE_ADDRESS: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --service-address= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_ADDRESS; - else - arg_flags &= ~SD_RESOLVED_NO_ADDRESS; + SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0); break; case ARG_SERVICE_TXT: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --service-txt= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_TXT; - else - arg_flags &= ~SD_RESOLVED_NO_TXT; + SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0); break; case ARG_SEARCH: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --search argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_SEARCH; - else - arg_flags &= ~SD_RESOLVED_NO_SEARCH; + SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0); break; case ARG_STATISTICS: diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 061d31f4de..02c03b98d8 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -461,10 +461,7 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) { if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b) return 0; - if (b) - f->flags |= PTY_FORWARD_IGNORE_VHANGUP; - else - f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP; + SET_FLAG(f->flags, PTY_FORWARD_IGNORE_VHANGUP, b); if (!ignore_vhangup(f)) { diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 946808fbec..efd264b34d 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -917,10 +917,7 @@ static int parse_attribute_from_arg(Item *item) { v = attributes[i].value; - if (mode == MODE_ADD || mode == MODE_SET) - value |= v; - else - value &= ~v; + SET_FLAG(value, v, (mode == MODE_ADD || mode == MODE_SET)); mask |= v; } -- cgit v1.2.3-54-g00ecf From b3cd687d86789dd0069095cc5f114865128aeb91 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sun, 6 Mar 2016 13:27:59 +0600 Subject: firstboot: use laccess macro instead of facessat() --- src/firstboot/firstboot.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 7790ab865d..435e3805c4 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -245,7 +245,7 @@ static int process_locale(void) { int r; etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf"); - if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_localeconf, F_OK) >= 0) return 0; if (arg_copy_locale && arg_root) { @@ -319,7 +319,7 @@ static int process_timezone(void) { int r; etc_localtime = prefix_roota(arg_root, "/etc/localtime"); - if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_localtime, F_OK) >= 0) return 0; if (arg_copy_timezone && arg_root) { @@ -399,7 +399,7 @@ static int process_hostname(void) { int r; etc_hostname = prefix_roota(arg_root, "/etc/hostname"); - if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_hostname, F_OK) >= 0) return 0; r = prompt_hostname(); @@ -424,7 +424,7 @@ static int process_machine_id(void) { int r; etc_machine_id = prefix_roota(arg_root, "/etc/machine-id"); - if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_machine_id, F_OK) >= 0) return 0; if (sd_id128_equal(arg_machine_id, SD_ID128_NULL)) @@ -450,7 +450,7 @@ static int prompt_root_password(void) { return 0; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); - if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_shadow, F_OK) >= 0) return 0; print_welcome(); @@ -533,7 +533,7 @@ static int process_root_password(void) { int r; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); - if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_shadow, F_OK) >= 0) return 0; mkdir_parents(etc_shadow, 0755); -- cgit v1.2.3-54-g00ecf From 68b020494d1ff085281061413d9236b5865ef238 Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Wed, 9 Mar 2016 09:29:25 -0500 Subject: /dev/console must be labeled with SELinux label If the user specifies an selinux_apifs_context all content created in the container including /dev/console should use this label. Currently when this uses the default label it gets labeled user_devpts_t, which would require us to write a policy allowing container processes to manage user_devpts_t. This means that an escaped process would be allowed to attack all users terminals as well as other container terminals. Changing the label to match the apifs_context, means the processes would only be allowed to manage their specific tty. This change fixes a problem preventing RKT containers from working with systemd-nspawn. --- src/nspawn/nspawn.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 4851c439c9..be07625a03 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -87,6 +87,7 @@ #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "selinux-util.h" #include "signal-util.h" #include "socket-util.h" #include "stat-util.h" @@ -3284,6 +3285,12 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_selinux_apifs_context) { + r = mac_selinux_apply(console, arg_selinux_apifs_context); + if (r < 0) + goto finish; + } + if (unlockpt(master) < 0) { r = log_error_errno(errno, "Failed to unlock tty: %m"); goto finish; -- cgit v1.2.3-54-g00ecf From c83321e6d40b294e73e2881e4a98172c4244323b Mon Sep 17 00:00:00 2001 From: Vinay Kulkarni Date: Wed, 9 Mar 2016 21:58:44 -0800 Subject: DHCP DUID and IAID configurability --- Makefile-man.am | 7 ++ Makefile.am | 4 + man/networkd.conf.xml | 112 +++++++++++++++++++++++++ man/systemd.network.xml | 6 ++ src/libsystemd-network/dhcp-identifier.c | 2 +- src/libsystemd-network/dhcp-identifier.h | 41 ++++++++- src/libsystemd-network/dhcp6-protocol.h | 7 -- src/libsystemd-network/network-internal.c | 28 +++++++ src/libsystemd-network/network-internal.h | 4 + src/libsystemd-network/sd-dhcp-client.c | 48 ++++++++++- src/libsystemd-network/sd-dhcp6-client.c | 49 +++++------ src/network/networkd-conf.c | 133 ++++++++++++++++++++++++++++++ src/network/networkd-conf.h | 32 +++++++ src/network/networkd-dhcp4.c | 8 +- src/network/networkd-dhcp6.c | 10 +++ src/network/networkd-gperf.gperf | 18 ++++ src/network/networkd-link.c | 18 ++++ src/network/networkd-manager.c | 2 + src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.h | 2 + src/network/networkd.c | 5 ++ src/network/networkd.h | 5 ++ src/systemd/sd-dhcp-client.h | 4 + src/systemd/sd-dhcp6-client.h | 7 +- 24 files changed, 509 insertions(+), 44 deletions(-) create mode 100644 man/networkd.conf.xml create mode 100644 src/network/networkd-conf.c create mode 100644 src/network/networkd-conf.h create mode 100644 src/network/networkd-gperf.gperf (limited to 'src') diff --git a/Makefile-man.am b/Makefile-man.am index 3f03afc2ef..a7e348b1f1 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -1960,15 +1960,21 @@ endif if ENABLE_NETWORKD MANPAGES += \ man/networkctl.1 \ + man/networkd.conf.5 \ man/systemd-networkd-wait-online.service.8 \ man/systemd-networkd.service.8 \ man/systemd.netdev.5 \ man/systemd.network.5 MANPAGES_ALIAS += \ + man/networkd.conf.d.5 \ man/systemd-networkd-wait-online.8 \ man/systemd-networkd.8 +man/networkd.conf.d.5: man/networkd.conf.5 man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8 man/systemd-networkd.8: man/systemd-networkd.service.8 +man/networkd.conf.d.html: man/networkd.conf.html + $(html-alias) + man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html $(html-alias) @@ -2479,6 +2485,7 @@ EXTRA_DIST += \ man/machinectl.xml \ man/modules-load.d.xml \ man/networkctl.xml \ + man/networkd.conf.xml \ man/nss-myhostname.xml \ man/nss-mymachines.xml \ man/nss-resolve.xml \ diff --git a/Makefile.am b/Makefile.am index 04553d81b2..5f47a81762 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5306,6 +5306,8 @@ libnetworkd_core_la_CFLAGS = \ libnetworkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ + src/network/networkd-conf.h \ + src/network/networkd-conf.c \ src/network/networkd-link.h \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ @@ -5354,6 +5356,7 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ + src/network/networkd-gperf.c \ src/network/networkd-network-gperf.c \ src/network/networkd-netdev-gperf.c @@ -5450,6 +5453,7 @@ BUSNAMES_TARGET_WANTS += \ endif gperf_gperf_sources += \ + src/network/networkd-gperf.gperf \ src/network/networkd-network-gperf.gperf \ src/network/networkd-netdev-gperf.gperf diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml new file mode 100644 index 0000000000..5e2927ba54 --- /dev/null +++ b/man/networkd.conf.xml @@ -0,0 +1,112 @@ + + + + + + + + networkd.conf + systemd + + + + Developer + Vinay + Kulkarni + kulkarniv@vmware.com + + + + + + networkd.conf + 5 + + + + networkd.conf + networkd.conf.d + Global Network configuration files + + + + /etc/systemd/networkd.conf + /etc/systemd/networkd.conf.d/*.conf + /usr/lib/systemd/networkd.conf.d/*.conf + + + + Description + + These configuration files control global network parameters. + For e.g. DHCP Unique Identifier (DUID). + + + + + + + [DUID] Section Options + + This section configures the DUID value used by the DHCP protocol. The DUID value + specified here overrides the DUID that systemd-networkd generates using the machine-id + from the /etc/machine-id file. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. To configure IAID, see + systemd.network5 + . + + The following options are available in [DUID] section: + + + + + Type= + The type of DUID specified in this section. The following values are + supported: + raw : If Type=raw, then RawData= specifies + the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00". + + + + RawData= + Specifies the DUID bytes as a single newline-terminated, hexadecimal + string, with each byte separated by a ':'. + + + + + + + See Also + + systemd1, + systemd.network5, + machine-id1 + + + + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 752a15a4e0..c6bbb95833 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -204,6 +204,12 @@ understood to the base of 1024. + + IAIDValue= + + Identity Association Identifier for the interface. This is a 32-bit value specified in host byte order. + + diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1d9ec7be82..1bef368852 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP6_DUID_EN); + unaligned_write_be16(&duid->type, DHCP_DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 93f06f5938..cb953cb416 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,13 +25,23 @@ #include "sparse-endian.h" #include "unaligned.h" +typedef enum DHCPDUIDType { + DHCP_DUID_TYPE_RAW = 0, + DHCP_DUID_TYPE_LLT = 1, + DHCP_DUID_TYPE_EN = 2, + DHCP_DUID_TYPE_LL = 3, + DHCP_DUID_TYPE_UUID = 4, + _DHCP_DUID_TYPE_MAX, + _DHCP_DUID_TYPE_INVALID = -1, +} DHCPDUIDType; + /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - uint16_t type; + be16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -61,3 +71,32 @@ struct duid { 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, void *_id); + +static inline int dhcp_validate_duid_len(be16_t duid_type, size_t duid_len) { + struct duid d; + + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + + switch (be16toh(duid_type)) { + case DHCP_DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index ee4bdfb07f..2487c470ab 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,13 +62,6 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC -enum { - DHCP6_DUID_LLT = 1, - DHCP6_DUID_EN = 2, - DHCP6_DUID_LL = 3, - DHCP6_DUID_UUID = 4, -}; - enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index cb7252bbeb..7c21f42591 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,6 +335,34 @@ int config_parse_hwaddr(const char *unit, return 0; } +int config_parse_iaid_value(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) { + uint32_t iaid_value; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if ((r = safe_atou32(rvalue, &iaid_value)) < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); + return r; + } + + *((be32_t *)data) = htobe32(iaid_value); + + return 0; +} + void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index c8a531ab0f..d8b551e8ce 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,6 +62,10 @@ int config_parse_ifalias(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_iaid_value(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 net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 1188b31500..b108e35386 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - uint32_t iaid; + be32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -298,6 +298,51 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, + size_t duid_len, struct duid *duid) { + DHCP_CLIENT_DONT_DESTROY(client); + int r; + assert_return(client, -EINVAL); + zero(client->client_id); + + client->client_id.type = 255; + + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = iaid; + + /* If DUID is not configured, generate DUID-EN. */ + if (duid_len == 0) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, + &duid_len); + if (r < 0) + return r; + } else { + r = dhcp_validate_duid_len(client->client_id.type, + duid_len - sizeof(client->client_id.type)); + if (r < 0) + return r; + memcpy(&client->client_id.ns.duid, duid, duid_len); + } + + client->client_id_len = sizeof(client->client_id.type) + duid_len + + sizeof(client->client_id.ns.iaid); + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Configured IAID+DUID, restarting."); + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + sd_dhcp_client_start(client); + } + + return 0; +} + int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; @@ -469,7 +514,6 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, if (client->arp_type == ARPHRD_ETHER) memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); - /* If no client identifier exists, construct an RFC 4361-compliant one */ if (client->client_id_len == 0) { size_t duid_len; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index af4709d788..7cecba120c 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -180,41 +180,30 @@ static int client_ensure_duid(sd_dhcp6_client *client) { 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) { +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, + struct duid *duid) { + int r; assert_return(client, -EINVAL); - assert_return(duid, -EINVAL); - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - switch (type) { - case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt)) - return -EINVAL; - break; - case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en)) - return -EINVAL; - break; - case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll)) - return -EINVAL; - break; - case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; + if (duid_len > 0) { + r = dhcp_validate_duid_len(duid->type, + duid_len - sizeof(duid->type)); + if (r < 0) + return r; + + memcpy(&client->duid, duid, duid_len); + client->duid_len = duid_len; } - client->duid.type = htobe16(type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); + return 0; +} + +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid) { + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->ia_na.id = iaid; return 0; } diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c new file mode 100644 index 0000000000..4bc92b8171 --- /dev/null +++ b/src/network/networkd-conf.c @@ -0,0 +1,133 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + 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 . + ***/ + +#include + +#include "conf-parser.h" +#include "def.h" +#include "dhcp-identifier.h" +#include "networkd-conf.h" +#include "string-table.h" + +int manager_parse_config_file(Manager *m) { + assert(m); + + return config_parse_many(PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "DUID\0", + config_item_perf_lookup, networkd_gperf_lookup, + false, m); +} + +static const char* const dhcp_duid_type_table[_DHCP_DUID_TYPE_MAX] = { + [DHCP_DUID_TYPE_RAW] = "raw", + [DHCP_DUID_TYPE_LLT] = "link-layer-time", + [DHCP_DUID_TYPE_EN] = "vendor", + [DHCP_DUID_TYPE_LL] = "link-layer", + [DHCP_DUID_TYPE_UUID] = "uuid" +}; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_duid_type, DHCPDUIDType); +DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_duid_type, dhcp_duid_type, DHCPDUIDType, "Failed to parse DHCP DUID type"); + +int config_parse_dhcp_duid_raw( + 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 r; + long byte; + char *cbyte, *pnext; + const char *pduid = (const char *)rvalue; + size_t count = 0, duid_len = 0; + Manager *m = userdata; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(m); + assert(m->dhcp_duid_type != _DHCP_DUID_TYPE_INVALID); + + switch (m->dhcp_duid_type) { + case DHCP_DUID_TYPE_LLT: + /* RawData contains DUID-LLT link-layer address (offset 6) */ + duid_len = 6; + break; + case DHCP_DUID_TYPE_EN: + /* RawData contains DUID-EN identifier (offset 4) */ + duid_len = 4; + break; + case DHCP_DUID_TYPE_LL: + /* RawData contains DUID-LL link-layer address (offset 2) */ + duid_len = 2; + break; + case DHCP_DUID_TYPE_UUID: + /* RawData specifies UUID (offset 0) - fall thru */ + case DHCP_DUID_TYPE_RAW: + /* First two bytes of RawData is DUID Type - fall thru */ + default: + break; + } + + if (m->dhcp_duid_type != DHCP_DUID_TYPE_RAW) + m->dhcp_duid.type = htobe16(m->dhcp_duid_type); + + /* RawData contains DUID in format " NN:NN:NN... " */ + while (true) { + r = extract_first_word(&pduid, &cbyte, ":", 0); + if (r < 0) { + log_error("Failed to read DUID."); + return -EINVAL; + } + if (r == 0) + break; + if (duid_len >= MAX_DUID_LEN) { + log_error("DUID length exceeds maximum length."); + return -EINVAL; + } + + errno = 0; + byte = strtol(cbyte, &pnext, 16); + if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) + || (errno != 0 && byte == 0) || (cbyte == pnext)) { + log_error("Invalid DUID byte: %s.", cbyte); + return -EINVAL; + } + + /* If DHCP_DUID_TYPE_RAW, first two bytes holds DUID Type */ + if ((m->dhcp_duid_type == DHCP_DUID_TYPE_RAW) && (count < 2)) { + m->dhcp_duid.type |= (byte << (8 * count)); + count++; + continue; + } + + m->dhcp_duid.raw.data[duid_len++] = byte; + } + + m->dhcp_duid_len = sizeof(m->dhcp_duid.type) + duid_len; + + return 0; +} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h new file mode 100644 index 0000000000..6d9ce010e3 --- /dev/null +++ b/src/network/networkd-conf.h @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + 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 . +***/ + +#include "networkd.h" + + +int manager_parse_config_file(Manager *m); + +const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); + +int config_parse_dhcp_duid_type(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_duid_raw(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-dhcp4.c b/src/network/networkd-dhcp4.c index 68998eabf2..3bbb21295c 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -625,7 +625,13 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* Library defaults to this. */ + /* If configured, apply user specified DUID and/or IAID */ + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid_value, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return r; break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 5f7a005c36..9f59cb3f8a 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,6 +230,16 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; + r = sd_dhcp6_client_set_iaid(client, link->network->iaid_value); + if (r < 0) + goto error; + + r = sd_dhcp6_client_set_duid(client, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + goto error; + r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf new file mode 100644 index 0000000000..3ef4155476 --- /dev/null +++ b/src/network/networkd-gperf.gperf @@ -0,0 +1,18 @@ +%{ +#include +#include "conf-parser.h" +#include "networkd-conf.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name networkd_gperf_hash +%define lookup-function-name networkd_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +DUID.Type, config_parse_dhcp_duid_type, 0, offsetof(Manager, dhcp_duid_type) +DUID.RawData, config_parse_dhcp_duid_raw, 0, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ff4bd76554..67b04560cd 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2781,6 +2781,13 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); + + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid_value, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2790,6 +2797,17 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); + + r = sd_dhcp6_client_set_iaid(link->dhcp6_client, + link->network->iaid_value); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); + + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b8cb7f875d..8d443f7b0f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,6 +1037,8 @@ int manager_new(Manager **ret) { if (r < 0) return r; + m->dhcp_duid_type = _DHCP_DUID_TYPE_INVALID; + *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a5d1714293..7a9a136d5b 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -26,6 +26,7 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Link.IAIDValue, config_parse_iaid_value, 0, offsetof(Network, iaid_value) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 4a13e2b574..c5530cdfba 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -30,6 +30,7 @@ typedef struct Network Network; #include "networkd-route.h" #include "networkd-util.h" #include "networkd.h" +#include "sparse-endian.h" #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 @@ -144,6 +145,7 @@ struct Network { struct ether_addr *mac; unsigned mtu; + be32_t iaid_value; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.c b/src/network/networkd.c index 3a2615e6fd..c8f81a2ca6 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,6 +21,7 @@ #include "capability-util.h" #include "networkd.h" +#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -89,6 +90,10 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_parse_config_file(m); + if (r < 0) + log_warning_errno(r, "Failed to parse configuration file: %m"); + r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index 6bdd8302a0..d815f30610 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -35,6 +35,7 @@ typedef struct Manager Manager; #include "networkd-link.h" #include "networkd-network.h" #include "networkd-util.h" +#include "dhcp-identifier.h" struct Manager { sd_netlink *rtnl; @@ -61,6 +62,10 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; + + DHCPDUIDType dhcp_duid_type; + size_t dhcp_duid_len; + struct duid dhcp_duid; }; extern const char* const network_dirs[]; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index ef45370505..7873cb1e04 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -27,6 +27,7 @@ #include "sd-dhcp-lease.h" #include "sd-event.h" +#include "sparse-endian.h" #include "_sd-common.h" @@ -82,6 +83,7 @@ enum { SD_DHCP_OPTION_END = 255, }; +struct duid; typedef struct sd_dhcp_client sd_dhcp_client; typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, @@ -98,6 +100,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, + size_t duid_len, struct duid *duid); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 1bedc941aa..ebdd017628 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -26,6 +26,7 @@ #include "sd-dhcp6-lease.h" #include "sd-event.h" +#include "sparse-endian.h" #include "_sd-common.h" @@ -74,6 +75,7 @@ enum { /* option codes 144-65535 are unassigned */ }; +struct duid; typedef struct sd_dhcp6_client sd_dhcp6_client; typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, @@ -85,8 +87,9 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, + struct duid *duid); +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, -- cgit v1.2.3-54-g00ecf From a0c9496cc826957fe0f3926f619e073f17a9ab4d Mon Sep 17 00:00:00 2001 From: Petr Lautrbach Date: Thu, 10 Mar 2016 10:19:56 +0100 Subject: socket_address_listen - do not rely on errno Currently socket_address_listen() calls mac_selinux_bind() to bind a UNIX socket and checks its return value and errno for EADDRINUSE. This is not correct. When there's an SELinux context change made for the new socket, bind() is not the last function called in mac_selinux_bind(). In that case the last call is setfscreatecon() from libselinux which can change errno as it uses access() to check if /proc/thread-self is available. It fails on kernels before 3.17 and errno is set to ENOENT. It's safe to check only the return value at it's set to -errno. --- src/basic/socket-label.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 35e9573aa4..65509be901 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -122,7 +122,7 @@ int socket_address_listen( r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); - if (r < 0 && errno == EADDRINUSE) { + if (r == -EADDRINUSE) { /* Unlink and try again */ unlink(a->sockaddr.un.sun_path); r = bind(fd, &a->sockaddr.sa, a->size); -- cgit v1.2.3-54-g00ecf From 7322824832e9a3527ea1316601eb06a54c013300 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Thu, 10 Mar 2016 12:43:00 +0100 Subject: test-ipcrm: fix log message --- src/test/test-ipcrm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 47b1c4443d..c5bcaf47bb 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -28,7 +28,7 @@ int main(int argc, char *argv[]) { r = get_user_creds(&name, &uid, NULL, NULL, NULL); if (r < 0) { - log_error("Failed to resolve \"nobody\": %m"); + log_error_errno(r, "Failed to resolve \"%s\": %m", name); return EXIT_FAILURE; } -- cgit v1.2.3-54-g00ecf From 825546ef761c829b7a22ccdb33981d3d4d23c2b9 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 10 Mar 2016 09:24:08 -0500 Subject: socket_address_listen: do not rely on errno (2) We'd still use the invalid errno for a return value. Rework the code to simply return the right error right away. --- src/basic/socket-label.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 65509be901..6d1dc83874 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -35,6 +34,7 @@ #include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" +#include "umask-util.h" int socket_address_listen( const SocketAddress *a, @@ -112,28 +112,24 @@ int socket_address_listen( return -errno; if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { - mode_t old_mask; - /* Create parents */ - mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); + (void) mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); /* Enforce the right access mode for the socket */ - old_mask = umask(~ socket_mode); - - r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); - - if (r == -EADDRINUSE) { - /* Unlink and try again */ - unlink(a->sockaddr.un.sun_path); - r = bind(fd, &a->sockaddr.sa, a->size); + RUN_WITH_UMASK(~socket_mode) { + r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); + if (r == -EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + if (bind(fd, &a->sockaddr.sa, a->size) < 0) + return -errno; + } else if (r < 0) + return r; } - - umask(old_mask); - } else - r = bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0) - return -errno; + } else { + if (bind(fd, &a->sockaddr.sa, a->size) < 0) + return -errno; + } if (socket_address_can_accept(a)) if (listen(fd, backlog) < 0) -- cgit v1.2.3-54-g00ecf From 0cb27225e9c658d80538ace7a267ba0a2d2f44f2 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 11 Mar 2016 13:41:49 -0500 Subject: headers: use __inline__ instead of inline https://gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/Alternate-Keywords.html#Alternate-Keywords recommends __inline__ over inline in ANSI C compatible headers. Tested with gcc-5.3 and clang-3.7. https://bugzilla.redhat.com/show_bug.cgi?id=1316964 --- src/systemd/_sd-common.h | 2 +- src/systemd/sd-id128.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index 2d4e1f26e1..3bb886be75 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -74,7 +74,7 @@ #endif #define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \ - static inline void func##p(type **p) { \ + static __inline__ void func##p(type **p) { \ if (*p) \ func(*p); \ } \ diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index a3bf5897b8..4dff0b9b81 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -100,11 +100,11 @@ int sd_id128_get_boot(sd_id128_t *ret); ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ 0 }) -_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) { +_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) { +_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) { return a.qwords[0] == 0 && a.qwords[1] == 0; } -- cgit v1.2.3-54-g00ecf From b2542bf9ab6cce97fcb67ff9536e1062c70b5b11 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 11 Mar 2016 13:46:12 -0500 Subject: headers: do not use siginfo_t if not defined Simply avoid the trouble and use a void* if the define is missing. We lose type safety, but who cares. sigaction(2) says that siginfo_t requires _POSIX_C_SOURCE >= 199309L, but we can be a bit more generous and use the same define as /usr/include/signal.h. --- src/systemd/sd-event.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 1ea97e47f8..9ded022624 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -69,7 +69,11 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); +#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); +#else +typedef void* sd_event_child_handler_t; +#endif int sd_event_default(sd_event **e); -- cgit v1.2.3-54-g00ecf From e0c0b07da191f152db116ba38c352b21004f1c93 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 11 Mar 2016 13:50:56 -0500 Subject: headers: remove commas at end of enum lists src/systemd/sd-journal.h:75:51: warning: commas at the end of enumerator lists are a C99-specific feature [-Wc99-extensions] --- src/systemd/sd-bus-protocol.h | 2 +- src/systemd/sd-bus-vtable.h | 2 +- src/systemd/sd-bus.h | 4 ++-- src/systemd/sd-event.h | 2 +- src/systemd/sd-journal.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/systemd/sd-bus-protocol.h b/src/systemd/sd-bus-protocol.h index 47b256d5b9..623cee0c50 100644 --- a/src/systemd/sd-bus-protocol.h +++ b/src/systemd/sd-bus-protocol.h @@ -59,7 +59,7 @@ enum { SD_BUS_TYPE_STRUCT_END = ')', SD_BUS_TYPE_DICT_ENTRY = 'e', /* not actually used in signatures */ SD_BUS_TYPE_DICT_ENTRY_BEGIN = '{', - SD_BUS_TYPE_DICT_ENTRY_END = '}', + SD_BUS_TYPE_DICT_ENTRY_END = '}' }; /* Well-known errors. Note that this is only a sanitized subset of the diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h index 6ad6d51979..e8f84eb545 100644 --- a/src/systemd/sd-bus-vtable.h +++ b/src/systemd/sd-bus-vtable.h @@ -34,7 +34,7 @@ enum { _SD_BUS_VTABLE_METHOD = 'M', _SD_BUS_VTABLE_SIGNAL = 'S', _SD_BUS_VTABLE_PROPERTY = 'P', - _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W', + _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W' }; enum { diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 2a2ef0eb98..295989cd69 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -89,13 +89,13 @@ enum { 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 << 34) -1, + _SD_BUS_CREDS_ALL = (1ULL << 34) -1 }; enum { SD_BUS_NAME_REPLACE_EXISTING = 1ULL << 0, SD_BUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, - SD_BUS_NAME_QUEUE = 1ULL << 2, + SD_BUS_NAME_QUEUE = 1ULL << 2 }; /* Callbacks */ diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 9ded022624..531ace1c34 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -55,7 +55,7 @@ enum { SD_EVENT_RUNNING, SD_EVENT_EXITING, SD_EVENT_FINISHED, - SD_EVENT_PREPARING, + SD_EVENT_PREPARING }; enum { diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index abb9eca576..d4c6f409cd 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -72,7 +72,7 @@ enum { SD_JOURNAL_SYSTEM = 4, SD_JOURNAL_CURRENT_USER = 8, - SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM, /* deprecated name */ + SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */ }; /* Wakeup event types */ -- cgit v1.2.3-54-g00ecf From b61a09a5227747db8b8a55b3949b38066fd1a0b7 Mon Sep 17 00:00:00 2001 From: Wieland Hoffmann Date: Sat, 12 Mar 2016 11:50:34 +0100 Subject: run: Improve the help message about timer options and existing units --- src/run/run.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/run/run.c b/src/run/run.c index e7f4c21f73..1ed1bd96bf 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -83,8 +83,8 @@ static void polkit_agent_open_if_enabled(void) { static void help(void) { printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n" "Run the specified command in a transient scope or service or timer\n" - "unit. If timer option is specified and unit is exist which is\n" - "specified with --unit option then command can be omitted.\n\n" + "unit. If a timer option is specified and the unit specified with\n" + "the --unit option exists, the command can be omitted.\n\n" " -h --help Show this help\n" " --version Show package version\n" " --no-ask-password Do not prompt for password\n" -- cgit v1.2.3-54-g00ecf From c3b0e5ac57f30226cf258d1a555da6c2863d4a45 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sun, 13 Mar 2016 23:51:37 +0000 Subject: shared/machine-pool: fix mkfs.btrfs checking binary_is_good translates ENOENT to 0 See https://github.com/systemd/systemd/commit/85eca92e#diff-bcad68c477b6651521e880c40b7a9b40R813 --- src/shared/machine-pool.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index f080b849a4..e0bad035b6 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -239,10 +239,8 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { } r = mkfs_exists("btrfs"); - if (r == -ENOENT) { - log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines."); - return 0; - } + if (r == 0) + return sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing"); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 579afbea21f6439e97c141160ed1f7dd740eab0d Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 14 Mar 2016 00:54:35 +0000 Subject: shared/machine-pool: fix another mkfs.btrfs checking Fixes: Message: Process 806 (systemd-importd) of user 0 dumped core. Stack trace of thread 806: #0 0x00007f5eaeff7227 raise (libc.so.6) #1 0x00007f5eaeff8e8a abort (libc.so.6) #2 0x000055b6d3418f4f log_assert_failed (systemd-importd) #3 0x000055b6d3409daf safe_close (systemd-importd) #4 0x000055b6d33c25ea closep (systemd-importd) #5 0x000055b6d33c38d9 setup_machine_directory (systemd-importd) #6 0x000055b6d33b8536 method_pull_tar_or_raw (systemd-importd) #7 0x000055b6d33ed097 method_callbacks_run (systemd-importd) #8 0x000055b6d33ef929 object_find_and_run (systemd-importd) #9 0x000055b6d33eff6b bus_process_object (systemd-importd) #10 0x000055b6d3447f77 process_message (systemd-importd) #11 0x000055b6d344815a process_running (systemd-importd) #12 0x000055b6d3448a10 bus_process_internal (systemd-importd) #13 0x000055b6d3448ae1 sd_bus_process (systemd-importd) #14 0x000055b6d3449779 time_callback (systemd-importd) #15 0x000055b6d3454ff4 source_dispatch (systemd-importd) #16 0x000055b6d34562b9 sd_event_dispatch (systemd-importd) #17 0x000055b6d34566f8 sd_event_run (systemd-importd) #18 0x000055b6d33ba72a bus_event_loop_with_idle (systemd-importd) #19 0x000055b6d33b95bc manager_run (systemd-importd) #20 0x000055b6d33b9766 main (systemd-importd) #21 0x00007f5eaefe2a00 __libc_start_main (libc.so.6) #22 0x000055b6d33b5569 _start (systemd-importd) --- src/shared/machine-pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index e0bad035b6..23890c63a0 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -139,7 +139,7 @@ static int setup_machine_raw(uint64_t size, sd_bus_error *error) { execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL); if (errno == ENOENT) - return 99; + _exit(99); _exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From 5e1558f4a09e596561c9168384f2258e7c0718a1 Mon Sep 17 00:00:00 2001 From: Colin Guthrie Date: Mon, 14 Mar 2016 09:42:07 +0000 Subject: device: Ensure we have sysfs path before comparing. In some cases we do not have a udev device when setting up a unit (certainly the code gracefully handles this). However, we do then go on to compare the path via path_equal which will assert if a null value is passed in. See https://bugs.mageia.org/show_bug.cgi?id=17766 Not sure if this is the correct fix, but it avoids the crash --- src/core/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/device.c b/src/core/device.c index d201dc5e4b..c64e01c2aa 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -318,7 +318,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa * the GC to have garbaged it. That's desired since the device * unit may have a dependency on the mount unit which was * added during the loading of the later. */ - if (u && DEVICE(u)->state == DEVICE_PLUGGED) { + if (sysfs && u && DEVICE(u)->state == DEVICE_PLUGGED) { /* This unit is in plugged state: we're sure it's * attached to a device. */ if (!path_equal(DEVICE(u)->sysfs, sysfs)) { -- cgit v1.2.3-54-g00ecf From 0513ea4e3fc42c2d495ae47d83815ce09d2274b2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 11 Mar 2016 16:18:13 +0100 Subject: lldp: fix starting ttl timer for lldp neighbor lldp_start_timer() was only called during sd_lldp_get_neighbors(). Ensure that the timer is (re-)started when a new neighbor appears. Otherwise, the timer is not started when relying on the events alone. Fixes: 34437b4f9c9c51b0a6f93788bdb9a105b8e46b66 --- src/libsystemd-network/sd-lldp.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index d0743cf3e2..9d4587c80e 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -112,6 +112,8 @@ static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { return true; } +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor); + static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL; bool keep; @@ -136,7 +138,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { if (lldp_neighbor_equal(n, old)) { /* Is this equal, then restart the TTL counter, but don't do anyting else. */ - lldp_neighbor_start_ttl(old); + lldp_start_timer(lldp, old); lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); return 0; } @@ -162,7 +164,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { n->lldp = lldp; - lldp_neighbor_start_ttl(n); + lldp_start_timer(lldp, n); lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n); return 1; @@ -368,8 +370,6 @@ static int neighbor_compare_func(const void *a, const void *b) { return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); } -static int lldp_start_timer(sd_lldp *lldp); - static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { sd_lldp *lldp = userdata; int r, q; @@ -378,19 +378,22 @@ static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { if (r < 0) return log_lldp_errno(r, "Failed to make space: %m"); - q = lldp_start_timer(lldp); + q = lldp_start_timer(lldp, NULL); if (q < 0) return log_lldp_errno(q, "Failed to restart timer: %m"); return 0; } -static int lldp_start_timer(sd_lldp *lldp) { +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { sd_lldp_neighbor *n; int r; assert(lldp); + if (neighbor) + lldp_neighbor_start_ttl(neighbor); + n = prioq_peek(lldp->neighbor_by_expiry); if (!n) { @@ -440,7 +443,7 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { if (!l) return -ENOMEM; - r = lldp_start_timer(lldp); + r = lldp_start_timer(lldp, NULL); if (r < 0) { free(l); return r; -- cgit v1.2.3-54-g00ecf From 27d13af71c3af6b2f9b60556d2c046dbb6e36e23 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 14 Mar 2016 17:44:49 -0400 Subject: include sys/sysmacros.h in more places Since glibc is moving away from implicitly including sys/sysmacros.h all the time via sys/types.h, include the header directly in more places. This seems to cover most makedev/major/minor usage. --- src/basic/macro.h | 1 + src/basic/util.h | 1 + src/libudev/libudev.h | 1 + src/systemd/sd-device.h | 1 + src/udev/udev.h | 1 + 5 files changed, 5 insertions(+) (limited to 'src') diff --git a/src/basic/macro.h b/src/basic/macro.h index c34441d75d..b36a95675a 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #define _printf_(a,b) __attribute__ ((format (printf, a, b))) diff --git a/src/basic/util.h b/src/basic/util.h index e095254b57..286db05159 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h index eb58740d26..3f6d0ed16c 100644 --- a/src/libudev/libudev.h +++ b/src/libudev/libudev.h @@ -21,6 +21,7 @@ #define _LIBUDEV_H_ #include +#include #include #ifdef __cplusplus diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 5bfca6ecec..c1d07561d7 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -22,6 +22,7 @@ ***/ #include +#include #include #include "_sd-common.h" diff --git a/src/udev/udev.h b/src/udev/udev.h index 56590517ef..8433e8d9f2 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -19,6 +19,7 @@ */ #include +#include #include #include "libudev.h" -- cgit v1.2.3-54-g00ecf From b6b0cfaafd5dd9685e636c9b46346ee8de68d68c Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 15 Mar 2016 01:00:34 +0000 Subject: sd-path: use XDG_CONFIG_HOME instead of hardcoding ~/.config for user-dirs --- src/libsystemd/sd-path/sd-path.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c index 480f1ad065..b7aec1f20a 100644 --- a/src/libsystemd/sd-path/sd-path.c +++ b/src/libsystemd/sd-path/sd-path.c @@ -89,7 +89,8 @@ static int from_home_dir(const char *envname, const char *suffix, char **buffer, static int from_user_dir(const char *field, char **buffer, const char **ret) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *b = NULL; - const char *fn = NULL; + _cleanup_free_ const char *fn = NULL; + const char *c = NULL; char line[LINE_MAX]; size_t n; int r; @@ -98,10 +99,14 @@ static int from_user_dir(const char *field, char **buffer, const char **ret) { assert(buffer); assert(ret); - r = from_home_dir(NULL, ".config/user-dirs.dirs", &b, &fn); + r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c); if (r < 0) return r; + fn = strappend(c, "/user-dirs.dirs"); + if (!fn) + return -ENOMEM; + f = fopen(fn, "re"); if (!f) { if (errno == ENOENT) -- cgit v1.2.3-54-g00ecf From 2abd5b5a49ae368b258ffc7257ab703bccda67dd Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 15 Mar 2016 12:43:33 +0100 Subject: time-util: fall back to CLOCK_MONOTONIC if CLOCK_BOOTTIME unsupported It was added in 2.6.39, and causes an assertion to fail when running in mock hosted on 2.6.23-based RHEL-6: Assertion 'clock_gettime(map_clock_id(clock_id), &ts) == 0' failed at systemd/src/basic/time-util.c:70, function now(). Aborting. --- src/basic/time-util.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 7ca764abeb..c16460a198 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -47,12 +47,15 @@ static clockid_t map_clock_id(clockid_t c) { /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on - * those archs. */ + * those archs. + * + * Also, older kernels don't support CLOCK_BOOTTIME: fall back to CLOCK_MONOTONIC. */ switch (c) { + case CLOCK_BOOTTIME: case CLOCK_BOOTTIME_ALARM: - return CLOCK_BOOTTIME; + return clock_boottime_or_monotonic (); case CLOCK_REALTIME_ALARM: return CLOCK_REALTIME; -- cgit v1.2.3-54-g00ecf From ce33fddad0806f859ff7324527ee0525dd10455e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 14 Mar 2016 13:18:14 -0400 Subject: test-copy: add a test shuffling bytes between normal files I started looking into adding copy_file_range support, and discovered that we can improve the way we call sendfile: - sendfile(2) man page is missing an important bit: the number of bytes to copy cannot be too big (SSIZE_MAX actually), and the description of EINVAL return code does not mention this either, - our implementation works but calls sendfile over and over with a small size, which seems suboptimal. First add a test which (under strace) can be used to see current behaviour. --- src/test/test-copy.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'src') diff --git a/src/test/test-copy.c b/src/test/test-copy.c index ad57cb0202..622fba777d 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -24,6 +24,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "log.h" #include "macro.h" #include "mkdir.h" #include "path-util.h" @@ -39,6 +40,8 @@ static void test_copy_file(void) { size_t sz = 0; int fd; + log_info("%s", __func__); + fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); close(fd); @@ -66,6 +69,8 @@ static void test_copy_file_fd(void) { char text[] = "boohoo\nfoo\n\tbar\n"; char buf[64] = {0}; + log_info("%s", __func__); + in_fd = mkostemp_safe(in_fn, O_RDWR); assert_se(in_fd >= 0); out_fd = mkostemp_safe(out_fn, O_RDWR); @@ -91,6 +96,8 @@ static void test_copy_tree(void) { "link2", "dir1/file"); char **p, **link; + log_info("%s", __func__); + (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); @@ -173,11 +180,50 @@ static void test_copy_bytes(void) { assert_se(r == -EBADF); } +static void test_copy_bytes_regular_file(const char *src, bool try_reflink) { + char fn2[] = "/tmp/test-copy-file-XXXXXX"; + char fn3[] = "/tmp/test-copy-file-XXXXXX"; + _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; + int r; + struct stat buf, buf2, buf3; + + log_info("%s try_reflink=%s", __func__, yes_no(try_reflink)); + + fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY); + assert_se(fd >= 0); + + fd2 = mkostemp_safe(fn2, O_RDWR); + assert_se(fd2 >= 0); + + fd3 = mkostemp_safe(fn3, O_WRONLY); + assert_se(fd3 >= 0); + + r = copy_bytes(fd, fd2, (uint64_t) -1, try_reflink); + assert_se(r == 0); + + assert_se(lseek(fd2, 0, SEEK_SET) == 0); + + r = copy_bytes(fd2, fd3, (uint64_t) -1, try_reflink); + assert_se(r == 0); + + assert_se(fstat(fd, &buf) == 0); + assert_se(fstat(fd2, &buf2) == 0); + assert_se(fstat(fd3, &buf3) == 0); + + assert_se(buf.st_size == buf2.st_size); + assert_se(buf.st_size == buf3.st_size); + + unlink(fn2); + unlink(fn3); +} + int main(int argc, char *argv[]) { test_copy_file(); test_copy_file_fd(); test_copy_tree(); test_copy_bytes(); + test_copy_bytes_regular_file(argv[0], false); + test_copy_bytes_regular_file(argv[0], true); return 0; } -- cgit v1.2.3-54-g00ecf From 00a8cf7763ec5e132efd4c974fbc6530c82240d0 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 14 Mar 2016 20:15:21 -0400 Subject: basic/copy: use sendfile smarter We called sendfile with 16kb (a.k.a. COPY_BUFFER_SIZE) as the maximum number of bytes to copy. This seems rather inefficient, especially with large files. Instead, call sendfile with a "large" maximum. What "large" max means is a bit tricky: current file offset + max must fit in loff_t. This means that as we call sendfile more than once, we have to lower the max size. With this patch, test-copy calls sendfile twice, e.g.: sendfile(4, 3, NULL, 9223372036854775807) = 738760 sendfile(4, 3, NULL, 9223372036854037047) = 0 The second call is necessary to determine EOF. --- src/basic/copy.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index 519b412941..dbbb1d0fd2 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -46,11 +46,12 @@ #include "umask-util.h" #include "xattr-util.h" -#define COPY_BUFFER_SIZE (16*1024) +#define COPY_BUFFER_SIZE (16*1024u) int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { bool try_sendfile = true, try_splice = true; int r; + size_t m = SSIZE_MAX; /* that the maximum that sendfile accepts */ assert(fdf >= 0); assert(fdt >= 0); @@ -67,11 +68,9 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { } for (;;) { - size_t m = COPY_BUFFER_SIZE; ssize_t n; if (max_bytes != (uint64_t) -1) { - if (max_bytes <= 0) return 1; /* return > 0 if we hit the max_bytes limit */ @@ -81,42 +80,41 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { /* First try sendfile(), unless we already tried */ if (try_sendfile) { - n = sendfile(fdt, fdf, NULL, m); if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) + if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; try_sendfile = false; /* use fallback below */ } else if (n == 0) /* EOF */ break; - else if (n > 0) + else /* Success! */ goto next; } - /* The try splice, unless we already tried */ + /* Then try splice, unless we already tried */ if (try_splice) { n = splice(fdf, NULL, fdt, NULL, m, 0); if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) + if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; try_splice = false; /* use fallback below */ } else if (n == 0) /* EOF */ break; - else if (n > 0) + else /* Success! */ goto next; } /* As a fallback just copy bits by hand */ { - uint8_t buf[m]; + uint8_t buf[MIN(m, COPY_BUFFER_SIZE)]; - n = read(fdf, buf, m); + n = read(fdf, buf, sizeof buf); if (n < 0) return -errno; if (n == 0) /* EOF */ @@ -132,6 +130,11 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { assert(max_bytes >= (uint64_t) n); max_bytes -= n; } + /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, + * so reduce our maximum by the amount we already copied, + * but don't go below our copy buffer size, unless we are + * close the the limit of bytes we are allowed to copy. */ + m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); } return 0; /* return 0 if we hit EOF earlier than the size limit */ -- cgit v1.2.3-54-g00ecf From 7a827fcb115b6e03e351599db76f247e199d6351 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 15 Mar 2016 13:55:50 -0400 Subject: test-copy: test with different max_bytes values --- src/test/test-copy.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 622fba777d..1462affbcf 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -180,14 +180,14 @@ static void test_copy_bytes(void) { assert_se(r == -EBADF); } -static void test_copy_bytes_regular_file(const char *src, bool try_reflink) { +static void test_copy_bytes_regular_file(const char *src, bool try_reflink, size_t max_bytes) { char fn2[] = "/tmp/test-copy-file-XXXXXX"; char fn3[] = "/tmp/test-copy-file-XXXXXX"; _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; int r; struct stat buf, buf2, buf3; - log_info("%s try_reflink=%s", __func__, yes_no(try_reflink)); + log_info("%s try_reflink=%s max_bytes=%zu", __func__, yes_no(try_reflink), max_bytes); fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY); assert_se(fd >= 0); @@ -198,20 +198,31 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink) { fd3 = mkostemp_safe(fn3, O_WRONLY); assert_se(fd3 >= 0); - r = copy_bytes(fd, fd2, (uint64_t) -1, try_reflink); - assert_se(r == 0); + r = copy_bytes(fd, fd2, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + assert_se(IN_SET(r, 0, 1)); assert_se(lseek(fd2, 0, SEEK_SET) == 0); - r = copy_bytes(fd2, fd3, (uint64_t) -1, try_reflink); - assert_se(r == 0); + r = copy_bytes(fd2, fd3, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + /* We cannot distinguish between the input being exactly max_bytes + * or longer than max_bytes (without trying to read one more byte, + * or calling stat, or FION_READ, etc, and we don't want to do any + * of that). So we expect "truncation" since we know that file we + * are copying is exactly max_bytes bytes. */ + assert_se(r == 1); assert_se(fstat(fd, &buf) == 0); assert_se(fstat(fd2, &buf2) == 0); assert_se(fstat(fd3, &buf3) == 0); - assert_se(buf.st_size == buf2.st_size); - assert_se(buf.st_size == buf3.st_size); + assert_se((size_t) buf2.st_size == MIN((size_t) buf.st_size, max_bytes)); + assert_se(buf3.st_size == buf2.st_size); unlink(fn2); unlink(fn3); @@ -222,8 +233,12 @@ int main(int argc, char *argv[]) { test_copy_file_fd(); test_copy_tree(); test_copy_bytes(); - test_copy_bytes_regular_file(argv[0], false); - test_copy_bytes_regular_file(argv[0], true); + test_copy_bytes_regular_file(argv[0], false, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], true, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], false, 1000); /* smaller than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 1000); + test_copy_bytes_regular_file(argv[0], false, 32000); /* larger than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 32000); return 0; } -- cgit v1.2.3-54-g00ecf From 26e9e10b39fdf343dcb7e11b6cb4eecf11a45970 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 15 Mar 2016 19:27:28 -0400 Subject: basic/macros: clang 3.5 doesn't support alloc_size The attribute was removed in commit c047507 in the clang repository as it was never properly implemented anyway. Avoid using the attribute with clang because it generates a ton of annoying warnings. --- src/basic/macro.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/macro.h b/src/basic/macro.h index c34441d75d..279d3f3f08 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -26,7 +26,11 @@ #include #define _printf_(a,b) __attribute__ ((format (printf, a, b))) -#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#ifdef __clang__ +# define _alloc_(...) +#else +# define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#endif #define _sentinel_ __attribute__ ((sentinel)) #define _unused_ __attribute__ ((unused)) #define _destructor_ __attribute__ ((destructor)) -- cgit v1.2.3-54-g00ecf From d2d23cf240a207d4b719c46e71dd869836a02c0e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 15 Mar 2016 19:27:34 -0400 Subject: basic/c-rbtree: remove unused function --- src/basic/c-rbtree.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src') diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c index 914d7e5229..cf5a7242df 100644 --- a/src/basic/c-rbtree.c +++ b/src/basic/c-rbtree.c @@ -195,11 +195,6 @@ static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigne n->__parent_and_color = (CRBNode*)((unsigned long)p | c); } -/* same as c_rbnode_set_parent_and_color(), but keeps the current parent */ -static inline void c_rbnode_set_color(CRBNode *n, unsigned long c) { - c_rbnode_set_parent_and_color(n, c_rbnode_parent(n), c); -} - /* same as c_rbnode_set_parent_and_color(), but keeps the current color */ static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) { c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n)); -- cgit v1.2.3-54-g00ecf From c337642992892219479704460a8d7042d66ce1e7 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 15 Mar 2016 19:27:36 -0400 Subject: basic/log: remove unused return value --- src/basic/log.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/basic/log.h b/src/basic/log.h index f9fb1742a1..b6356228d9 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -246,5 +246,4 @@ int log_syntax_internal( log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ } \ - -EINVAL; \ }) -- cgit v1.2.3-54-g00ecf From 998fdc16aa3fd461ed932214e2e50c74d2f81040 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 16 Mar 2016 14:34:00 +0100 Subject: nspawn: Fix two misspellings of "hierarchy" in error messages --- src/nspawn/nspawn-cgroup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index 1db5ba7116..9f9a4759d1 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -73,7 +73,7 @@ int sync_cgroup(pid_t pid, bool unified_requested) { unified = cg_unified(); if (unified < 0) - return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m"); + return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m"); if ((unified > 0) == unified_requested) return 0; @@ -135,7 +135,7 @@ int create_subcgroup(pid_t pid, bool unified_requested) { unified = cg_unified(); if (unified < 0) - return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m"); + return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m"); if (unified == 0) return 0; -- cgit v1.2.3-54-g00ecf From 7aad67e7f2b3dfbc3b5a884471bd551e4bf997cc Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Wed, 16 Mar 2016 14:52:44 +0100 Subject: core: look for instance when processing template name If first attempt to merge units failed and we are trying to do merge the other way around and at the same time we are working with template name, then other unit can't possibly be template, because it is not possible to have template unit running, only instances of the template. Thus we need to look for already active instance instead. --- src/core/load-fragment.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index e1bfdccbca..d078924c5b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3507,7 +3507,19 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { * ours? Then let's try it the other way * round */ - other = manager_get_unit((*u)->manager, k); + /* If the symlink name we are looking at is unit template, then + we must search for instance of this template */ + if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE)) { + _cleanup_free_ char *instance = NULL; + + r = unit_name_replace_instance(k, (*u)->instance, &instance); + if (r < 0) + return r; + + other = manager_get_unit((*u)->manager, instance); + } else + other = manager_get_unit((*u)->manager, k); + free(k); if (other) { -- cgit v1.2.3-54-g00ecf From 483d8bbb4c0190f419bf9fba57fb0feb1a56bea6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 17 Mar 2016 08:40:39 -0400 Subject: rules: allow users to access frame buffer devices For example it allows weston to be started unprivileged. Related discussion: https://bugs.freedesktop.org/show_bug.cgi?id=73782 https://lists.freedesktop.org/archives/wayland-devel/2015-May/022005.html https://bugzilla.redhat.com/show_bug.cgi?id=1226680 --- src/login/70-uaccess.rules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules index 694df2cfc8..ff3e68e961 100644 --- a/src/login/70-uaccess.rules +++ b/src/login/70-uaccess.rules @@ -42,8 +42,9 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" -# DRI video devices +# DRI and frame buffer video devices SUBSYSTEM=="drm", KERNEL=="card*|renderD*", TAG+="uaccess" +SUBSYSTEM=="graphics", KERNEL=="fb*", TAG+="uaccess" # KVM SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" -- cgit v1.2.3-54-g00ecf From dc9b58166ca062583bcc8145ab3df79b2b39b9ae Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 16 Mar 2016 09:27:37 -0400 Subject: systemd: obey systemd.log_color config Fixes #2845. --- src/core/job.c | 26 +++++++++++++++++--------- src/core/main.c | 13 +++++++++---- src/core/transaction.c | 9 ++++++++- 3 files changed, 34 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/core/job.c b/src/core/job.c index 012cf72d1f..719cb0a3e5 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -690,17 +690,20 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR } static void job_print_status_message(Unit *u, JobType t, JobResult result) { - static const char* const job_result_status_table[_JOB_RESULT_MAX] = { - [JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL, - [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL, - [JOB_FAILED] = ANSI_HIGHLIGHT_RED "FAILED" ANSI_NORMAL, - [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW "DEPEND" ANSI_NORMAL, - [JOB_SKIPPED] = ANSI_HIGHLIGHT " INFO " ANSI_NORMAL, - [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW "ASSERT" ANSI_NORMAL, - [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL, + static struct { + const char *color, *word; + } const statuses[_JOB_RESULT_MAX] = { + [JOB_DONE] = {ANSI_GREEN, " OK "}, + [JOB_TIMEOUT] = {ANSI_HIGHLIGHT_RED, " TIME "}, + [JOB_FAILED] = {ANSI_HIGHLIGHT_RED, "FAILED"}, + [JOB_DEPENDENCY] = {ANSI_HIGHLIGHT_YELLOW, "DEPEND"}, + [JOB_SKIPPED] = {ANSI_HIGHLIGHT, " INFO "}, + [JOB_ASSERT] = {ANSI_HIGHLIGHT_YELLOW, "ASSERT"}, + [JOB_UNSUPPORTED] = {ANSI_HIGHLIGHT_YELLOW, "UNSUPP"}, }; const char *format; + const char *status; assert(u); assert(t >= 0); @@ -714,11 +717,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { if (!format) return; + if (log_get_show_color()) + status = strjoina(statuses[result].color, statuses[result].word, ANSI_NORMAL); + else + status = statuses[result].word; + if (result != JOB_DONE) manager_flip_auto_status(u->manager, true); DISABLE_WARNING_FORMAT_NONLITERAL; - unit_status_printf(u, job_result_status_table[result], format); + unit_status_printf(u, status, format); REENABLE_WARNING; if (t == JOB_START && result == JOB_FAILED) { diff --git a/src/core/main.c b/src/core/main.c index 1783b9c7af..78701805ea 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1218,10 +1218,15 @@ static int status_welcome(void) { if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read os-release file: %m"); - return status_printf(NULL, false, false, - "\nWelcome to \x1B[%sm%s\x1B[0m!\n", - isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); + if (log_get_show_color()) + return status_printf(NULL, false, false, + "\nWelcome to \x1B[%sm%s\x1B[0m!\n", + isempty(ansi_color) ? "1" : ansi_color, + isempty(pretty_name) ? "Linux" : pretty_name); + else + return status_printf(NULL, false, false, + "\nWelcome to %s!\n", + isempty(pretty_name) ? "Linux" : pretty_name); } static int write_container_id(void) { diff --git a/src/core/transaction.c b/src/core/transaction.c index b28fc76785..c894001cf9 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -391,6 +391,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi if (delete) { + const char *status; /* logging for j not k here here to provide consistent narrative */ log_unit_warning(j->unit, "Breaking ordering cycle by deleting job %s/%s", @@ -399,7 +400,13 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi "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)); - unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL, + + if (log_get_show_color()) + status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL; + else + status = " SKIP "; + + unit_status_printf(delete->unit, status, "Ordering cycle found, skipping %s"); transaction_delete_unit(tr, delete->unit); return -EAGAIN; -- cgit v1.2.3-54-g00ecf From 1d4b557d1b5cd200b27562808c690653658ffadf Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 15 Mar 2016 19:26:30 -0400 Subject: basic/missing: add copy_file_range syscall numbers based on: https://fedora.juszkiewicz.com.pl/syscalls.html --- configure.ac | 15 +++++++++++++-- src/basic/missing.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/configure.ac b/configure.ac index 79340bcca9..cb14abda05 100644 --- a/configure.ac +++ b/configure.ac @@ -296,8 +296,19 @@ LIBS="$save_LIBS" AC_SUBST(CAP_LIBS) AC_CHECK_FUNCS([__secure_getenv secure_getenv]) -AC_CHECK_DECLS([memfd_create, gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, keyctl, LO_FLAGS_PARTSCAN], - [], [], [[ +AC_CHECK_DECLS([ + memfd_create, + gettid, + pivot_root, + name_to_handle_at, + setns, + getrandom, + renameat2, + kcmp, + keyctl, + LO_FLAGS_PARTSCAN, + copy_file_range], + [], [], [[ #include #include #include diff --git a/src/basic/missing.h b/src/basic/missing.h index 417604aa64..bdea7606e6 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -1177,3 +1177,33 @@ static inline key_serial_t request_key(const char *type, const char *description #endif #endif + +#ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +#endif + +#if !HAVE_DECL_COPY_FILE_RANGE +static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +#ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif -- cgit v1.2.3-54-g00ecf From a44202e98b638024c45e50ad404c7069c7835c04 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 15 Mar 2016 19:26:34 -0400 Subject: basic/copy: use copy_file_range() For btrfs, c_f_r() is like BTRFS_IOC_CLONE which we already used, but also works when max_bytes is set. We do call copy_bytes in coredump code with max_bytes set, and for large files, so we might see some benefit from using c_f_r() on btrfs. For other filesystems, c_f_r() falls back to do_splice_direct(), the same as sendfile, which we already call, so there shouldn't be much difference. Tested with test-copy and systemd-coredump on Linux 4.3 (w/o c_f_r) and 4.5 (w/ c_f_r). --- TODO | 2 -- src/basic/copy.c | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/TODO b/TODO index 08b74083d3..b2840ba4ab 100644 --- a/TODO +++ b/TODO @@ -49,8 +49,6 @@ Features: * cache sd_event_now() result from before the first iteration... -* support for the new copy_file_range() syscall - * add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction * Maybe add a way how users can "pin" units into memory, so that they are not subject to automatic GC? diff --git a/src/basic/copy.c b/src/basic/copy.c index dbbb1d0fd2..41dc8ca79a 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -40,6 +40,7 @@ #include "fs-util.h" #include "io-util.h" #include "macro.h" +#include "missing.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -48,10 +49,29 @@ #define COPY_BUFFER_SIZE (16*1024u) +static ssize_t try_copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { + static int have = -1; + ssize_t r; + + if (have == false) + return -ENOSYS; + + r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); + if (_unlikely_(have < 0)) + have = r >= 0 || errno != ENOSYS; + if (r >= 0) + return r; + else + return -errno; +} + int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { - bool try_sendfile = true, try_splice = true; + bool try_cfr = true, try_sendfile = true, try_splice = true; int r; - size_t m = SSIZE_MAX; /* that the maximum that sendfile accepts */ + size_t m = SSIZE_MAX; /* that the maximum that sendfile and c_f_r accept */ assert(fdf >= 0); assert(fdt >= 0); @@ -78,6 +98,22 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { m = (size_t) max_bytes; } + /* First try copy_file_range(), unless we already tried */ + if (try_cfr) { + n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u); + if (n < 0) { + if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV)) + return n; + + try_cfr = false; + /* use fallback below */ + } else if (n == 0) /* EOF */ + break; + else + /* Success! */ + goto next; + } + /* First try sendfile(), unless we already tried */ if (try_sendfile) { n = sendfile(fdt, fdf, NULL, m); -- cgit v1.2.3-54-g00ecf From 2f368e4a114888dae8c7ebb1020efc3d922b61e9 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 17 Mar 2016 13:26:13 -0400 Subject: basic/missing: move syscall definitions to basic/missing_syscall.h We have a bunch of syscall wrapper definitions and it's easier to see that they follow the same pattern if they are not interspersed with other defines. Change the wrappers to be uniform: - if __NR_XXX is not defined, do not bother to call the syscall, and return -1/ENOSYS immediately. - do not check __NR_XXX defines if we detect the symbol as defined, since we don't need them anyway - reindent stuff for readability New file basic/missing_syscall.h is included at the end of missing.h because it might make use of some of the definitions in missing.h. --- Makefile.am | 1 + src/basic/missing.h | 244 +--------------------------------- src/basic/missing_syscall.h | 310 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 312 insertions(+), 243 deletions(-) create mode 100644 src/basic/missing_syscall.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 9cee98ec5a..71e0664c74 100644 --- a/Makefile.am +++ b/Makefile.am @@ -744,6 +744,7 @@ noinst_LTLIBRARIES += \ libbasic_la_SOURCES = \ src/basic/missing.h \ + src/basic/missing_syscall.h \ src/basic/capability-util.c \ src/basic/capability-util.h \ src/basic/c-rbtree.c \ diff --git a/src/basic/missing.h b/src/basic/missing.h index bdea7606e6..034e334e66 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -135,84 +135,6 @@ #define SOL_SCTP 132 #endif -#if !HAVE_DECL_PIVOT_ROOT -static inline int pivot_root(const char *new_root, const char *put_old) { - return syscall(SYS_pivot_root, new_root, put_old); -} -#endif - -#ifndef __NR_memfd_create -# if defined __x86_64__ -# define __NR_memfd_create 319 -# elif defined __arm__ -# define __NR_memfd_create 385 -# elif defined __aarch64__ -# define __NR_memfd_create 279 -# elif defined __s390__ -# define __NR_memfd_create 350 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_memfd_create 4354 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_memfd_create 6318 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_memfd_create 5314 -# endif -# elif defined __i386__ -# define __NR_memfd_create 356 -# else -# warning "__NR_memfd_create unknown for your architecture" -# define __NR_memfd_create 0xffffffff -# endif -#endif - -#if !HAVE_DECL_MEMFD_CREATE -static inline int memfd_create(const char *name, unsigned int flags) { - return syscall(__NR_memfd_create, name, flags); -} -#endif - -#ifndef __NR_getrandom -# if defined __x86_64__ -# define __NR_getrandom 318 -# elif defined(__i386__) -# define __NR_getrandom 355 -# elif defined(__arm__) -# define __NR_getrandom 384 -# elif defined(__aarch64__) -# define __NR_getrandom 278 -# elif defined(__ia64__) -# define __NR_getrandom 1339 -# elif defined(__m68k__) -# define __NR_getrandom 352 -# elif defined(__s390x__) -# 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 -# endif -#endif - -#if !HAVE_DECL_GETRANDOM -static inline int getrandom(void *buffer, size_t count, unsigned flags) { - return syscall(__NR_getrandom, buffer, count, flags); -} -#endif - #ifndef GRND_NONBLOCK #define GRND_NONBLOCK 0x0001 #endif @@ -527,12 +449,6 @@ struct btrfs_ioctl_quota_ctl_args { #define MS_PRIVATE (1 << 18) #endif -#if !HAVE_DECL_GETTID -static inline pid_t gettid(void) { - return (pid_t) syscall(SYS_gettid); -} -#endif - #ifndef SCM_SECURITY #define SCM_SECURITY 0x03 #endif @@ -561,32 +477,6 @@ static inline pid_t gettid(void) { #define MAX_HANDLE_SZ 128 #endif -#ifndef __NR_name_to_handle_at -# if defined(__x86_64__) -# define __NR_name_to_handle_at 303 -# elif defined(__i386__) -# define __NR_name_to_handle_at 341 -# elif defined(__arm__) -# define __NR_name_to_handle_at 370 -# elif defined(__powerpc__) -# define __NR_name_to_handle_at 345 -# else -# error "__NR_name_to_handle_at is not defined" -# endif -#endif - -#if !HAVE_DECL_NAME_TO_HANDLE_AT -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { - return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); -} -#endif - #ifndef HAVE_SECURE_GETENV # ifdef HAVE___SECURE_GETENV # define secure_getenv __secure_getenv @@ -635,22 +525,6 @@ static inline int name_to_handle_at(int fd, const char *name, struct file_handle #endif -#ifndef __NR_setns -# if defined(__x86_64__) -# define __NR_setns 308 -# elif defined(__i386__) -# define __NR_setns 346 -# else -# error "__NR_setns is not defined" -# endif -#endif - -#if !HAVE_DECL_SETNS -static inline int setns(int fd, int nstype) { - return syscall(__NR_setns, fd, nstype); -} -#endif - #if !HAVE_DECL_LO_FLAGS_PARTSCAN #define LO_FLAGS_PARTSCAN 8 #endif @@ -1018,69 +892,10 @@ static inline int setns(int fd, int nstype) { #define CAP_AUDIT_READ 37 #endif -static inline int raw_clone(unsigned long flags, void *child_stack) { -#if defined(__s390__) || defined(__CRIS__) - /* On s390 and cris the order of the first and second arguments - * of the raw clone() system call is reversed. */ - return (int) syscall(__NR_clone, child_stack, flags); -#else - return (int) syscall(__NR_clone, flags, child_stack); -#endif -} - -static inline pid_t raw_getpid(void) { -#if defined(__alpha__) - return (pid_t) syscall(__NR_getxpid); -#else - return (pid_t) syscall(__NR_getpid); -#endif -} - -#if !HAVE_DECL_RENAMEAT2 - -#ifndef __NR_renameat2 -# if defined __x86_64__ -# define __NR_renameat2 316 -# elif defined __arm__ -# define __NR_renameat2 382 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_renameat2 4351 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_renameat2 6315 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_renameat2 5311 -# endif -# elif defined __i386__ -# define __NR_renameat2 353 -# else -# warning "__NR_renameat2 unknown for your architecture" -# define __NR_renameat2 0xffffffff -# endif -#endif - -static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { - return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); -} -#endif - #ifndef RENAME_NOREPLACE #define RENAME_NOREPLACE (1 << 0) #endif -#if !HAVE_DECL_KCMP -static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { -#if defined(__NR_kcmp) - return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif - #ifndef KCMP_FILE #define KCMP_FILE 0 #endif @@ -1097,35 +912,6 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns typedef int32_t key_serial_t; #endif -#if !HAVE_DECL_KEYCTL -static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) { -#if defined(__NR_keyctl) - return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); -#else - errno = ENOSYS; - return -1; -#endif -} - -static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { -#if defined (__NR_add_key) - return syscall(__NR_add_key, type, description, payload, plen, ringid); -#else - errno = ENOSYS; - return -1; -#endif -} - -static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { -#if defined (__NR_request_key) - return syscall(__NR_request_key, type, description, callout_info, destringid); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif - #ifndef KEYCTL_READ #define KEYCTL_READ 11 #endif @@ -1178,32 +964,4 @@ static inline key_serial_t request_key(const char *type, const char *description #endif -#ifndef __NR_copy_file_range -# if defined(__x86_64__) -# define __NR_copy_file_range 326 -# elif defined(__i386__) -# define __NR_copy_file_range 377 -# elif defined __s390__ -# define __NR_copy_file_range 375 -# elif defined __arm__ -# define __NR_copy_file_range 391 -# elif defined __aarch64__ -# define __NR_copy_file_range 285 -# else -# warning "__NR_copy_file_range not defined for your architecture" -# endif -#endif - -#if !HAVE_DECL_COPY_FILE_RANGE -static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, - int fd_out, loff_t *off_out, - size_t len, - unsigned int flags) { -#ifdef __NR_copy_file_range - return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif +#include "missing_syscall.h" diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h new file mode 100644 index 0000000000..d502d3b9ca --- /dev/null +++ b/src/basic/missing_syscall.h @@ -0,0 +1,310 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2016 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 . +***/ + +/* Missing glibc definitions to access certain kernel APIs */ + +#if !HAVE_DECL_PIVOT_ROOT +static inline int pivot_root(const char *new_root, const char *put_old) { + return syscall(SYS_pivot_root, new_root, put_old); +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_MEMFD_CREATE +# ifndef __NR_memfd_create +# if defined __x86_64__ +# define __NR_memfd_create 319 +# elif defined __arm__ +# define __NR_memfd_create 385 +# elif defined __aarch64__ +# define __NR_memfd_create 279 +# elif defined __s390__ +# define __NR_memfd_create 350 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_memfd_create 4354 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_memfd_create 6318 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_memfd_create 5314 +# endif +# elif defined __i386__ +# define __NR_memfd_create 356 +# else +# warning "__NR_memfd_create unknown for your architecture" +# endif +# endif + +static inline int memfd_create(const char *name, unsigned int flags) { +# ifdef __NR_memfd_create + return syscall(__NR_memfd_create, name, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_GETRANDOM +# ifndef __NR_getrandom +# if defined __x86_64__ +# define __NR_getrandom 318 +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__arm__) +# define __NR_getrandom 384 +# elif defined(__aarch64__) +# define __NR_getrandom 278 +# elif defined(__ia64__) +# define __NR_getrandom 1339 +# elif defined(__m68k__) +# define __NR_getrandom 352 +# elif defined(__s390x__) +# 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" +# endif +# endif + +static inline int getrandom(void *buffer, size_t count, unsigned flags) { +# ifdef __NR_getrandom + return syscall(__NR_getrandom, buffer, count, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_GETTID +static inline pid_t gettid(void) { + return (pid_t) syscall(SYS_gettid); +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_NAME_TO_HANDLE_AT +# ifndef __NR_name_to_handle_at +# if defined(__x86_64__) +# define __NR_name_to_handle_at 303 +# elif defined(__i386__) +# define __NR_name_to_handle_at 341 +# elif defined(__arm__) +# define __NR_name_to_handle_at 370 +# elif defined(__powerpc__) +# define __NR_name_to_handle_at 345 +# else +# error "__NR_name_to_handle_at is not defined" +# endif +# endif + +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[0]; +}; + +static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { +# ifdef __NR_name_to_handle_at + return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_SETNS +# ifndef __NR_setns +# if defined(__x86_64__) +# define __NR_setns 308 +# elif defined(__i386__) +# define __NR_setns 346 +# else +# error "__NR_setns is not defined" +# endif +# endif + +static inline int setns(int fd, int nstype) { +# ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +static inline int raw_clone(unsigned long flags, void *child_stack) { +#if defined(__s390__) || defined(__CRIS__) + /* On s390 and cris the order of the first and second arguments + * of the raw clone() system call is reversed. */ + return (int) syscall(__NR_clone, child_stack, flags); +#else + return (int) syscall(__NR_clone, flags, child_stack); +#endif +} + +/* ======================================================================= */ + +static inline pid_t raw_getpid(void) { +#if defined(__alpha__) + return (pid_t) syscall(__NR_getxpid); +#else + return (pid_t) syscall(__NR_getpid); +#endif +} + +/* ======================================================================= */ + +#if !HAVE_DECL_RENAMEAT2 +# ifndef __NR_renameat2 +# if defined __x86_64__ +# define __NR_renameat2 316 +# elif defined __arm__ +# define __NR_renameat2 382 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_renameat2 4351 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_renameat2 6315 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_renameat2 5311 +# endif +# elif defined __i386__ +# define __NR_renameat2 353 +# else +# warning "__NR_renameat2 unknown for your architecture" +# endif +# endif + +static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { +# ifdef __NR_renameat2 + return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_KCMP +static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { +# ifdef __NR_kcmp + return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_KEYCTL +static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) { +# ifdef __NR_keyctl + return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); +# else + errno = ENOSYS; + return -1; +# endif +} + +static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { +# ifdef __NR_add_key + return syscall(__NR_add_key, type, description, payload, plen, ringid); +# else + errno = ENOSYS; + return -1; +# endif +} + +static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { +# ifdef __NR_request_key + return syscall(__NR_request_key, type, description, callout_info, destringid); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_COPY_FILE_RANGE +# ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +# endif + +static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +# ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif -- cgit v1.2.3-54-g00ecf From 1c1ea217357c60ab2f57ea8f20d84166f641f49f Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Thu, 17 Mar 2016 21:06:17 +0000 Subject: nspawn: don't run nspawn --port=... without libiptc support We get $ systemd-nspawn --image /dev/loop1 --port 8080:80 -n -b 3 --port= is not supported, compiled without libiptc support. instead of a ping-nc-iptables debugging session --- src/nspawn/nspawn.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index be07625a03..eb89916b7e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -977,6 +977,13 @@ static int verify_arguments(void) { return -EINVAL; } +#ifndef HAVE_LIBIPTC + if (arg_expose_ports) { + log_error("--port= is not supported, compiled without libiptc support."); + return -EOPNOTSUPP; + } +#endif + if (arg_start_mode == START_BOOT && arg_kill_signal <= 0) arg_kill_signal = SIGRTMIN+3; -- cgit v1.2.3-54-g00ecf From fa13cf9e218ae0bb32ad169d0e83b007e1cb5dea Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 21 Mar 2016 14:55:30 +0100 Subject: test-copy: use correct data type for max_bytes copy_bytes() and the comparisons in test_copy_bytes_regular_file() expect an uint64_t, not a size_t. On 32 bit architectures the latter is 32 bit, leading to truncation errors. Fixes regression from commit 7a827fcb. --- src/test/test-copy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 1462affbcf..cb437754b4 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -180,14 +180,14 @@ static void test_copy_bytes(void) { assert_se(r == -EBADF); } -static void test_copy_bytes_regular_file(const char *src, bool try_reflink, size_t max_bytes) { +static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint64_t max_bytes) { char fn2[] = "/tmp/test-copy-file-XXXXXX"; char fn3[] = "/tmp/test-copy-file-XXXXXX"; _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; int r; struct stat buf, buf2, buf3; - log_info("%s try_reflink=%s max_bytes=%zu", __func__, yes_no(try_reflink), max_bytes); + log_info("%s try_reflink=%s max_bytes=%" PRIu64, __func__, yes_no(try_reflink), max_bytes); fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY); assert_se(fd >= 0); @@ -221,7 +221,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, size assert_se(fstat(fd2, &buf2) == 0); assert_se(fstat(fd3, &buf3) == 0); - assert_se((size_t) buf2.st_size == MIN((size_t) buf.st_size, max_bytes)); + assert_se((uint64_t) buf2.st_size == MIN((uint64_t) buf.st_size, max_bytes)); assert_se(buf3.st_size == buf2.st_size); unlink(fn2); -- cgit v1.2.3-54-g00ecf From 34f5ff465fc63c46aa2aa2f10465286c2ddde6a1 Mon Sep 17 00:00:00 2001 From: Ronny Chevalier Date: Mon, 21 Mar 2016 18:40:07 +0100 Subject: test-execute: fix execution of AmbientCapabilities tests Wrong tests were executed --- src/test/test-execute.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 3e91a5601e..901cc44af6 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -252,10 +252,11 @@ static void test_exec_capabilityambientset(Manager *m) { r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); if (r >= 0 || errno != EINVAL) { if (getpwnam("nobody")) { - test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); - } else if (getpwnam("nfsnobody")) { test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); + } else if (getpwnam("nfsnobody")) { + test(m, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED); + test(m, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED); } else log_error_errno(errno, "Skipping test_exec_capabilityambientset, could not find nobody/nfsnobody user: %m"); } else -- cgit v1.2.3-54-g00ecf From 93515caebfaacaf14b34c114ef77a42310b4b89f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 21 Mar 2016 16:17:18 -0400 Subject: tests: rename test-env-replace to test-env-util --- .gitignore | 2 +- Makefile.am | 8 +- src/test/test-env-replace.c | 194 -------------------------------------------- src/test/test-env-util.c | 194 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+), 199 deletions(-) delete mode 100644 src/test/test-env-replace.c create mode 100644 src/test/test-env-util.c (limited to 'src') diff --git a/.gitignore b/.gitignore index dd887902ad..0e1d428ab0 100644 --- a/.gitignore +++ b/.gitignore @@ -182,7 +182,7 @@ /test-efi-disk.img /test-ellipsize /test-engine -/test-env-replace +/test-env-util /test-escape /test-event /test-execute diff --git a/Makefile.am b/Makefile.am index c2a82a5a35..350416af30 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1421,7 +1421,7 @@ tests += \ test-watchdog \ test-cgroup-mask \ test-job-type \ - test-env-replace \ + test-env-util \ test-strbuf \ test-strv \ test-path \ @@ -2197,10 +2197,10 @@ test_cgroup_util_SOURCES = \ test_cgroup_util_LDADD = \ libshared.la -test_env_replace_SOURCES = \ - src/test/test-env-replace.c +test_env_util_SOURCES = \ + src/test/test-env-util.c -test_env_replace_LDADD = \ +test_env_util_LDADD = \ libshared.la test_strbuf_SOURCES = \ diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c deleted file mode 100644 index 264acc6ea6..0000000000 --- a/src/test/test-env-replace.c +++ /dev/null @@ -1,194 +0,0 @@ -/*** - 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 . -***/ - -#include - -#include "env-util.h" -#include "string-util.h" -#include "strv.h" -#include "util.h" - -static void test_strv_env_delete(void) { - _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; - - a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); - assert_se(a); - - b = strv_new("PIEP", "FOO", NULL); - assert_se(b); - - c = strv_new("SCHLUMPF", NULL); - assert_se(c); - - d = strv_env_delete(a, 2, b, c); - assert_se(d); - - assert_se(streq(d[0], "WALDO=WALDO")); - assert_se(streq(d[1], "WALDO=")); - assert_se(strv_length(d) == 2); -} - -static void test_strv_env_unset(void) { - _cleanup_strv_free_ char **l = NULL; - - l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); - assert_se(l); - - assert_se(strv_env_unset(l, "SCHLUMPF") == l); - - assert_se(streq(l[0], "PIEP")); - assert_se(streq(l[1], "NANANANA=YES")); - assert_se(strv_length(l) == 2); -} - -static void test_strv_env_set(void) { - _cleanup_strv_free_ char **l = NULL, **r = NULL; - - l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); - assert_se(l); - - r = strv_env_set(l, "WALDO=WALDO"); - assert_se(r); - - assert_se(streq(r[0], "PIEP")); - assert_se(streq(r[1], "SCHLUMPF=SMURFF")); - assert_se(streq(r[2], "NANANANA=YES")); - assert_se(streq(r[3], "WALDO=WALDO")); - assert_se(strv_length(r) == 4); -} - -static void test_strv_env_merge(void) { - _cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL; - - a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); - assert_se(a); - - b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); - assert_se(b); - - r = strv_env_merge(2, a, b); - assert_se(r); - assert_se(streq(r[0], "FOO=")); - assert_se(streq(r[1], "WALDO=")); - assert_se(streq(r[2], "PIEP")); - assert_se(streq(r[3], "SCHLUMPF=SMURFF")); - assert_se(streq(r[4], "PIEP=")); - assert_se(streq(r[5], "NANANANA=YES")); - assert_se(strv_length(r) == 6); - - assert_se(strv_env_clean(r) == r); - assert_se(streq(r[0], "FOO=")); - assert_se(streq(r[1], "WALDO=")); - assert_se(streq(r[2], "SCHLUMPF=SMURFF")); - assert_se(streq(r[3], "PIEP=")); - assert_se(streq(r[4], "NANANANA=YES")); - assert_se(strv_length(r) == 5); -} - -static void test_replace_env_arg(void) { - const char *env[] = { - "FOO=BAR BAR", - "BAR=waldo", - NULL - }; - const char *line[] = { - "FOO$FOO", - "FOO$FOOFOO", - "FOO${FOO}$FOO", - "FOO${FOO}", - "${FOO}", - "$FOO", - "$FOO$FOO", - "${FOO}${BAR}", - "${FOO", - "FOO$$${FOO}", - "$$FOO${FOO}", - NULL - }; - _cleanup_strv_free_ char **r = NULL; - - r = replace_env_argv((char**) line, (char**) env); - assert_se(r); - assert_se(streq(r[0], "FOO$FOO")); - assert_se(streq(r[1], "FOO$FOOFOO")); - assert_se(streq(r[2], "FOOBAR BAR$FOO")); - assert_se(streq(r[3], "FOOBAR BAR")); - assert_se(streq(r[4], "BAR BAR")); - assert_se(streq(r[5], "BAR")); - assert_se(streq(r[6], "BAR")); - assert_se(streq(r[7], "BAR BARwaldo")); - assert_se(streq(r[8], "${FOO")); - assert_se(streq(r[9], "FOO$BAR BAR")); - assert_se(streq(r[10], "$FOOBAR BAR")); - assert_se(strv_length(r) == 11); -} - -static void test_env_clean(void) { - _cleanup_strv_free_ char **e; - - e = strv_new("FOOBAR=WALDO", - "FOOBAR=WALDO", - "FOOBAR", - "F", - "X=", - "F=F", - "=", - "=F", - "", - "0000=000", - "äöüß=abcd", - "abcd=äöüß", - "xyz\n=xyz", - "xyz=xyz\n", - "another=one", - "another=final one", - NULL); - assert_se(e); - assert_se(!strv_env_is_valid(e)); - assert_se(strv_env_clean(e) == e); - assert_se(strv_env_is_valid(e)); - - assert_se(streq(e[0], "FOOBAR=WALDO")); - assert_se(streq(e[1], "X=")); - assert_se(streq(e[2], "F=F")); - assert_se(streq(e[3], "abcd=äöüß")); - assert_se(streq(e[4], "another=final one")); - assert_se(e[5] == NULL); -} - -static void test_env_name_is_valid(void) { - assert_se(env_name_is_valid("test")); - - assert_se(!env_name_is_valid(NULL)); - assert_se(!env_name_is_valid("")); - assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong")); - assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed")); -} - -int main(int argc, char *argv[]) { - test_strv_env_delete(); - test_strv_env_unset(); - test_strv_env_set(); - test_strv_env_merge(); - test_replace_env_arg(); - test_env_clean(); - test_env_name_is_valid(); - - return 0; -} diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c new file mode 100644 index 0000000000..264acc6ea6 --- /dev/null +++ b/src/test/test-env-util.c @@ -0,0 +1,194 @@ +/*** + 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 . +***/ + +#include + +#include "env-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +static void test_strv_env_delete(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; + + a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); + assert_se(a); + + b = strv_new("PIEP", "FOO", NULL); + assert_se(b); + + c = strv_new("SCHLUMPF", NULL); + assert_se(c); + + d = strv_env_delete(a, 2, b, c); + assert_se(d); + + assert_se(streq(d[0], "WALDO=WALDO")); + assert_se(streq(d[1], "WALDO=")); + assert_se(strv_length(d) == 2); +} + +static void test_strv_env_unset(void) { + _cleanup_strv_free_ char **l = NULL; + + l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + assert_se(l); + + assert_se(strv_env_unset(l, "SCHLUMPF") == l); + + assert_se(streq(l[0], "PIEP")); + assert_se(streq(l[1], "NANANANA=YES")); + assert_se(strv_length(l) == 2); +} + +static void test_strv_env_set(void) { + _cleanup_strv_free_ char **l = NULL, **r = NULL; + + l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + assert_se(l); + + r = strv_env_set(l, "WALDO=WALDO"); + assert_se(r); + + assert_se(streq(r[0], "PIEP")); + assert_se(streq(r[1], "SCHLUMPF=SMURFF")); + assert_se(streq(r[2], "NANANANA=YES")); + assert_se(streq(r[3], "WALDO=WALDO")); + assert_se(strv_length(r) == 4); +} + +static void test_strv_env_merge(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL; + + a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", NULL); + assert_se(a); + + b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES", NULL); + assert_se(b); + + r = strv_env_merge(2, a, b); + assert_se(r); + assert_se(streq(r[0], "FOO=")); + assert_se(streq(r[1], "WALDO=")); + assert_se(streq(r[2], "PIEP")); + assert_se(streq(r[3], "SCHLUMPF=SMURFF")); + assert_se(streq(r[4], "PIEP=")); + assert_se(streq(r[5], "NANANANA=YES")); + assert_se(strv_length(r) == 6); + + assert_se(strv_env_clean(r) == r); + assert_se(streq(r[0], "FOO=")); + assert_se(streq(r[1], "WALDO=")); + assert_se(streq(r[2], "SCHLUMPF=SMURFF")); + assert_se(streq(r[3], "PIEP=")); + assert_se(streq(r[4], "NANANANA=YES")); + assert_se(strv_length(r) == 5); +} + +static void test_replace_env_arg(void) { + const char *env[] = { + "FOO=BAR BAR", + "BAR=waldo", + NULL + }; + const char *line[] = { + "FOO$FOO", + "FOO$FOOFOO", + "FOO${FOO}$FOO", + "FOO${FOO}", + "${FOO}", + "$FOO", + "$FOO$FOO", + "${FOO}${BAR}", + "${FOO", + "FOO$$${FOO}", + "$$FOO${FOO}", + NULL + }; + _cleanup_strv_free_ char **r = NULL; + + r = replace_env_argv((char**) line, (char**) env); + assert_se(r); + assert_se(streq(r[0], "FOO$FOO")); + assert_se(streq(r[1], "FOO$FOOFOO")); + assert_se(streq(r[2], "FOOBAR BAR$FOO")); + assert_se(streq(r[3], "FOOBAR BAR")); + assert_se(streq(r[4], "BAR BAR")); + assert_se(streq(r[5], "BAR")); + assert_se(streq(r[6], "BAR")); + assert_se(streq(r[7], "BAR BARwaldo")); + assert_se(streq(r[8], "${FOO")); + assert_se(streq(r[9], "FOO$BAR BAR")); + assert_se(streq(r[10], "$FOOBAR BAR")); + assert_se(strv_length(r) == 11); +} + +static void test_env_clean(void) { + _cleanup_strv_free_ char **e; + + e = strv_new("FOOBAR=WALDO", + "FOOBAR=WALDO", + "FOOBAR", + "F", + "X=", + "F=F", + "=", + "=F", + "", + "0000=000", + "äöüß=abcd", + "abcd=äöüß", + "xyz\n=xyz", + "xyz=xyz\n", + "another=one", + "another=final one", + NULL); + assert_se(e); + assert_se(!strv_env_is_valid(e)); + assert_se(strv_env_clean(e) == e); + assert_se(strv_env_is_valid(e)); + + assert_se(streq(e[0], "FOOBAR=WALDO")); + assert_se(streq(e[1], "X=")); + assert_se(streq(e[2], "F=F")); + assert_se(streq(e[3], "abcd=äöüß")); + assert_se(streq(e[4], "another=final one")); + assert_se(e[5] == NULL); +} + +static void test_env_name_is_valid(void) { + assert_se(env_name_is_valid("test")); + + assert_se(!env_name_is_valid(NULL)); + assert_se(!env_name_is_valid("")); + assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong")); + assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed")); +} + +int main(int argc, char *argv[]) { + test_strv_env_delete(); + test_strv_env_unset(); + test_strv_env_set(); + test_strv_env_merge(); + test_replace_env_arg(); + test_env_clean(); + test_env_name_is_valid(); + + return 0; +} -- cgit v1.2.3-54-g00ecf From b8c83cfc1a12456d0f0f30c5b4cb62f34ed4fa35 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 21 Mar 2016 16:45:37 -0400 Subject: test-env-util: test env_{value,assignment}_is_valid Just to make sure everything works as expected in relation to https://bugzilla.redhat.com/show_bug.cgi?id=1312384. --- src/test/test-env-util.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src') diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c index 264acc6ea6..35bb62906e 100644 --- a/src/test/test-env-util.c +++ b/src/test/test-env-util.c @@ -2,6 +2,7 @@ This file is part of systemd. Copyright 2010 Lennart Poettering + Copyright 2016 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 @@ -177,10 +178,37 @@ static void test_env_name_is_valid(void) { assert_se(!env_name_is_valid(NULL)); assert_se(!env_name_is_valid("")); + assert_se(!env_name_is_valid("xxx\a")); + assert_se(!env_name_is_valid("xxx\007b")); + assert_se(!env_name_is_valid("\007\009")); assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong")); assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed")); } +static void test_env_value_is_valid(void) { + assert_se(env_value_is_valid("")); + assert_se(env_value_is_valid("głąb kapuściany")); + assert_se(env_value_is_valid("printf \"\\x1b]0;\\x07\"")); +} + +static void test_env_assignment_is_valid(void) { + assert_se(env_assignment_is_valid("a=")); + assert_se(env_assignment_is_valid("b=głąb kapuściany")); + assert_se(env_assignment_is_valid("c=\\007\\009\\011")); + assert_se(env_assignment_is_valid("e=printf \"\\x1b]0;\\x07\"")); + + assert_se(!env_assignment_is_valid("=")); + assert_se(!env_assignment_is_valid("a b=")); + assert_se(!env_assignment_is_valid("a =")); + assert_se(!env_assignment_is_valid(" b=")); + /* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */ + assert_se(!env_assignment_is_valid("a.b=")); + assert_se(!env_assignment_is_valid("a-b=")); + assert_se(!env_assignment_is_valid("\007=głąb kapuściany")); + assert_se(!env_assignment_is_valid("c\009=\007\009\011")); + assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;\x07\"")); +} + int main(int argc, char *argv[]) { test_strv_env_delete(); test_strv_env_unset(); @@ -189,6 +217,8 @@ int main(int argc, char *argv[]) { test_replace_env_arg(); test_env_clean(); test_env_name_is_valid(); + test_env_value_is_valid(); + test_env_assignment_is_valid(); return 0; } -- cgit v1.2.3-54-g00ecf From afec45395fb019f19ac1e157fce9128b0137b25e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 21 Mar 2016 18:24:24 -0400 Subject: Revert "DHCP DUID and IAID configurability" --- Makefile-man.am | 7 -- Makefile.am | 4 - man/networkd.conf.xml | 112 ------------------------- man/systemd.network.xml | 6 -- src/libsystemd-network/dhcp-identifier.c | 2 +- src/libsystemd-network/dhcp-identifier.h | 41 +-------- src/libsystemd-network/dhcp6-protocol.h | 7 ++ src/libsystemd-network/network-internal.c | 28 ------- src/libsystemd-network/network-internal.h | 4 - src/libsystemd-network/sd-dhcp-client.c | 48 +---------- src/libsystemd-network/sd-dhcp6-client.c | 49 ++++++----- src/network/networkd-conf.c | 133 ------------------------------ src/network/networkd-conf.h | 32 ------- src/network/networkd-dhcp4.c | 8 +- src/network/networkd-dhcp6.c | 10 --- src/network/networkd-gperf.gperf | 18 ---- src/network/networkd-link.c | 18 ---- src/network/networkd-manager.c | 2 - src/network/networkd-network-gperf.gperf | 1 - src/network/networkd-network.h | 2 - src/network/networkd.c | 5 -- src/network/networkd.h | 5 -- src/systemd/sd-dhcp-client.h | 4 - src/systemd/sd-dhcp6-client.h | 7 +- 24 files changed, 44 insertions(+), 509 deletions(-) delete mode 100644 man/networkd.conf.xml delete mode 100644 src/network/networkd-conf.c delete mode 100644 src/network/networkd-conf.h delete mode 100644 src/network/networkd-gperf.gperf (limited to 'src') diff --git a/Makefile-man.am b/Makefile-man.am index a7e348b1f1..3f03afc2ef 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -1960,21 +1960,15 @@ endif if ENABLE_NETWORKD MANPAGES += \ man/networkctl.1 \ - man/networkd.conf.5 \ man/systemd-networkd-wait-online.service.8 \ man/systemd-networkd.service.8 \ man/systemd.netdev.5 \ man/systemd.network.5 MANPAGES_ALIAS += \ - man/networkd.conf.d.5 \ man/systemd-networkd-wait-online.8 \ man/systemd-networkd.8 -man/networkd.conf.d.5: man/networkd.conf.5 man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8 man/systemd-networkd.8: man/systemd-networkd.service.8 -man/networkd.conf.d.html: man/networkd.conf.html - $(html-alias) - man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html $(html-alias) @@ -2485,7 +2479,6 @@ EXTRA_DIST += \ man/machinectl.xml \ man/modules-load.d.xml \ man/networkctl.xml \ - man/networkd.conf.xml \ man/nss-myhostname.xml \ man/nss-mymachines.xml \ man/nss-resolve.xml \ diff --git a/Makefile.am b/Makefile.am index c2a82a5a35..9a7ae2c286 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5398,8 +5398,6 @@ libnetworkd_core_la_CFLAGS = \ libnetworkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ - src/network/networkd-conf.h \ - src/network/networkd-conf.c \ src/network/networkd-link.h \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ @@ -5448,7 +5446,6 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ - src/network/networkd-gperf.c \ src/network/networkd-network-gperf.c \ src/network/networkd-netdev-gperf.c @@ -5545,7 +5542,6 @@ BUSNAMES_TARGET_WANTS += \ endif gperf_gperf_sources += \ - src/network/networkd-gperf.gperf \ src/network/networkd-network-gperf.gperf \ src/network/networkd-netdev-gperf.gperf diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml deleted file mode 100644 index 5e2927ba54..0000000000 --- a/man/networkd.conf.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - networkd.conf - systemd - - - - Developer - Vinay - Kulkarni - kulkarniv@vmware.com - - - - - - networkd.conf - 5 - - - - networkd.conf - networkd.conf.d - Global Network configuration files - - - - /etc/systemd/networkd.conf - /etc/systemd/networkd.conf.d/*.conf - /usr/lib/systemd/networkd.conf.d/*.conf - - - - Description - - These configuration files control global network parameters. - For e.g. DHCP Unique Identifier (DUID). - - - - - - - [DUID] Section Options - - This section configures the DUID value used by the DHCP protocol. The DUID value - specified here overrides the DUID that systemd-networkd generates using the machine-id - from the /etc/machine-id file. - - The configured DHCP DUID should conform to the specification in - RFC 3315, - RFC 6355. To configure IAID, see - systemd.network5 - . - - The following options are available in [DUID] section: - - - - - Type= - The type of DUID specified in this section. The following values are - supported: - raw : If Type=raw, then RawData= specifies - the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 - specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), - and identifier value "f9:2a:c2:77:29:f9:5c:00". - - - - RawData= - Specifies the DUID bytes as a single newline-terminated, hexadecimal - string, with each byte separated by a ':'. - - - - - - - See Also - - systemd1, - systemd.network5, - machine-id1 - - - - diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 73b9c00543..f2e715cf6f 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -204,12 +204,6 @@ understood to the base of 1024. - - IAIDValue= - - Identity Association Identifier for the interface. This is a 32-bit value specified in host byte order. - - diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1bef368852..1d9ec7be82 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP_DUID_TYPE_EN); + unaligned_write_be16(&duid->type, DHCP6_DUID_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index cb953cb416..93f06f5938 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,23 +25,13 @@ #include "sparse-endian.h" #include "unaligned.h" -typedef enum DHCPDUIDType { - DHCP_DUID_TYPE_RAW = 0, - DHCP_DUID_TYPE_LLT = 1, - DHCP_DUID_TYPE_EN = 2, - DHCP_DUID_TYPE_LL = 3, - DHCP_DUID_TYPE_UUID = 4, - _DHCP_DUID_TYPE_MAX, - _DHCP_DUID_TYPE_INVALID = -1, -} DHCPDUIDType; - /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - be16_t type; + uint16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -71,32 +61,3 @@ struct duid { 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, void *_id); - -static inline int dhcp_validate_duid_len(be16_t duid_type, size_t duid_len) { - struct duid d; - - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - - switch (be16toh(duid_type)) { - case DHCP_DUID_TYPE_LLT: - if (duid_len <= sizeof(d.llt)) - return -EINVAL; - break; - case DHCP_DUID_TYPE_EN: - if (duid_len != sizeof(d.en)) - return -EINVAL; - break; - case DHCP_DUID_TYPE_LL: - if (duid_len <= sizeof(d.ll)) - return -EINVAL; - break; - case DHCP_DUID_TYPE_UUID: - if (duid_len != sizeof(d.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; - } - return 0; -} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index 2487c470ab..ee4bdfb07f 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,6 +62,13 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC +enum { + DHCP6_DUID_LLT = 1, + DHCP6_DUID_EN = 2, + DHCP6_DUID_LL = 3, + DHCP6_DUID_UUID = 4, +}; + enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 7c21f42591..cb7252bbeb 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,34 +335,6 @@ int config_parse_hwaddr(const char *unit, return 0; } -int config_parse_iaid_value(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) { - uint32_t iaid_value; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atou32(rvalue, &iaid_value)) < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); - return r; - } - - *((be32_t *)data) = htobe32(iaid_value); - - return 0; -} - void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index d8b551e8ce..c8a531ab0f 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,10 +62,6 @@ int config_parse_ifalias(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_iaid_value(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 net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index b108e35386..1188b31500 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - be32_t iaid; + uint32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -298,51 +298,6 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, - size_t duid_len, struct duid *duid) { - DHCP_CLIENT_DONT_DESTROY(client); - int r; - assert_return(client, -EINVAL); - zero(client->client_id); - - client->client_id.type = 255; - - /* If IAID is not configured, generate it. */ - if (iaid == 0) { - r = dhcp_identifier_set_iaid(client->index, client->mac_addr, - client->mac_addr_len, - &client->client_id.ns.iaid); - if (r < 0) - return r; - } else - client->client_id.ns.iaid = iaid; - - /* If DUID is not configured, generate DUID-EN. */ - if (duid_len == 0) { - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, - &duid_len); - if (r < 0) - return r; - } else { - r = dhcp_validate_duid_len(client->client_id.type, - duid_len - sizeof(client->client_id.type)); - if (r < 0) - return r; - memcpy(&client->client_id.ns.duid, duid, duid_len); - } - - client->client_id_len = sizeof(client->client_id.type) + duid_len + - sizeof(client->client_id.ns.iaid); - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Configured IAID+DUID, restarting."); - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - sd_dhcp_client_start(client); - } - - return 0; -} - int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; @@ -514,6 +469,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, if (client->arp_type == ARPHRD_ETHER) memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); + /* If no client identifier exists, construct an RFC 4361-compliant one */ if (client->client_id_len == 0) { size_t duid_len; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 7cecba120c..af4709d788 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -180,30 +180,41 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, - struct duid *duid) { - int r; +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t type, + uint8_t *duid, size_t duid_len) { assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + assert_return(duid, -EINVAL); + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - if (duid_len > 0) { - r = dhcp_validate_duid_len(duid->type, - duid_len - sizeof(duid->type)); - if (r < 0) - return r; + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - memcpy(&client->duid, duid, duid_len); - client->duid_len = duid_len; + switch (type) { + case DHCP6_DUID_LLT: + if (duid_len <= sizeof(client->duid.llt)) + return -EINVAL; + break; + case DHCP6_DUID_EN: + if (duid_len != sizeof(client->duid.en)) + return -EINVAL; + break; + case DHCP6_DUID_LL: + if (duid_len <= sizeof(client->duid.ll)) + return -EINVAL; + break; + case DHCP6_DUID_UUID: + if (duid_len != sizeof(client->duid.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; } - return 0; -} - -int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid) { - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - - client->ia_na.id = iaid; + client->duid.type = htobe16(type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len + sizeof(client->duid.type); return 0; } diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c deleted file mode 100644 index 4bc92b8171..0000000000 --- a/src/network/networkd-conf.c +++ /dev/null @@ -1,133 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - 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 . - ***/ - -#include - -#include "conf-parser.h" -#include "def.h" -#include "dhcp-identifier.h" -#include "networkd-conf.h" -#include "string-table.h" - -int manager_parse_config_file(Manager *m) { - assert(m); - - return config_parse_many(PKGSYSCONFDIR "/networkd.conf", - CONF_PATHS_NULSTR("systemd/networkd.conf.d"), - "DUID\0", - config_item_perf_lookup, networkd_gperf_lookup, - false, m); -} - -static const char* const dhcp_duid_type_table[_DHCP_DUID_TYPE_MAX] = { - [DHCP_DUID_TYPE_RAW] = "raw", - [DHCP_DUID_TYPE_LLT] = "link-layer-time", - [DHCP_DUID_TYPE_EN] = "vendor", - [DHCP_DUID_TYPE_LL] = "link-layer", - [DHCP_DUID_TYPE_UUID] = "uuid" -}; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_duid_type, DHCPDUIDType); -DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_duid_type, dhcp_duid_type, DHCPDUIDType, "Failed to parse DHCP DUID type"); - -int config_parse_dhcp_duid_raw( - 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 r; - long byte; - char *cbyte, *pnext; - const char *pduid = (const char *)rvalue; - size_t count = 0, duid_len = 0; - Manager *m = userdata; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(m); - assert(m->dhcp_duid_type != _DHCP_DUID_TYPE_INVALID); - - switch (m->dhcp_duid_type) { - case DHCP_DUID_TYPE_LLT: - /* RawData contains DUID-LLT link-layer address (offset 6) */ - duid_len = 6; - break; - case DHCP_DUID_TYPE_EN: - /* RawData contains DUID-EN identifier (offset 4) */ - duid_len = 4; - break; - case DHCP_DUID_TYPE_LL: - /* RawData contains DUID-LL link-layer address (offset 2) */ - duid_len = 2; - break; - case DHCP_DUID_TYPE_UUID: - /* RawData specifies UUID (offset 0) - fall thru */ - case DHCP_DUID_TYPE_RAW: - /* First two bytes of RawData is DUID Type - fall thru */ - default: - break; - } - - if (m->dhcp_duid_type != DHCP_DUID_TYPE_RAW) - m->dhcp_duid.type = htobe16(m->dhcp_duid_type); - - /* RawData contains DUID in format " NN:NN:NN... " */ - while (true) { - r = extract_first_word(&pduid, &cbyte, ":", 0); - if (r < 0) { - log_error("Failed to read DUID."); - return -EINVAL; - } - if (r == 0) - break; - if (duid_len >= MAX_DUID_LEN) { - log_error("DUID length exceeds maximum length."); - return -EINVAL; - } - - errno = 0; - byte = strtol(cbyte, &pnext, 16); - if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) - || (errno != 0 && byte == 0) || (cbyte == pnext)) { - log_error("Invalid DUID byte: %s.", cbyte); - return -EINVAL; - } - - /* If DHCP_DUID_TYPE_RAW, first two bytes holds DUID Type */ - if ((m->dhcp_duid_type == DHCP_DUID_TYPE_RAW) && (count < 2)) { - m->dhcp_duid.type |= (byte << (8 * count)); - count++; - continue; - } - - m->dhcp_duid.raw.data[duid_len++] = byte; - } - - m->dhcp_duid_len = sizeof(m->dhcp_duid.type) + duid_len; - - return 0; -} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h deleted file mode 100644 index 6d9ce010e3..0000000000 --- a/src/network/networkd-conf.h +++ /dev/null @@ -1,32 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - 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 . -***/ - -#include "networkd.h" - - -int manager_parse_config_file(Manager *m); - -const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); - -int config_parse_dhcp_duid_type(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_duid_raw(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-dhcp4.c b/src/network/networkd-dhcp4.c index 3bbb21295c..68998eabf2 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -625,13 +625,7 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* If configured, apply user specified DUID and/or IAID */ - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid_value, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - return r; + /* Library defaults to this. */ break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 9f59cb3f8a..5f7a005c36 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,16 +230,6 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; - r = sd_dhcp6_client_set_iaid(client, link->network->iaid_value); - if (r < 0) - goto error; - - r = sd_dhcp6_client_set_duid(client, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - goto error; - r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf deleted file mode 100644 index 3ef4155476..0000000000 --- a/src/network/networkd-gperf.gperf +++ /dev/null @@ -1,18 +0,0 @@ -%{ -#include -#include "conf-parser.h" -#include "networkd-conf.h" -%} -struct ConfigPerfItem; -%null_strings -%language=ANSI-C -%define slot-name section_and_lvalue -%define hash-function-name networkd_gperf_hash -%define lookup-function-name networkd_gperf_lookup -%readonly-tables -%omit-struct-type -%struct-type -%includes -%% -DUID.Type, config_parse_dhcp_duid_type, 0, offsetof(Manager, dhcp_duid_type) -DUID.RawData, config_parse_dhcp_duid_raw, 0, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 67b04560cd..ff4bd76554 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2781,13 +2781,6 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); - - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid_value, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2797,17 +2790,6 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); - - r = sd_dhcp6_client_set_iaid(link->dhcp6_client, - link->network->iaid_value); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); - - r = sd_dhcp6_client_set_duid(link->dhcp6_client, - link->manager->dhcp_duid_len, - &link->manager->dhcp_duid); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 8d443f7b0f..b8cb7f875d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,8 +1037,6 @@ int manager_new(Manager **ret) { if (r < 0) return r; - m->dhcp_duid_type = _DHCP_DUID_TYPE_INVALID; - *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 7a9a136d5b..a5d1714293 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -26,7 +26,6 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) -Link.IAIDValue, config_parse_iaid_value, 0, offsetof(Network, iaid_value) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index c5530cdfba..4a13e2b574 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -30,7 +30,6 @@ typedef struct Network Network; #include "networkd-route.h" #include "networkd-util.h" #include "networkd.h" -#include "sparse-endian.h" #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 @@ -145,7 +144,6 @@ struct Network { struct ether_addr *mac; unsigned mtu; - be32_t iaid_value; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.c b/src/network/networkd.c index c8f81a2ca6..3a2615e6fd 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,7 +21,6 @@ #include "capability-util.h" #include "networkd.h" -#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -90,10 +89,6 @@ int main(int argc, char *argv[]) { goto out; } - r = manager_parse_config_file(m); - if (r < 0) - log_warning_errno(r, "Failed to parse configuration file: %m"); - r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index d815f30610..6bdd8302a0 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -35,7 +35,6 @@ typedef struct Manager Manager; #include "networkd-link.h" #include "networkd-network.h" #include "networkd-util.h" -#include "dhcp-identifier.h" struct Manager { sd_netlink *rtnl; @@ -62,10 +61,6 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; - - DHCPDUIDType dhcp_duid_type; - size_t dhcp_duid_len; - struct duid dhcp_duid; }; extern const char* const network_dirs[]; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 7873cb1e04..ef45370505 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -27,7 +27,6 @@ #include "sd-dhcp-lease.h" #include "sd-event.h" -#include "sparse-endian.h" #include "_sd-common.h" @@ -83,7 +82,6 @@ enum { SD_DHCP_OPTION_END = 255, }; -struct duid; typedef struct sd_dhcp_client sd_dhcp_client; typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, @@ -100,8 +98,6 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, - size_t duid_len, struct duid *duid); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index ebdd017628..1bedc941aa 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -26,7 +26,6 @@ #include "sd-dhcp6-lease.h" #include "sd-event.h" -#include "sparse-endian.h" #include "_sd-common.h" @@ -75,7 +74,6 @@ enum { /* option codes 144-65535 are unassigned */ }; -struct duid; typedef struct sd_dhcp6_client sd_dhcp6_client; typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, @@ -87,9 +85,8 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, - struct duid *duid); -int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, + size_t duid_len); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, -- cgit v1.2.3-54-g00ecf From 68ea57b21d4d570fd1b5f22f9da4111892341fca Mon Sep 17 00:00:00 2001 From: Jaroslav Škarvada Date: Tue, 15 Mar 2016 14:25:51 +0100 Subject: Added support for 3D printers to uaccess (ID_MAKER_TOOL) This is to support 3D printers, CNCs, laser cutters, 3D scanners, etc. --- src/login/70-uaccess.rules | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules index 694df2cfc8..50dcd2e275 100644 --- a/src/login/70-uaccess.rules +++ b/src/login/70-uaccess.rules @@ -75,4 +75,7 @@ SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess" # software-defined radio communication devices ENV{ID_SOFTWARE_RADIO}=="?*", TAG+="uaccess" +# 3D printers, CNC machines, laser cutters, 3D scanners, etc. +ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess" + LABEL="uaccess_end" -- cgit v1.2.3-54-g00ecf From 9dd7ea9a7d5053be0c2a744b1b57a7b1dc203f0e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 21 Mar 2016 23:34:13 -0400 Subject: Ignore BOM in config files Fixes #2823. Also remove unnecessary feof check. --- src/basic/utf8.h | 1 + src/shared/conf-parser.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/utf8.h b/src/basic/utf8.h index 12c272d66e..f9b9c9468b 100644 --- a/src/basic/utf8.h +++ b/src/basic/utf8.h @@ -28,6 +28,7 @@ #include "missing.h" #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" +#define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf" bool unichar_is_valid(char32_t c); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index e7fe9ac21e..bd0a1f483b 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -294,7 +294,7 @@ int config_parse(const char *unit, _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; - bool section_ignored = false; + bool section_ignored = false, allow_bom = true; int r; assert(filename); @@ -314,11 +314,11 @@ int config_parse(const char *unit, fd_warn_permissions(filename, fileno(f)); - while (!feof(f)) { - char l[LINE_MAX], *p, *c = NULL, *e; + for (;;) { + char buf[LINE_MAX], *l, *p, *c = NULL, *e; bool escaped = false; - if (!fgets(l, sizeof(l), f)) { + if (!fgets(buf, sizeof buf, f)) { if (feof(f)) break; @@ -326,6 +326,11 @@ int config_parse(const char *unit, return -errno; } + l = buf; + if (allow_bom && startswith(l, UTF8_BYTE_ORDER_MARK)) + l += strlen(UTF8_BYTE_ORDER_MARK); + allow_bom = false; + truncate_nl(l); if (continuation) { -- cgit v1.2.3-54-g00ecf From ebc962656cee33e3e8395f456a8208c3ca41969c Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Wed, 23 Mar 2016 07:47:00 +0100 Subject: systemctl: no need to pass --all if inactive is explicitly requested in list-units If list-units command is explicitly asked to show inactive units by using '--state=inactive' option, there's no need to force the user to pass '--all' option to include inactive units in the search in this case. --- src/systemctl/systemctl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 180c8f9656..2afb7bad1a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -340,6 +340,11 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) { if (arg_all) return true; + if (!strv_isempty(arg_states)) + return true; + + /* By default show all units except the ones in inactive + * state and with no pending job */ if (u->job_id > 0) return true; -- cgit v1.2.3-54-g00ecf From 110ceee58e5bc796c03a7db2109f85a999d5bc2e Mon Sep 17 00:00:00 2001 From: Iago López Galeiras Date: Wed, 23 Mar 2016 15:45:32 +0100 Subject: run: remove period when printing started units If you start a unit with systemd-run you usually need its name to inspect it or stop it. Removing the period makes copying the unit name easier. --- man/systemd-run.xml | 6 +++--- src/run/run.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/man/systemd-run.xml b/man/systemd-run.xml index 414e1c8335..a92dfb402a 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -345,7 +345,7 @@ provided by systemd to services: # systemd-run env -Running as unit run-19945.service. +Running as unit run-19945.service # journalctl -u run-19945.service Sep 08 07:37:21 bupkis systemd[1]: Starting /usr/bin/env... Sep 08 07:37:21 bupkis systemd[1]: Started /usr/bin/env. @@ -366,8 +366,8 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20. # date; systemd-run --on-active=30 --timer-property=AccuracySec=100ms /bin/touch /tmp/foo Mon Dec 8 20:44:24 KST 2014 -Running as unit run-71.timer. -Will run as unit run-71.service. +Running as unit run-71.timer +Will run service as unit run-71.service # 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. diff --git a/src/run/run.c b/src/run/run.c index 1ed1bd96bf..540a612fdf 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -878,7 +878,7 @@ static int start_transient_service( (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); if (!arg_quiet) - log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service); + log_info("Running as unit %s\nPress ^] three times within 1s to disconnect TTY.", service); r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward); if (r < 0) @@ -896,7 +896,7 @@ static int start_transient_service( fputc('\n', stdout); } else if (!arg_quiet) - log_info("Running as unit %s.", service); + log_info("Running as unit %s", service); return 0; } @@ -1038,7 +1038,7 @@ static int start_transient_scope( return r; if (!arg_quiet) - log_info("Running scope as unit %s.", scope); + log_info("Running scope as unit %s", scope); execvpe(argv[0], argv, env); @@ -1189,9 +1189,9 @@ static int start_transient_timer( if (r < 0) return r; - log_info("Running timer as unit %s.", timer); + log_info("Running timer as unit %s", timer); if (argv[0]) - log_info("Will run service as unit %s.", service); + log_info("Will run service as unit %s", service); return 0; } -- cgit v1.2.3-54-g00ecf From 27a6ea9163384993312f3a0da9710c9151111f50 Mon Sep 17 00:00:00 2001 From: Georgia Brikis Date: Tue, 22 Mar 2016 12:08:42 +0100 Subject: core: Fix path for opening ffs endpoint ep0 usbffs_address_create() expects an absolute path to the file that is supposed to be opened. The path specified only leads to the directory containing the endpoint ep0 not the endpoint itself. This commit adds the endpoints name to the path. --- src/core/socket.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index 87586c1c2e..dd515a17a5 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1341,8 +1341,12 @@ static int socket_open_fds(Socket *s) { break; case SOCKET_USB_FUNCTION: + { + _cleanup_free_ char *ep = NULL; - p->fd = usbffs_address_create(p->path); + ep = path_make_absolute("ep0", p->path); + + p->fd = usbffs_address_create(ep); if (p->fd < 0) { r = p->fd; goto rollback; @@ -1357,7 +1361,7 @@ static int socket_open_fds(Socket *s) { goto rollback; break; - + } default: assert_not_reached("Unknown port type"); } -- cgit v1.2.3-54-g00ecf From a75db59cf77f1fd0893936df9759d1276b30647f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 24 Mar 2016 10:44:36 +0900 Subject: localectl: remove unnecessary line break If /etc/locale.conf is empty or does not exist, the output of 'localectl status' command includes an unnecessary line break as follows: ======================= System Locale: n/a VC Keymap: n/a X11 Layout: n/a ======================= This commit removes the line break after the system locale. --- src/locale/localectl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/locale/localectl.c b/src/locale/localectl.c index cde33bdf41..3494af15c6 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -131,7 +131,7 @@ static void print_status_info(StatusInfo *i) { assert(i); if (strv_isempty(i->locale)) - puts(" System Locale: n/a\n"); + puts(" System Locale: n/a"); else { char **j; -- cgit v1.2.3-54-g00ecf From c86b2d8f7334c97224391b6e384fa52622e0d800 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 24 Mar 2016 10:58:38 +0900 Subject: localectl: align output of 'localectl status' command If kernel command line options for locale are given, the output of 'localectl status' command is not aligned, for example, ============= Warning: Settings on kernel command line override system locale settings in /etc/locale.conf. Command Line: LANG=C System Locale: LANG=C VC Keymap: n/a X11 Layout: n/a ============= This commit fixes the alignment. --- src/locale/localectl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 3494af15c6..4865335349 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -116,11 +116,11 @@ static void print_overridden_variables(void) { if (variables[j]) { if (print_warning) { log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n" - " Command Line: %s=%s", locale_variable_to_string(j), variables[j]); + " Command Line: %s=%s", locale_variable_to_string(j), variables[j]); print_warning = false; } else - log_warning(" %s=%s", locale_variable_to_string(j), variables[j]); + log_warning(" %s=%s", locale_variable_to_string(j), variables[j]); } finish: for (j = 0; j < _VARIABLE_LC_MAX; j++) -- cgit v1.2.3-54-g00ecf From b59f0ecd27b1c6e24a1835e31c638dcf765517e4 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Wed, 23 Mar 2016 08:46:39 +0100 Subject: core: fix "stoppping" typo --- src/core/job.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/job.c b/src/core/job.c index 719cb0a3e5..5557a6a942 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -645,7 +645,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = { [JOB_DONE] = "Stopped %s.", [JOB_FAILED] = "Stopped (with error) %s.", - [JOB_TIMEOUT] = "Timed out stoppping %s.", + [JOB_TIMEOUT] = "Timed out stopping %s.", }; static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = { [JOB_DONE] = "Reloaded %s.", -- cgit v1.2.3-54-g00ecf From b4944d2df248fbd2f96a4b9b4fe02fe0c1af7499 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Wed, 23 Mar 2016 08:46:58 +0100 Subject: logind: fix crash when shutdown is not issued from a tty It's possible that sd_bus_creds_get_tty() fails and thus scheduled_shutdown_tty is NULL in method_schedule_shutdown(). Fix logind_wall_tty_filter() to get along with that, by showing the message on all TTYs, instead of crashing in strcmp(). https://launchpad.net/bugs/1553040 --- src/login/logind-utmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 11a91c3947..29ab00eb1f 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -65,7 +65,7 @@ bool logind_wall_tty_filter(const char *tty, void *userdata) { assert(m); - if (!startswith(tty, "/dev/")) + if (!startswith(tty, "/dev/") || !m->scheduled_shutdown_tty) return true; return !streq(tty + 5, m->scheduled_shutdown_tty); -- cgit v1.2.3-54-g00ecf From 6afa676780455e2d847cd367b8f39a02cac98ae3 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 23 Mar 2016 18:47:26 +0100 Subject: lldp: move public macros to sd-lldp.h and namespace them lldp.h contains definitions of LLDP types, subtypes and capabilities which should be exposed in public headers. Get rid of the file and move those definitions to sd-lldp.h with the SD_ prefix. --- Makefile.am | 1 - src/libsystemd-network/lldp-neighbor.c | 47 ++++++++------- src/libsystemd-network/lldp.h | 102 --------------------------------- src/libsystemd-network/test-lldp.c | 23 ++++---- src/network/networkctl.c | 1 - src/network/networkd-link.c | 5 +- src/network/networkd-lldp-tx.c | 31 +++++----- src/systemd/sd-lldp.h | 81 ++++++++++++++++++++++++++ 8 files changed, 132 insertions(+), 159 deletions(-) delete mode 100644 src/libsystemd-network/lldp.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 2b72a53ecd..06efd09e7a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3423,7 +3423,6 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/sd-dhcp6-lease.c \ src/libsystemd-network/dhcp-identifier.h \ src/libsystemd-network/dhcp-identifier.c \ - src/libsystemd-network/lldp.h \ src/libsystemd-network/lldp-internal.h \ src/libsystemd-network/lldp-network.h \ src/libsystemd-network/lldp-network.c \ diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 190c9baece..6a716430e3 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -24,7 +24,6 @@ #include "in-addr-util.h" #include "lldp-internal.h" #include "lldp-neighbor.h" -#include "lldp.h" #include "unaligned.h" static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) { @@ -245,7 +244,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { switch (type) { - case LLDP_TYPE_END: + case SD_LLDP_TYPE_END: if (length != 0) { log_lldp("End marker TLV not zero-sized, ignoring datagram."); return -EBADMSG; @@ -257,7 +256,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { goto end_marker; - case LLDP_TYPE_CHASSIS_ID: + case SD_LLDP_TYPE_CHASSIS_ID: if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */ log_lldp("Chassis ID field size out of range, ignoring datagram."); return -EBADMSG; @@ -274,7 +273,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { n->id.chassis_id_size = length; break; - case LLDP_TYPE_PORT_ID: + case SD_LLDP_TYPE_PORT_ID: if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */ log_lldp("Port ID field size out of range, ignoring datagram."); return -EBADMSG; @@ -291,7 +290,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { n->id.port_id_size = length; break; - case LLDP_TYPE_TTL: + case SD_LLDP_TYPE_TTL: if (length != 2) { log_lldp("TTL field has wrong size, ignoring datagram."); return -EBADMSG; @@ -306,25 +305,25 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { n->has_ttl = true; break; - case LLDP_TYPE_PORT_DESCRIPTION: + case SD_LLDP_TYPE_PORT_DESCRIPTION: r = parse_string(&n->port_description, p, length); if (r < 0) return r; break; - case LLDP_TYPE_SYSTEM_NAME: + case SD_LLDP_TYPE_SYSTEM_NAME: r = parse_string(&n->system_name, p, length); if (r < 0) return r; break; - case LLDP_TYPE_SYSTEM_DESCRIPTION: + case SD_LLDP_TYPE_SYSTEM_DESCRIPTION: r = parse_string(&n->system_description, p, length); if (r < 0) return r; break; - case LLDP_TYPE_SYSTEM_CAPABILITIES: + case SD_LLDP_TYPE_SYSTEM_CAPABILITIES: if (length != 4) log_lldp("System capabilities field has wrong size, ignoring."); else { @@ -335,7 +334,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { break; - case LLDP_TYPE_PRIVATE: + case SD_LLDP_TYPE_PRIVATE: if (length < 4) log_lldp("Found private TLV that is too short, ignoring."); @@ -479,18 +478,18 @@ _public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, cons switch (*(uint8_t*) n->id.chassis_id) { - case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: - case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: - case LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: - case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: - case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: + case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1); if (!k) return -ENOMEM; goto done; - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k); if (r < 0) return r; @@ -499,7 +498,7 @@ _public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, cons break; - case LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: + case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k); if (r < 0) return r; @@ -550,17 +549,17 @@ _public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const c switch (*(uint8_t*) n->id.port_id) { - case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1); if (!k) return -ENOMEM; goto done; - case LLDP_PORT_SUBTYPE_MAC_ADDRESS: + case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS: r = format_mac_address(n->id.port_id, n->id.port_id_size, &k); if (r < 0) return r; @@ -569,7 +568,7 @@ _public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const c break; - case LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: + case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: r = format_network_address(n->id.port_id, n->id.port_id_size, &k); if (r < 0) return r; @@ -738,7 +737,7 @@ _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], u assert_return(oui, -EINVAL); assert_return(subtype, -EINVAL); - r = sd_lldp_neighbor_tlv_is_type(n, LLDP_TYPE_PRIVATE); + r = sd_lldp_neighbor_tlv_is_type(n, SD_LLDP_TYPE_PRIVATE); if (r < 0) return r; if (r == 0) diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h deleted file mode 100644 index d61ecabcfc..0000000000 --- a/src/libsystemd-network/lldp.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - 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 . -***/ - -#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } - -/* IEEE 802.3AB Clause 9: TLV Types */ -enum { - LLDP_TYPE_END = 0, - LLDP_TYPE_CHASSIS_ID = 1, - LLDP_TYPE_PORT_ID = 2, - LLDP_TYPE_TTL = 3, - LLDP_TYPE_PORT_DESCRIPTION = 4, - LLDP_TYPE_SYSTEM_NAME = 5, - LLDP_TYPE_SYSTEM_DESCRIPTION = 6, - LLDP_TYPE_SYSTEM_CAPABILITIES = 7, - LLDP_TYPE_MGMT_ADDRESS = 8, - LLDP_TYPE_PRIVATE = 127, -}; - -/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ -enum { - LLDP_CHASSIS_SUBTYPE_RESERVED = 0, - LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, - LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, - LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3, - LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, - LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, - LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, - LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, -}; - -/* IEEE 802.3AB Clause 9.5.3: Port subtype */ -enum { - LLDP_PORT_SUBTYPE_RESERVED = 0, - LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, - LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, - LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, - LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, - LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, - LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, - LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, -}; - -enum { - LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, - LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, - LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, - LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, - LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, - LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, - LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, - LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, - LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, - LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, - LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, -}; - -#define _LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) - -#define _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \ - ((uint16_t) \ - (LLDP_SYSTEM_CAPABILITIES_REPEATER| \ - LLDP_SYSTEM_CAPABILITIES_BRIDGE| \ - LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \ - LLDP_SYSTEM_CAPABILITIES_ROUTER| \ - LLDP_SYSTEM_CAPABILITIES_DOCSIS| \ - LLDP_SYSTEM_CAPABILITIES_CVLAN| \ - LLDP_SYSTEM_CAPABILITIES_SVLAN| \ - LLDP_SYSTEM_CAPABILITIES_TPMR)) - - -#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } -#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } - -enum { - LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, - LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, - LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, - LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, - LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, - LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, - LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, -}; diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index da4ce293bc..1aae2253c0 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -30,7 +30,6 @@ #include "alloc-util.h" #include "fd-util.h" #include "lldp-network.h" -#include "lldp.h" #include "macro.h" #include "string-util.h" @@ -127,12 +126,12 @@ static void test_receive_basic_packet(sd_event *e) { assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0); - assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); + assert_se(type == SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); assert_se(length == ETH_ALEN); assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN)); assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0); - assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME); + assert_se(type == SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME); assert_se(length == 3); assert_se(strneq((char *) data, "1/3", 3)); @@ -218,23 +217,23 @@ static void test_receive_oui_packet(sd_event *e) { assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0); - assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_CHASSIS_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_CHASSIS_ID) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_PORT_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_PORT_ID) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_TTL) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_TTL) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); - assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_END) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_END) > 0); assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0); sd_lldp_neighbor_unref(neighbors[0]); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 6ec7a911ca..b22a0f648a 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -33,7 +33,6 @@ #include "ether-addr-util.h" #include "fd-util.h" #include "hwdb-util.h" -#include "lldp.h" #include "local-addresses.h" #include "locale-util.h" #include "netlink-util.h" diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ff4bd76554..ae3bac217b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -26,7 +26,6 @@ #include "dhcp-lease-internal.h" #include "fd-util.h" #include "fileio.h" -#include "lldp.h" #include "netlink-util.h" #include "network-internal.h" #include "networkd-link.h" @@ -2234,8 +2233,8 @@ static int link_configure(Link *link) { r = sd_lldp_match_capabilities(link->lldp, link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ? - _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS : - _LLDP_SYSTEM_CAPABILITIES_ALL); + SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS : + SD_LLDP_SYSTEM_CAPABILITIES_ALL); if (r < 0) return r; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index ae8367a60e..5af2a31ea7 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -24,7 +24,6 @@ #include "fd-util.h" #include "fileio.h" #include "hostname-util.h" -#include "lldp.h" #include "networkd-lldp-tx.h" #include "random-util.h" #include "socket-util.h" @@ -128,51 +127,51 @@ static int lldp_make_packet( h = (struct ether_header*) packet; h->ether_type = htobe16(ETHERTYPE_LLDP); - memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN); + memcpy(h->ether_dhost, &(struct ether_addr) { SD_LLDP_MULTICAST_ADDR }, ETH_ALEN); memcpy(h->ether_shost, hwaddr, ETH_ALEN); p = (uint8_t*) packet + sizeof(struct ether_header); - r = lldp_write_tlv_header(&p, LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length); if (r < 0) return r; - *(p++) = LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED; + *(p++) = SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED; p = mempcpy(p, machine_id, machine_id_length); - r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_ID, 1 + ifname_length); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_ID, 1 + ifname_length); if (r < 0) return r; - *(p++) = LLDP_PORT_SUBTYPE_INTERFACE_NAME; + *(p++) = SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME; p = mempcpy(p, ifname, ifname_length); - r = lldp_write_tlv_header(&p, LLDP_TYPE_TTL, 2); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_TTL, 2); if (r < 0) return r; unaligned_write_be16(p, ttl); p += 2; if (port_description) { - r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_DESCRIPTION, port_description_length); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_DESCRIPTION, port_description_length); if (r < 0) return r; p = mempcpy(p, port_description, port_description_length); } if (hostname) { - r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_NAME, hostname_length); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_NAME, hostname_length); if (r < 0) return r; p = mempcpy(p, hostname, hostname_length); } if (pretty_hostname) { - r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length); if (r < 0) return r; p = mempcpy(p, pretty_hostname, pretty_hostname_length); } - r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_CAPABILITIES, 4); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4); if (r < 0) return r; unaligned_write_be16(p, system_capabilities); @@ -180,7 +179,7 @@ static int lldp_make_packet( unaligned_write_be16(p, enabled_capabilities); p += 2; - r = lldp_write_tlv_header(&p, LLDP_TYPE_END, 0); + r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_END, 0); if (r < 0) return r; @@ -200,7 +199,7 @@ static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) .ll.sll_protocol = htobe16(ETHERTYPE_LLDP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, - .ll.sll_addr = LLDP_MULTICAST_ADDR, + .ll.sll_addr = SD_LLDP_MULTICAST_ADDR, }; _cleanup_close_ int fd = -1; @@ -245,8 +244,8 @@ static int link_send_lldp(Link *link) { ttl = (usec_t) UINT16_MAX; caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ? - LLDP_SYSTEM_CAPABILITIES_ROUTER : - LLDP_SYSTEM_CAPABILITIES_STATION; + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER : + SD_LLDP_SYSTEM_CAPABILITIES_STATION; r = lldp_make_packet(&link->mac, sd_id128_to_string(machine_id, machine_id_string), @@ -255,7 +254,7 @@ static int link_send_lldp(Link *link) { link->network ? link->network->description : NULL, hostname, pretty_hostname, - LLDP_SYSTEM_CAPABILITIES_STATION|LLDP_SYSTEM_CAPABILITIES_BRIDGE|LLDP_SYSTEM_CAPABILITIES_ROUTER, + SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER, caps, &packet, &packet_size); if (r < 0) diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index f7eff58769..4f2a3b50c0 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -33,6 +33,87 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_lldp sd_lldp; typedef struct sd_lldp_neighbor sd_lldp_neighbor; +#define SD_LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } + +/* IEEE 802.3AB Clause 9: TLV Types */ +enum { + SD_LLDP_TYPE_END = 0, + SD_LLDP_TYPE_CHASSIS_ID = 1, + SD_LLDP_TYPE_PORT_ID = 2, + SD_LLDP_TYPE_TTL = 3, + SD_LLDP_TYPE_PORT_DESCRIPTION = 4, + SD_LLDP_TYPE_SYSTEM_NAME = 5, + SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6, + SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7, + SD_LLDP_TYPE_MGMT_ADDRESS = 8, + SD_LLDP_TYPE_PRIVATE = 127, +}; + +/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ +enum { + SD_LLDP_CHASSIS_SUBTYPE_RESERVED = 0, + SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, + SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, + SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3, + SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, + SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, + SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, + SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, +}; + +/* IEEE 802.3AB Clause 9.5.3: Port subtype */ +enum { + SD_LLDP_PORT_SUBTYPE_RESERVED = 0, + SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, + SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, + SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, + SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, + SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, + SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, + SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, +}; + +enum { + SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, + SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, + SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, + SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, + SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, + SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, + SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, + SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, + SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, + SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, +}; + +#define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) + +#define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \ + ((uint16_t) \ + (SD_LLDP_SYSTEM_CAPABILITIES_REPEATER| \ + SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE| \ + SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \ + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER| \ + SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS| \ + SD_LLDP_SYSTEM_CAPABILITIES_CVLAN| \ + SD_LLDP_SYSTEM_CAPABILITIES_SVLAN| \ + SD_LLDP_SYSTEM_CAPABILITIES_TPMR)) + + +#define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } +#define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } + +enum { + SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, + SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, + SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, + SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, + SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, + SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, + SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, +}; + typedef enum sd_lldp_event { SD_LLDP_EVENT_ADDED = 'a', SD_LLDP_EVENT_REMOVED = 'r', -- cgit v1.2.3-54-g00ecf From 099619957a0d9ae0e6e5e221493e40fb8fc2cd81 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Mon, 7 Dec 2015 01:10:50 +0100 Subject: cgroup2: use new fstype for unified hierarchy Since Linux v4.4-rc1, __DEVEL__sane_behavior does not exist anymore and is replaced by a new fstype "cgroup2". With this patch, systemd no longer supports the old (unstable) way of doing unified hierarchy with __DEVEL__sane_behavior and systemd now requires Linux v4.4 for unified hierarchy. Non-unified hierarchy is still the default and is unchanged by this patch. https://github.com/torvalds/linux/commit/67e9c74b8a873408c27ac9a8e4c1d1c8d72c93ff --- src/basic/cgroup-util.c | 2 +- src/basic/missing.h | 4 ++++ src/core/mount-setup.c | 2 +- src/nspawn/nspawn-cgroup.c | 2 +- src/nspawn/nspawn-mount.c | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 56c1fcaab9..5124b5bf93 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2129,7 +2129,7 @@ int cg_unified(void) { if (statfs("/sys/fs/cgroup/", &fs) < 0) return -errno; - if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC)) + if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) unified_cache = true; else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) unified_cache = false; diff --git a/src/basic/missing.h b/src/basic/missing.h index 034e334e66..66cd5921ad 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -437,6 +437,10 @@ struct btrfs_ioctl_quota_ctl_args { #define CGROUP_SUPER_MAGIC 0x27e0eb #endif +#ifndef CGROUP2_SUPER_MAGIC +#define CGROUP2_SUPER_MAGIC 0x63677270 +#endif + #ifndef TMPFS_MAGIC #define TMPFS_MAGIC 0x01021994 #endif diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index de1a361cc4..32fe51c67e 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -94,7 +94,7 @@ static const MountPoint mount_table[] = { #endif { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, NULL, MNT_FATAL|MNT_IN_CONTAINER }, - { "cgroup", "/sys/fs/cgroup", "cgroup", "__DEVEL__sane_behavior", MS_NOSUID|MS_NOEXEC|MS_NODEV, + { "cgroup", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, cg_is_unified_wanted, MNT_FATAL|MNT_IN_CONTAINER }, { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER }, diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index 9f9a4759d1..53a7ee7134 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -94,7 +94,7 @@ int sync_cgroup(pid_t pid, bool unified_requested) { if (unified) r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "none,name=systemd,xattr"); else - r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "__DEVEL__sane_behavior"); + r = mount("cgroup", tree, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); if (r < 0) { r = log_error_errno(errno, "Failed to mount unified hierarchy: %m"); goto finish; diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 70cca15278..64cb6b3ce3 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -750,7 +750,7 @@ static int mount_unified_cgroups(const char *dest) { return -EINVAL; } - if (mount("cgroup", p, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "__DEVEL__sane_behavior") < 0) + if (mount("cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0) return log_error_errno(errno, "Failed to mount unified cgroup hierarchy to %s: %m", p); return 0; -- cgit v1.2.3-54-g00ecf From ab2c3861dcbece00d1c03357556faced6e048de0 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 25 Mar 2016 11:38:50 -0400 Subject: core: update populated event handling in unified hierarchy Earlier during the development of unified hierarchy, the populated event was reported through by the dedicated "cgroup.populated" file; however, the interface was updated so that it's reported through the "populated" field of "cgroup.events" file. Update populated event handling logic accordingly. --- src/basic/cgroup-util.c | 45 ++++++++++++++++++++++++++++++++++++--------- src/basic/cgroup-util.h | 2 ++ src/core/cgroup.c | 6 +++--- src/nspawn/nspawn-cgroup.c | 3 +-- 4 files changed, 42 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 5124b5bf93..5043180747 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -101,6 +101,39 @@ int cg_read_pid(FILE *f, pid_t *_pid) { return 1; } +int cg_read_event(const char *controller, const char *path, const char *event, + char **val) +{ + _cleanup_free_ char *events = NULL, *content = NULL; + char *p, *line; + int r; + + r = cg_get_path(controller, path, "cgroup.events", &events); + if (r < 0) + return r; + + r = read_full_file(events, &content, NULL); + if (r < 0) + return r; + + p = content; + while ((line = strsep(&p, "\n"))) { + char *key; + + key = strsep(&line, " "); + if (!key || !line) + return -EINVAL; + + if (strcmp(key, event)) + continue; + + *val = strdup(line); + return 0; + } + + return -ENOENT; +} + int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) { _cleanup_free_ char *fs = NULL; int r; @@ -1007,18 +1040,12 @@ int cg_is_empty_recursive(const char *controller, const char *path) { return unified; if (unified > 0) { - _cleanup_free_ char *populated = NULL, *t = NULL; + _cleanup_free_ char *t = NULL; /* On the unified hierarchy we can check empty state - * via the "cgroup.populated" attribute. */ + * via the "populated" attribute of "cgroup.events". */ - r = cg_get_path(controller, path, "cgroup.populated", &populated); - if (r < 0) - return r; - - r = read_one_line_file(populated, &t); - if (r == -ENOENT) - return 1; + r = cg_read_event(controller, path, "populated", &t); if (r < 0) return r; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index ad1edd9cdb..4254e51e5d 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -96,6 +96,8 @@ static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) { int cg_enumerate_processes(const char *controller, const char *path, FILE **_f); int cg_read_pid(FILE *f, pid_t *_pid); +int cg_read_event(const char *controller, const char *path, const char *event, + char **val); int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d); int cg_read_subgroup(DIR *d, char **fn); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 39235a95f6..9c34928052 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -765,7 +765,7 @@ int unit_set_cgroup_path(Unit *u, const char *path) { } int unit_watch_cgroup(Unit *u) { - _cleanup_free_ char *populated = NULL; + _cleanup_free_ char *events = NULL; int r; assert(u); @@ -791,11 +791,11 @@ int unit_watch_cgroup(Unit *u) { if (r < 0) return log_oom(); - r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated); + r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events", &events); if (r < 0) return log_oom(); - u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY); + u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, events, IN_MODIFY); if (u->cgroup_inotify_wd < 0) { if (errno == ENOENT) /* If the directory is already diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index 53a7ee7134..f50f1ad6c2 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -55,8 +55,7 @@ int chown_cgroup(pid_t pid, uid_t uid_shift) { "cgroup.events", "cgroup.clone_children", "cgroup.controllers", - "cgroup.subtree_control", - "cgroup.populated") + "cgroup.subtree_control") if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to chown() cgroup file %s, ignoring: %m", fn); -- cgit v1.2.3-54-g00ecf From e57051f542080a4ec1d9e4e1c428b39defe9f098 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 25 Mar 2016 11:38:50 -0400 Subject: core: update invoke_sigchld_event() to handle NULL ->sigchld_event() After receiving SIGCHLD, one of the ways manager_dispatch_sigchld() maps the now zombie $PID to its unit is through manager_get_unit_by_pid_cgroup() which reads /proc/$PID/cgroup and looks up the unit associated with the cgroup path. On non-unified cgroup hierarchies, a process is immediately migrated to the root cgroup on death and the cgroup lookup would always have returned the unit associated with it, making it rather pointless but safe. On unified hierarchy, a zombie remains associated with the cgroup that it was associated with at the time of death and thus manager_get_unit_by_pid_cgroup() will look up the unit properly. However, by the time manager_dispatch_sigchld() is running, the original cgroup may have become empty and it and its associated unit might already have been removed. If the cgroup path doesn't yield a match, manager_dispatch_sigchld() keeps pruning the leaf component. This means that the function may return a slice unit for a pid and as a slice doesn't have ->sigchld_event() handler, calling invoke_sigchld_event() on it causes a segfault. This patch updates invoke_sigchld_event() so that it skips calling if the handler is not set. --- src/core/manager.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index f13e933578..78f2a21061 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1631,7 +1631,9 @@ static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) { 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); + + if (UNIT_VTABLE(u)->sigchld_event) + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); } static int manager_dispatch_sigchld(Manager *m) { -- cgit v1.2.3-54-g00ecf From b68f10bf1f7519e012da5e35fab3a57da7dc46d4 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 27 Mar 2016 17:33:54 -0400 Subject: build-sys: fix build with libgrcypt disabled - Move gcrypt.h include inside grcrypt-util.h. - Allow gcrypt-util.[ch] to be compiled even without gcrypt. This allows the logic in files using gcrypt to be simplified. - Fix compilation of systemd-resolve without gcrypt. systemd-resolved already supported that. Fixes #2711. --- Makefile.am | 8 ++++---- src/resolve/resolve-tool.c | 3 +-- src/shared/gcrypt-util.c | 4 +++- src/shared/gcrypt-util.h | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 2b72a53ecd..95eaa9af1a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4262,7 +4262,9 @@ libsystemd_journal_internal_la_SOURCES = \ src/journal/mmap-cache.h \ src/journal/compress.c \ src/journal/audit-type.h \ - src/journal/audit-type.c + src/journal/audit-type.c \ + src/shared/gcrypt-util.h \ + src/shared/gcrypt-util.c nodist_libsystemd_journal_internal_la_SOURCES = \ src/journal/audit_type-to-name.h @@ -4294,9 +4296,7 @@ libsystemd_journal_internal_la_SOURCES += \ src/journal/journal-authenticate.c \ src/journal/journal-authenticate.h \ src/journal/fsprg.c \ - src/journal/fsprg.h \ - src/shared/gcrypt-util.c \ - src/shared/gcrypt-util.h + src/journal/fsprg.h libsystemd_journal_internal_la_LIBADD += \ $(GCRYPT_LIBS) diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 009cc73aec..14ee01c49d 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -17,7 +17,6 @@ along with systemd; If not, see . ***/ -#include #include #include @@ -863,7 +862,7 @@ static int resolve_openpgp(sd_bus *bus, const char *address) { } domain++; - r = string_hashsum(address, domain - 1 - address, GCRY_MD_SHA224, &hashed); + r = string_hashsum_sha224(address, domain - 1 - address, &hashed); if (r < 0) return log_error_errno(r, "Hashing failed: %m"); diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c index 4ff94520c3..39b544b6f0 100644 --- a/src/shared/gcrypt-util.c +++ b/src/shared/gcrypt-util.c @@ -19,10 +19,11 @@ along with systemd; If not, see . ***/ +#ifdef HAVE_GCRYPT #include -#include "hexdecoct.h" #include "gcrypt-util.h" +#include "hexdecoct.h" void initialize_libgcrypt(bool secmem) { const char *p; @@ -67,3 +68,4 @@ int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) { *out = enc; return 0; } +#endif diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h index c7652c22d1..cf33b3c59c 100644 --- a/src/shared/gcrypt-util.h +++ b/src/shared/gcrypt-util.h @@ -19,7 +19,21 @@ along with systemd; If not, see . ***/ +#include #include +#include + +#ifdef HAVE_GCRYPT +#include void initialize_libgcrypt(bool secmem); int string_hashsum(const char *s, size_t len, int md_algorithm, char **out); +#endif + +static inline int string_hashsum_sha224(const char *s, size_t len, char **out) { +#ifdef HAVE_GCRYPT + return string_hashsum(s, len, GCRY_MD_SHA224, out); +#else + return -EOPNOTSUPP; +#endif +} -- cgit v1.2.3-54-g00ecf From f0634dd1751c752b0760fd3965e790b08f456080 Mon Sep 17 00:00:00 2001 From: Biao Lu Date: Tue, 29 Mar 2016 01:46:04 +0800 Subject: shared: fix a misspelling of "journalctl" --- src/shared/bus-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index b102a79da8..90b312a1a7 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -2030,7 +2030,7 @@ static const struct { static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) { _cleanup_free_ char *service_shell_quoted = NULL; - const char *systemctl = "systemctl", *journalctl = "journalct"; + const char *systemctl = "systemctl", *journalctl = "journalctl"; assert(service); -- cgit v1.2.3-54-g00ecf From 947292eef49546db1379cfdf3a63bf7396d4a835 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 28 Mar 2016 17:17:32 +0000 Subject: core: RuntimeWatchdogSec=infinity disables the watchdog logic --- src/core/main.c | 2 +- src/core/manager.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index 78701805ea..e4e025e34e 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1664,7 +1664,7 @@ int main(int argc, char *argv[]) { test_usr(); } - if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0) + if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY) watchdog_set_timeout(&arg_runtime_watchdog); if (arg_timer_slack_nsec != NSEC_INFINITY) diff --git a/src/core/manager.c b/src/core/manager.c index f13e933578..26cb588e30 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2016,7 +2016,7 @@ int manager_loop(Manager *m) { while (m->exit_code == MANAGER_OK) { usec_t wait_usec; - if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) + if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) watchdog_ping(); if (!ratelimit_test(&rl)) { @@ -2041,7 +2041,7 @@ int manager_loop(Manager *m) { continue; /* Sleep for half the watchdog time */ - if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) { + if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) { wait_usec = m->runtime_watchdog / 2; if (wait_usec <= 0) wait_usec = 1; -- cgit v1.2.3-54-g00ecf From 5146c61928de60bbedb81c5f4f47bf06528722a5 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Tue, 29 Mar 2016 11:04:04 +0000 Subject: core: ShutdownWatchdogSec=infinity disables the watchdog logic too This is a follow-up for 947292eef --- src/core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index e4e025e34e..56df32426a 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2095,7 +2095,7 @@ finish: assert(pos < ELEMENTSOF(command_line)); - if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) { + if (arm_reboot_watchdog && arg_shutdown_watchdog > 0 && arg_shutdown_watchdog != USEC_INFINITY) { char *e; /* If we reboot let's set the shutdown -- cgit v1.2.3-54-g00ecf From 5d512d54429aa9d2f4a0ca215bb2e982db720d6b Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Wed, 30 Mar 2016 13:49:50 +0200 Subject: core: improve error message when starting template without instance --- src/core/manager.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 14ee68a3d2..e739795e70 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1333,8 +1333,12 @@ int manager_load_unit_prepare( t = unit_name_to_type(name); - if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { + if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is missing the instance name.", name); + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + } ret = manager_get_unit(m, name); if (ret) { -- cgit v1.2.3-54-g00ecf From 413708d106afb5ec36464c3fad56f081373320e0 Mon Sep 17 00:00:00 2001 From: Vinay Kulkarni Date: Wed, 30 Mar 2016 16:33:55 -0700 Subject: DHCP DUID, IAID configuration options --- Makefile-man.am | 7 ++ Makefile.am | 4 + man/networkd.conf.xml | 159 ++++++++++++++++++++++++++++++ man/systemd.network.xml | 86 ++++++++++++++++ src/libsystemd-network/dhcp-identifier.c | 2 +- src/libsystemd-network/dhcp-identifier.h | 41 +++++++- src/libsystemd-network/dhcp6-protocol.h | 7 -- src/libsystemd-network/network-internal.c | 29 ++++++ src/libsystemd-network/network-internal.h | 4 + src/libsystemd-network/sd-dhcp-client.c | 48 ++++++++- src/libsystemd-network/sd-dhcp6-client.c | 48 ++++----- src/network/networkd-conf.c | 155 +++++++++++++++++++++++++++++ src/network/networkd-conf.h | 36 +++++++ src/network/networkd-dhcp4.c | 16 ++- src/network/networkd-dhcp6.c | 17 ++++ src/network/networkd-gperf.gperf | 18 ++++ src/network/networkd-link.c | 33 +++++++ src/network/networkd-manager.c | 2 + src/network/networkd-network-gperf.gperf | 4 + src/network/networkd-network.c | 2 + src/network/networkd-network.h | 8 ++ src/network/networkd.c | 5 + src/network/networkd.h | 8 ++ src/systemd/sd-dhcp-client.h | 2 + src/systemd/sd-dhcp6-client.h | 5 +- 25 files changed, 703 insertions(+), 43 deletions(-) create mode 100644 man/networkd.conf.xml create mode 100644 src/network/networkd-conf.c create mode 100644 src/network/networkd-conf.h create mode 100644 src/network/networkd-gperf.gperf (limited to 'src') diff --git a/Makefile-man.am b/Makefile-man.am index 3f03afc2ef..a7e348b1f1 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -1960,15 +1960,21 @@ endif if ENABLE_NETWORKD MANPAGES += \ man/networkctl.1 \ + man/networkd.conf.5 \ man/systemd-networkd-wait-online.service.8 \ man/systemd-networkd.service.8 \ man/systemd.netdev.5 \ man/systemd.network.5 MANPAGES_ALIAS += \ + man/networkd.conf.d.5 \ man/systemd-networkd-wait-online.8 \ man/systemd-networkd.8 +man/networkd.conf.d.5: man/networkd.conf.5 man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8 man/systemd-networkd.8: man/systemd-networkd.service.8 +man/networkd.conf.d.html: man/networkd.conf.html + $(html-alias) + man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html $(html-alias) @@ -2479,6 +2485,7 @@ EXTRA_DIST += \ man/machinectl.xml \ man/modules-load.d.xml \ man/networkctl.xml \ + man/networkd.conf.xml \ man/nss-myhostname.xml \ man/nss-mymachines.xml \ man/nss-resolve.xml \ diff --git a/Makefile.am b/Makefile.am index 2b72a53ecd..350416af30 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5398,6 +5398,8 @@ libnetworkd_core_la_CFLAGS = \ libnetworkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ + src/network/networkd-conf.h \ + src/network/networkd-conf.c \ src/network/networkd-link.h \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ @@ -5446,6 +5448,7 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-lldp-tx.c nodist_libnetworkd_core_la_SOURCES = \ + src/network/networkd-gperf.c \ src/network/networkd-network-gperf.c \ src/network/networkd-netdev-gperf.c @@ -5542,6 +5545,7 @@ BUSNAMES_TARGET_WANTS += \ endif gperf_gperf_sources += \ + src/network/networkd-gperf.gperf \ src/network/networkd-network-gperf.gperf \ src/network/networkd-netdev-gperf.gperf diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml new file mode 100644 index 0000000000..30674e12bc --- /dev/null +++ b/man/networkd.conf.xml @@ -0,0 +1,159 @@ + + + + + + + + networkd.conf + systemd + + + + Developer + Vinay + Kulkarni + kulkarniv@vmware.com + + + + + + networkd.conf + 5 + + + + networkd.conf + networkd.conf.d + Global Network configuration files + + + + /etc/systemd/networkd.conf + /etc/systemd/networkd.conf.d/*.conf + /usr/lib/systemd/networkd.conf.d/*.conf + + + + Description + + These configuration files control global network parameters. + For e.g. DHCP Unique Identifier (DUID). + + + + + + + [DUID] Section Options + + This section configures the DHCP Unique Idendifier (DUID) value used by DHCP + protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface + Identity Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 + address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring + a dynamic IPv4 address if . IAID and DUID allows + a DHCP server to uniquely identify the machine and the interface requesting a DHCP IP. + To configure IAID and ClientIdentifier, see systemd.network + 5. + + The DUID value specified here overrides the DUID that systemd-networkd + generates using the machine-id from the /etc/machine-id file. + To configure DUID per-network, see systemd.network + 5. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. To configure IAID, see + systemd.network5 + . + + The following options are available in [DUID] section: + + + + + Type= + The type of DUID specified in this section. The following values are + supported: + raw : If Type=raw, then RawData= specifies + the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and + RawData is specified, Type defaults to 'raw'. + Type will support the following values in the future: + link-layer-and-time : If Type=link-layer-and-time, then + MACAddress= and TimeStamp= specify the hardware + address and time-stamp for DUID-LLT. + vendor : If Type=vendor, then EnterpriseNumber= + and RawData= specify the enterprise number and identifier for DUID-EN. + link-layer : If Type=link-layer, then MACAddress= + specifies the hardware address for DUID-LL. + uuid : If Type=uuid, then UUID= specifies DUID-UUID. + + + + + RawData= + Specifies the DUID bytes as a single newline-terminated, hexadecimal + string, with each byte separated by a ':'. + + + + + + The following options will be supported in the future: + + + + MACAddress= + Specifies the link-layer address for DUID Type or . + + + TimeStamp= + Specifies the DUID generation time for DUID Type . + + + EnterpriseNumber= + Specifies the enterprise number for DUID Type + . + + + UUID= + Specifies the UUID for DUID Type . + + + + + + + See Also + + systemd1, + systemd.network5, + machine-id1 + + + + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index f2e715cf6f..8611c0032d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -204,6 +204,12 @@ understood to the base of 1024. + + IAIDValue= + + Identity Association Identifier for the interface, a 32-bit unsigned integer. + + @@ -823,6 +829,86 @@ + + [DUID] Section Options + + This section configures the DHCP Unique Idendifier (DUID) value used by DHCP + protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface + Identity Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 + address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring + a dynamic IPv4 address if . IAID and DUID allows a + DHCP server to uniquely identify the machine and the interface requesting a DHCP IP. + + The DUID value specified here overrides the DUID that systemd-networkd generates + using the machine-id from the /etc/machine-id file, as well as the + global DUID that may be specified in networkd.conf + 5. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. + + The following options are available in [DUID] section: + + + + + Type= + The type of DUID specified in this section. The following values are + supported: + raw : If Type=raw, then RawData= specifies + the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and + RawData is specified, Type defaults to 'raw'. + Type will support the following values in the future: + link-layer-and-time : If Type=link-layer-and-time, then + MACAddress= and TimeStamp= specify the hardware + address and time-stamp for DUID-LLT. + vendor : If Type=vendor, then EnterpriseNumber= + and RawData= specify the enterprise number and identifier for DUID-EN. + link-layer : If Type=link-layer, then MACAddress= + specifies the hardware address for DUID-LL. + uuid : If Type=uuid, then UUID= specifies DUID-UUID. + + + + + RawData= + Specifies the DUID bytes as a single newline-terminated, hexadecimal + string, with each byte separated by a ':'. + + + + + + + The following options will be supported in the future: + + + + MACAddress= + Specifies the link-layer address for DUID Type or . + + + TimeStamp= + Specifies the DUID generation time for DUID Type . + + + EnterpriseNumber= + Specifies the enterprise number for DUID Type . + + + UUID= + Specifies the UUID for DUID Type . + + + + + [DHCPServer] Section Options The [DHCPServer] section contains diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1d9ec7be82..4f7d4d8bf2 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP6_DUID_EN); + unaligned_write_be16(&duid->type, DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 93f06f5938..babae15c5b 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,13 +25,23 @@ #include "sparse-endian.h" #include "unaligned.h" +typedef enum DUIDType { + DUID_TYPE_RAW = 0, + DUID_TYPE_LLT = 1, + DUID_TYPE_EN = 2, + DUID_TYPE_LL = 3, + DUID_TYPE_UUID = 4, + _DUID_TYPE_MAX, + _DUID_TYPE_INVALID = -1, +} DUIDType; + /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - uint16_t type; + be16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -61,3 +71,32 @@ struct duid { 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, void *_id); + +static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { + struct duid d; + + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + + switch (duid_type) { + case DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index ee4bdfb07f..2487c470ab 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,13 +62,6 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC -enum { - DHCP6_DUID_LLT = 1, - DHCP6_DUID_EN = 2, - DHCP6_DUID_LL = 3, - DHCP6_DUID_UUID = 4, -}; - enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index cb7252bbeb..0e2d757b2b 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,6 +335,35 @@ int config_parse_hwaddr(const char *unit, return 0; } +int config_parse_iaid(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) { + uint32_t iaid; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou32(rvalue, &iaid); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); + return r; + } + + *((uint32_t *)data) = iaid; + + return 0; +} + void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index c8a531ab0f..72432774d7 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,6 +62,10 @@ int config_parse_ifalias(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_iaid(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 net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 1188b31500..287b6e26fa 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - uint32_t iaid; + be32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -298,6 +298,52 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, + uint16_t duid_type, uint8_t *duid, size_t duid_len) { + DHCP_CLIENT_DONT_DESTROY(client); + int r; + assert_return(client, -EINVAL); + zero(client->client_id); + + client->client_id.type = 255; + + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = htobe32(iaid); + + /* If DUID is not configured, generate DUID-EN. */ + if (duid_len == 0) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, + &duid_len); + if (r < 0) + return r; + } else { + r = dhcp_validate_duid_len(client->client_id.type, duid_len); + if (r < 0) + return r; + client->client_id.ns.duid.type = htobe16(duid_type); + memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); + duid_len += sizeof(client->client_id.ns.duid.type); + } + + client->client_id_len = sizeof(client->client_id.type) + duid_len + + sizeof(client->client_id.ns.iaid); + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Configured IAID+DUID, restarting."); + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + sd_dhcp_client_start(client); + } + + return 0; +} + int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index af4709d788..ee4fb4fc1e 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -180,41 +180,29 @@ static int client_ensure_duid(sd_dhcp6_client *client) { 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) { +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, + uint8_t *duid, size_t duid_len) { + int r; assert_return(client, -EINVAL); - assert_return(duid, -EINVAL); - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - switch (type) { - case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt)) - return -EINVAL; - break; - case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en)) - return -EINVAL; - break; - case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll)) - return -EINVAL; - break; - case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; + if (duid_len > 0) { + r = dhcp_validate_duid_len(duid_type, duid_len); + if (r < 0) + return r; + client->duid.type = htobe16(duid_type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len + sizeof(client->duid.type); } - client->duid.type = htobe16(type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); + return 0; +} + +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->ia_na.id = htobe32(iaid); return 0; } diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c new file mode 100644 index 0000000000..8b149124b3 --- /dev/null +++ b/src/network/networkd-conf.c @@ -0,0 +1,155 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Vinay Kulkarni + + 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 . + ***/ + +#include + +#include "conf-parser.h" +#include "def.h" +#include "dhcp-identifier.h" +#include "networkd-conf.h" +#include "string-table.h" + +int manager_parse_config_file(Manager *m) { + assert(m); + + return config_parse_many(PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "DUID\0", + config_item_perf_lookup, networkd_gperf_lookup, + false, m); +} + +static const char* const duid_type_table[_DUID_TYPE_MAX] = { + [DUID_TYPE_RAW] = "raw", + [DUID_TYPE_LLT] = "link-layer-time", + [DUID_TYPE_EN] = "vendor", + [DUID_TYPE_LL] = "link-layer", + [DUID_TYPE_UUID] = "uuid" +}; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); +DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type"); + +int config_parse_duid_rawdata( + 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 r; + long byte; + char *cbyte, *pnext; + const char *pduid = rvalue; + size_t count = 0, duid_index = 0; + Manager *m; + Network *n; + DUIDType *duid_type; + uint16_t *dhcp_duid_type; + size_t *dhcp_duid_len; + uint8_t *dhcp_duid; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(userdata); + + if (ltype == DUID_CONFIG_SOURCE_GLOBAL) { + m = userdata; + duid_type = &m->duid_type; + dhcp_duid_type = &m->dhcp_duid_type; + dhcp_duid_len = &m->dhcp_duid_len; + dhcp_duid = m->dhcp_duid; + } else { + /* DUID_CONFIG_SOURCE_NETWORK */ + n = userdata; + duid_type = &n->duid_type; + dhcp_duid_type = &n->dhcp_duid_type; + dhcp_duid_len = &n->dhcp_duid_len; + dhcp_duid = n->dhcp_duid; + } + + if (*duid_type == _DUID_TYPE_INVALID) + *duid_type = DUID_TYPE_RAW; + + switch (*duid_type) { + case DUID_TYPE_LLT: + /* RawData contains DUID-LLT link-layer address (offset 6) */ + duid_index = 6; + break; + case DUID_TYPE_EN: + /* RawData contains DUID-EN identifier (offset 4) */ + duid_index = 4; + break; + case DUID_TYPE_LL: + /* RawData contains DUID-LL link-layer address (offset 2) */ + duid_index = 2; + break; + case DUID_TYPE_UUID: + /* RawData specifies UUID (offset 0) - fall thru */ + case DUID_TYPE_RAW: + /* First two bytes of RawData is DUID Type - fall thru */ + default: + break; + } + + if (*duid_type != DUID_TYPE_RAW) + *dhcp_duid_type = (uint16_t)(*duid_type); + + /* RawData contains DUID in format " NN:NN:NN... " */ + while (true) { + r = extract_first_word(&pduid, &cbyte, ":", 0); + if (r < 0) { + log_error("Failed to read DUID."); + return -EINVAL; + } + if (r == 0) + break; + if (duid_index >= MAX_DUID_LEN) { + log_error("DUID length exceeds maximum length."); + return -EINVAL; + } + + errno = 0; + byte = strtol(cbyte, &pnext, 16); + if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) + || (errno != 0 && byte == 0) || (cbyte == pnext)) { + log_error("Invalid DUID byte: %s.", cbyte); + return -EINVAL; + } + + /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ + if ((*duid_type == DUID_TYPE_RAW) && (count < 2)) { + *dhcp_duid_type |= (byte << (8 * (1 - count))); + count++; + continue; + } + + dhcp_duid[duid_index++] = byte; + } + + *dhcp_duid_len = duid_index; + + return 0; +} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h new file mode 100644 index 0000000000..efc370f839 --- /dev/null +++ b/src/network/networkd-conf.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Vinay Kulkarni + + 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 . +***/ + +#include "networkd.h" + +typedef enum DuidConfigSource { + DUID_CONFIG_SOURCE_GLOBAL = 0, + DUID_CONFIG_SOURCE_NETWORK, +} DuidConfigSource; + +int manager_parse_config_file(Manager *m); + +const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); + +int config_parse_duid_type(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_duid_rawdata(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-dhcp4.c b/src/network/networkd-dhcp4.c index 68998eabf2..0589ebf227 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -625,7 +625,21 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* Library defaults to this. */ + /* If configured, apply user specified DUID and/or IAID */ + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return r; break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 5f7a005c36..d4b2fbfc57 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,6 +230,23 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; + r = sd_dhcp6_client_set_iaid(client, link->network->iaid); + if (r < 0) + goto error; + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp6_client_set_duid(client, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp6_client_set_duid(client, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + goto error; + r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf new file mode 100644 index 0000000000..0625fb335b --- /dev/null +++ b/src/network/networkd-gperf.gperf @@ -0,0 +1,18 @@ +%{ +#include +#include "conf-parser.h" +#include "networkd-conf.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name networkd_gperf_hash +%define lookup-function-name networkd_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +DUID.Type, config_parse_duid_type, 0, offsetof(Manager, duid_type) +DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ff4bd76554..eac8123311 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2781,6 +2781,21 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2790,6 +2805,24 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); + + r = sd_dhcp6_client_set_iaid(link->dhcp6_client, + link->network->iaid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); + + if (link->network->duid_type != _DUID_TYPE_INVALID) + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->network->dhcp_duid_type, + link->network->dhcp_duid, + link->network->dhcp_duid_len); + else + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->manager->dhcp_duid_type, + link->manager->dhcp_duid, + link->manager->dhcp_duid_len); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b8cb7f875d..d355aaa19c 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,6 +1037,8 @@ int manager_new(Manager **ret) { if (r < 0) return r; + m->duid_type = _DUID_TYPE_INVALID; + *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a5d1714293..9793938080 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -2,6 +2,7 @@ #include #include "conf-parser.h" #include "networkd.h" +#include "networkd-conf.h" #include "network-internal.h" %} struct ConfigPerfItem; @@ -26,6 +27,9 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid) +DUID.Type, config_parse_duid_type, 0, offsetof(Network, duid_type) +DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 491b9a3efa..5946ba18dc 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -131,10 +131,12 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_accept_ra = -1; network->ipv6_dad_transmits = -1; network->ipv6_hop_limit = -1; + network->duid_type = _DUID_TYPE_INVALID; r = config_parse(NULL, filename, file, "Match\0" "Link\0" + "DUID\0" "Network\0" "Address\0" "Route\0" diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 4a13e2b574..5400a8bc9d 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -24,6 +24,7 @@ typedef struct Network Network; +#include "dhcp-identifier.h" #include "networkd-address.h" #include "networkd-fdb.h" #include "networkd-netdev.h" @@ -144,6 +145,13 @@ struct Network { struct ether_addr *mac; unsigned mtu; + uint32_t iaid; + /* Value of Type in [DUID] section */ + DUIDType duid_type; + /* DUID type code - RFC 3315 */ + uint16_t dhcp_duid_type; + size_t dhcp_duid_len; + uint8_t dhcp_duid[MAX_DUID_LEN]; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.c b/src/network/networkd.c index 3a2615e6fd..c8f81a2ca6 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,6 +21,7 @@ #include "capability-util.h" #include "networkd.h" +#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -89,6 +90,10 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_parse_config_file(m); + if (r < 0) + log_warning_errno(r, "Failed to parse configuration file: %m"); + r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index 6bdd8302a0..72a2438ac8 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -31,6 +31,7 @@ typedef struct Manager Manager; +#include "dhcp-identifier.h" #include "networkd-address-pool.h" #include "networkd-link.h" #include "networkd-network.h" @@ -61,6 +62,13 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; + + /* Value of Type in [DUID] section */ + DUIDType duid_type; + /* DUID type code - RFC 3315 */ + uint16_t dhcp_duid_type; + size_t dhcp_duid_len; + uint8_t dhcp_duid[MAX_DUID_LEN]; }; extern const char* const network_dirs[]; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index ef45370505..374ff8774e 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -98,6 +98,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, + uint16_t duid_type, uint8_t *duid, size_t duid_len); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 1bedc941aa..4604cb6382 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -85,8 +85,9 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, + uint8_t *duid, size_t duid_len); +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, -- cgit v1.2.3-54-g00ecf From 21b95806b88bd645a7ded8274240f37fb65ea150 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 31 Mar 2016 00:08:34 -0400 Subject: core/unit: extract checking of stat paths into helper function The same code was repeated three times. --- src/core/unit.c | 58 +++++++++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index af38beb0c3..64d5ed04c9 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2924,34 +2924,32 @@ int unit_coldplug(Unit *u) { return 0; } +static bool fragment_mtime_changed(const char *path, usec_t mtime) { + struct stat st; + + if (!path) + return false; + + if (stat(path, &st) < 0) + /* What, cannot access this anymore? */ + return true; + + if (mtime > 0 && timespec_load(&st.st_mtim) != mtime) + return true; + + return false; +} + bool unit_need_daemon_reload(Unit *u) { _cleanup_strv_free_ char **t = NULL; char **path; - struct stat st; unsigned loaded_cnt, current_cnt; assert(u); - if (u->fragment_path) { - zero(st); - if (stat(u->fragment_path, &st) < 0) - /* What, cannot access this anymore? */ - return true; - - if (u->fragment_mtime > 0 && - timespec_load(&st.st_mtim) != u->fragment_mtime) - return true; - } - - if (u->source_path) { - zero(st); - if (stat(u->source_path, &st) < 0) - return true; - - if (u->source_mtime > 0 && - timespec_load(&st.st_mtim) != u->source_mtime) - return true; - } + if (fragment_mtime_changed(u->fragment_path, u->fragment_mtime) || + fragment_mtime_changed(u->source_path, u->source_mtime)) + return true; (void) unit_find_dropin_paths(u, &t); loaded_cnt = strv_length(t); @@ -2962,21 +2960,15 @@ bool unit_need_daemon_reload(Unit *u) { return false; if (strv_overlap(u->dropin_paths, t)) { - STRV_FOREACH(path, u->dropin_paths) { - zero(st); - if (stat(*path, &st) < 0) - return true; - - if (u->dropin_mtime > 0 && - timespec_load(&st.st_mtim) > u->dropin_mtime) + STRV_FOREACH(path, u->dropin_paths) + if (fragment_mtime_changed(*path, u->dropin_mtime)) return true; - } return false; - } else - return true; - } else - return true; + } + } + + return true; } void unit_reset_failed(Unit *u) { -- cgit v1.2.3-54-g00ecf From 3a8db9fe81b3f7faae7f09c4ac7d2c863bf0177d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 31 Mar 2016 00:22:33 -0400 Subject: core: treat masked files as "unchanged" systemctl prints the "unit file changed on disk" warning for a masked unit. I think it's better to print nothing in that case. When a masked unit is loaded, set mtime as 0. When checking if a unit with mtime of 0 needs reload, check that the mask is still in place. --- src/core/load-fragment.c | 8 ++++---- src/core/unit.c | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d078924c5b..f1a874cfdf 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3620,10 +3620,12 @@ static int load_from_path(Unit *u, const char *path) { if (fstat(fileno(f), &st) < 0) return -errno; - if (null_or_empty(&st)) + if (null_or_empty(&st)) { u->load_state = UNIT_MASKED; - else { + u->fragment_mtime = 0; + } else { u->load_state = UNIT_LOADED; + u->fragment_mtime = timespec_load(&st.st_mtim); /* Now, parse the file contents */ r = config_parse(u->id, filename, f, @@ -3638,8 +3640,6 @@ static int load_from_path(Unit *u, const char *path) { u->fragment_path = filename; filename = NULL; - u->fragment_mtime = timespec_load(&st.st_mtim); - if (u->source_path) { if (stat(u->source_path, &st) >= 0) u->source_mtime = timespec_load(&st.st_mtim); diff --git a/src/core/unit.c b/src/core/unit.c index 64d5ed04c9..70175557f7 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2934,7 +2934,11 @@ static bool fragment_mtime_changed(const char *path, usec_t mtime) { /* What, cannot access this anymore? */ return true; - if (mtime > 0 && timespec_load(&st.st_mtim) != mtime) + if (mtime > 0) + /* For non-empty files check the mtime */ + return timespec_load(&st.st_mtim) != mtime; + else if (!null_or_empty(&st)) + /* For masked files check if they are still so */ return true; return false; -- cgit v1.2.3-54-g00ecf From 1691cfd8d995607f2d1eda460525011edf601192 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 31 Mar 2016 00:37:27 -0400 Subject: test-dnssec: fix build without gcrypt Also reorder the test functions to follow the way they are called from main(). --- src/resolve/test-dnssec.c | 274 +++++++++++++++++++++++----------------------- 1 file changed, 140 insertions(+), 134 deletions(-) (limited to 'src') diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index c9b5ffa62b..155be9946f 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -27,77 +27,89 @@ #include "string-util.h" #include "hexdecoct.h" -static void test_dnssec_verify_rrset2(void) { +static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { + char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; - static const uint8_t signature_blob[] = { - 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, - 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, - 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca, - 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2, - 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda, - 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27, - 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50, - 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22, - }; + assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); + if (r < 0) + return; + assert_se(streq(canonicalized, canonical)); +} + +static void test_dnssec_canonicalize(void) { + test_dnssec_canonicalize_one("", ".", 1); + test_dnssec_canonicalize_one(".", ".", 1); + test_dnssec_canonicalize_one("foo", "foo.", 4); + test_dnssec_canonicalize_one("foo.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); + test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); +} + +#ifdef HAVE_GCRYPT + +static void test_dnssec_verify_dns_key(void) { + + static const uint8_t ds1_fprint[] = { + 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, + 0x80, 0x67, 0x14, 0x01, + }; + static const uint8_t ds2_fprint[] = { + 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, + 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, + }; static const uint8_t dnskey_blob[] = { - 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea, - 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3, - 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07, - 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5, - 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7, - 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56, - 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e, - 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49, - 0x74, 0x62, 0xfe, 0xd7, + 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, + 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, + 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, + 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, + 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, + 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, + 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, + 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, + 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, + 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, + 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, + 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, + 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, + 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, + 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, + 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, + 0xe7, 0xea, 0x77, 0x03, }; - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - DnssecResult result; - - nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); - assert_se(nsec); + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; - nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov"); - assert_se(nsec->nsec.next_domain_name); + /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ + ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); + assert_se(ds1); - nsec->nsec.types = bitmap_new(); - assert_se(nsec->nsec.types); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0); - assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0); + ds1->ds.key_tag = 47857; + ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; + ds1->ds.digest_size = sizeof(ds1_fprint); + ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); + assert_se(ds1->ds.digest); - log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec))); + log_info("DS1: %s", strna(dns_resource_record_to_string(ds1))); - rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); - assert_se(rrsig); + ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); + assert_se(ds2); - rrsig->rrsig.type_covered = DNS_TYPE_NSEC; - rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; - rrsig->rrsig.labels = 2; - rrsig->rrsig.original_ttl = 300; - rrsig->rrsig.expiration = 0x5689002f; - rrsig->rrsig.inception = 0x56617230; - rrsig->rrsig.key_tag = 30390; - rrsig->rrsig.signer = strdup("Nasa.Gov."); - assert_se(rrsig->rrsig.signer); - rrsig->rrsig.signature_size = sizeof(signature_blob); - rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); - assert_se(rrsig->rrsig.signature); + ds2->ds.key_tag = 47857; + ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; + ds2->ds.digest_size = sizeof(ds2_fprint); + ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); + assert_se(ds2->ds.digest); - log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + log_info("DS2: %s", strna(dns_resource_record_to_string(ds2))); - dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); assert_se(dnskey); - dnskey->dnskey.flags = 256; + dnskey->dnskey.flags = 257; dnskey->dnskey.protocol = 3; dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; dnskey->dnskey.key_size = sizeof(dnskey_blob); @@ -107,16 +119,8 @@ static void test_dnssec_verify_rrset2(void) { log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); - assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0); - assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); - - answer = dns_answer_new(1); - assert_se(answer); - assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); - - /* Validate the RR as it if was 2015-12-11 today */ - assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); - assert_se(result == DNSSEC_VALIDATED); + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0); + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); } static void test_dnssec_verify_rrset(void) { @@ -198,67 +202,78 @@ static void test_dnssec_verify_rrset(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_verify_dns_key(void) { +static void test_dnssec_verify_rrset2(void) { - static const uint8_t ds1_fprint[] = { - 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, - 0x80, 0x67, 0x14, 0x01, - }; - static const uint8_t ds2_fprint[] = { - 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, - 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, + static const uint8_t signature_blob[] = { + 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, + 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, + 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca, + 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2, + 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda, + 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27, + 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50, + 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22, }; + static const uint8_t dnskey_blob[] = { - 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, - 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, - 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, - 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, - 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, - 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, - 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, - 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, - 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, - 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, - 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, - 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, - 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, - 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, - 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, - 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, - 0xe7, 0xea, 0x77, 0x03, + 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea, + 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3, + 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07, + 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5, + 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7, + 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56, + 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e, + 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49, + 0x74, 0x62, 0xfe, 0xd7, }; - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnssecResult result; + int r; - /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ - ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); - assert_se(ds1); + nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); + assert_se(nsec); - ds1->ds.key_tag = 47857; - ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; - ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; - ds1->ds.digest_size = sizeof(ds1_fprint); - ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); - assert_se(ds1->ds.digest); + nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov"); + assert_se(nsec->nsec.next_domain_name); - log_info("DS1: %s", strna(dns_resource_record_to_string(ds1))); + nsec->nsec.types = bitmap_new(); + assert_se(nsec->nsec.types); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0); + assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0); - ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); - assert_se(ds2); + log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec))); - ds2->ds.key_tag = 47857; - ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; - ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; - ds2->ds.digest_size = sizeof(ds2_fprint); - ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); - assert_se(ds2->ds.digest); + rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); + assert_se(rrsig); - log_info("DS2: %s", strna(dns_resource_record_to_string(ds2))); + rrsig->rrsig.type_covered = DNS_TYPE_NSEC; + rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; + rrsig->rrsig.labels = 2; + rrsig->rrsig.original_ttl = 300; + rrsig->rrsig.expiration = 0x5689002f; + rrsig->rrsig.inception = 0x56617230; + rrsig->rrsig.key_tag = 30390; + rrsig->rrsig.signer = strdup("Nasa.Gov."); + assert_se(rrsig->rrsig.signer); + rrsig->rrsig.signature_size = sizeof(signature_blob); + rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); + assert_se(rrsig->rrsig.signature); - dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); + log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); assert_se(dnskey); - dnskey->dnskey.flags = 257; + dnskey->dnskey.flags = 256; dnskey->dnskey.protocol = 3; dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; dnskey->dnskey.key_size = sizeof(dnskey_blob); @@ -268,28 +283,16 @@ static void test_dnssec_verify_dns_key(void) { log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); - assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0); - assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); -} - -static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { - char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; - - assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); - if (r < 0) - return; + assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0); + assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); - assert_se(streq(canonicalized, canonical)); -} + answer = dns_answer_new(1); + assert_se(answer); + assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); -static void test_dnssec_canonicalize(void) { - test_dnssec_canonicalize_one("", ".", 1); - test_dnssec_canonicalize_one(".", ".", 1); - test_dnssec_canonicalize_one("foo", "foo.", 4); - test_dnssec_canonicalize_one("foo.", "foo.", 4); - test_dnssec_canonicalize_one("FOO.", "foo.", 4); - test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); - test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); + /* Validate the RR as it if was 2015-12-11 today */ + assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); + assert_se(result == DNSSEC_VALIDATED); } static void test_dnssec_nsec3_hash(void) { @@ -324,9 +327,12 @@ static void test_dnssec_nsec3_hash(void) { assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0); } +#endif + int main(int argc, char*argv[]) { test_dnssec_canonicalize(); + #ifdef HAVE_GCRYPT test_dnssec_verify_dns_key(); test_dnssec_verify_rrset(); -- cgit v1.2.3-54-g00ecf From bdf19f8fb2f4f2eff2c80bc629f7f6115c04c6e6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Apr 2016 09:48:36 +0200 Subject: Revert "time-util: fall back to CLOCK_MONOTONIC if CLOCK_BOOTTIME unsupported" --- src/basic/time-util.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index c16460a198..7ca764abeb 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -47,15 +47,12 @@ static clockid_t map_clock_id(clockid_t c) { /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on - * those archs. - * - * Also, older kernels don't support CLOCK_BOOTTIME: fall back to CLOCK_MONOTONIC. */ + * those archs. */ switch (c) { - case CLOCK_BOOTTIME: case CLOCK_BOOTTIME_ALARM: - return clock_boottime_or_monotonic (); + return CLOCK_BOOTTIME; case CLOCK_REALTIME_ALARM: return CLOCK_REALTIME; -- cgit v1.2.3-54-g00ecf From da8358c625d3d7fbc0e9df172852c5f87d91e537 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 1 Apr 2016 14:16:14 +0200 Subject: bus-util: Fix reading uint32 properties Fix copy&paste bug in map_basic() to use the correct data type for SD_BUS_TYPE_UINT32. Before we were copying the wrong 32 bits into the destination pointer, resulting in complete garbage on big-endian systems. Fixes #2927 --- src/shared/bus-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 90b312a1a7..d9dd3c6a11 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1068,7 +1068,7 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_ } case SD_BUS_TYPE_UINT32: { - uint64_t u; + uint32_t u; uint32_t *p = userdata; r = sd_bus_message_read_basic(m, type, &u); -- cgit v1.2.3-54-g00ecf From c6ba5b80690f87bd81cfa58fe1a9680bbf3741b5 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 1 Apr 2016 14:17:58 +0200 Subject: systemctl: use correct printf macros for uint32 %u is a simple uint which might not be 32 bit on every platform. Use PRIu32 instead. --- src/systemctl/systemctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 2afb7bad1a..3407d93c80 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1896,13 +1896,13 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n) printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state); if (m->is_host) - printf("%-*s (host) %s%-*s%s %s%*u%s %*u\n", + printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n", (int) (namelen - (sizeof(" (host)")-1)), strna(m->name), on_state, statelen, strna(m->state), off_state, on_failed, failedlen, m->n_failed_units, off_failed, jobslen, m->n_jobs); else - printf("%-*s %s%-*s%s %s%*u%s %*u\n", + printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n", namelen, strna(m->name), on_state, statelen, strna(m->state), off_state, on_failed, failedlen, m->n_failed_units, off_failed, @@ -4637,8 +4637,8 @@ static int show_system_status(sd_bus *bus) { printf(" State: %s%s%s\n", on, strna(mi.state), off); - printf(" Jobs: %u queued\n", mi.n_jobs); - printf(" Failed: %u units\n", mi.n_failed_units); + printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs); + printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units); printf(" Since: %s; %s\n", format_timestamp(since2, sizeof(since2), mi.timestamp), -- cgit v1.2.3-54-g00ecf From 7908dd6730693d7f6a09485b56de7eed0b77afbe Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 1 Apr 2016 14:42:22 +0200 Subject: dhcp-identifier: handle too long duid_len in dhcp_validate_duid_len() Callers of dhcp_validate_duid_len() know that they must not pass a zero duid_len. Thus asserting against that is appropriate. On the other hand, they are not aware of the maximum allowed length of a duid, as that is the reason why they call dhcp_validate_duid_len() in the first place. So dhcp_validate_duid_len() should just signal a regular error. Thereby, change assert_return() to an assert() as this is an internal function. --- src/libsystemd-network/dhcp-identifier.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index babae15c5b..e6486b78f8 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -75,7 +75,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { struct duid d; - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + assert(duid_len > 0); switch (duid_type) { case DUID_TYPE_LLT: @@ -95,6 +95,8 @@ static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { return -EINVAL; break; default: + if (duid_len > sizeof(d.raw)) + return -EINVAL; /* accept unknown type in order to be forward compatible */ break; } -- cgit v1.2.3-54-g00ecf From b97e83cb52d63600921ceb30f15c1ff349790841 Mon Sep 17 00:00:00 2001 From: Bjørnar Ness Date: Fri, 1 Apr 2016 17:31:55 +0200 Subject: prevent systemd-nspawn from trying to create target for bind-mounts when they already exist. This allows bind-mounting over read-only files. --- src/nspawn/nspawn-mount.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 64cb6b3ce3..8e2d2d543c 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -438,21 +438,22 @@ static int mount_bind(const char *dest, CustomMount *m) { r = mkdir_parents_label(where, 0755); if (r < 0) return log_error_errno(r, "Failed to make parents of %s: %m", where); + + /* 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) + return log_error_errno(r, "Failed to create mount point %s: %m", where); + } else { return log_error_errno(errno, "Failed to stat %s: %m", where); } - /* 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 (mount(m->source, where, NULL, mount_flags, mount_opts) < 0) return log_error_errno(errno, "mount(%s) failed: %m", where); -- cgit v1.2.3-54-g00ecf From a0bfc9c26a2cc44b95b1a02200cb999dedf9c0c3 Mon Sep 17 00:00:00 2001 From: Mantas Mikulėnas Date: Fri, 1 Apr 2016 21:51:20 +0300 Subject: cryptsetup: do not 'fail' if trying to detach a nonexistent device It could be that our .service is being stopped precisely because the device already disappeared (e.g. due to a manual `cryptsetup close`, or due to UDisks2 cleaning up). --- src/cryptsetup/cryptsetup.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 2ef966257a..9927621ea0 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -719,8 +719,12 @@ int main(int argc, char *argv[]) { int k; k = crypt_init_by_name(&cd, argv[2]); - if (k) { - log_error_errno(k, "crypt_init() failed: %m"); + if (k == -ENODEV) { + log_info("Volume %s already inactive.", argv[2]); + r = EXIT_SUCCESS; + goto finish; + } else if (k) { + log_error_errno(k, "crypt_init_by_name() failed: %m"); goto finish; } -- cgit v1.2.3-54-g00ecf From af640dca6e5aa1c5264dd90a419f0b63bfdea7b7 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 1 Apr 2016 09:19:11 -0400 Subject: rpm triggers: add note about minimum supported version --- src/core/triggers.systemd.in | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/core/triggers.systemd.in b/src/core/triggers.systemd.in index 9e18a39a67..0d8c303136 100644 --- a/src/core/triggers.systemd.in +++ b/src/core/triggers.systemd.in @@ -18,6 +18,8 @@ # along with systemd; If not, see . # The contents of this are an example to be copied into systemd.spec. +# +# Minimum rpm version supported: 4.13.0 %transfiletriggerin -P 900900 -p -- @systemunitdir@ /etc/systemd/system -- This script will run after any package is initially installed or -- cgit v1.2.3-54-g00ecf From 0f8aeac2557e5ef41b68569890c81ba1d5e92136 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 2 Apr 2016 10:02:41 -0400 Subject: coredumpctl: grammaro fix Mentioned in #2901. --- src/coredump/coredumpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index dac800ebef..27b1e0fb3f 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -664,7 +664,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) { #endif } else { if (r == -ENOENT) - log_error("Cannot retrieve coredump from journal nor disk."); + log_error("Cannot retrieve coredump from journal or disk."); else log_error_errno(r, "Failed to retrieve COREDUMP field: %m"); goto error; -- cgit v1.2.3-54-g00ecf From e7f376c2e8b0495345c6b8f8e93ee9bfdc6f350d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 2 Apr 2016 11:50:30 -0400 Subject: sd-lldp.h: remove double newline For #2898. --- src/systemd/sd-lldp.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 4f2a3b50c0..fa6ab9ad3b 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -100,7 +100,6 @@ enum { SD_LLDP_SYSTEM_CAPABILITIES_SVLAN| \ SD_LLDP_SYSTEM_CAPABILITIES_TPMR)) - #define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } #define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } -- cgit v1.2.3-54-g00ecf From 1a112b52734316085eb430df1785279a2ab6f083 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 2 Apr 2016 11:52:44 -0400 Subject: Add networkd-gperf.c to gitignore For #2915. --- src/network/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/network/.gitignore b/src/network/.gitignore index 8858596489..aca55206b7 100644 --- a/src/network/.gitignore +++ b/src/network/.gitignore @@ -1,2 +1,3 @@ /networkd-network-gperf.c /networkd-netdev-gperf.c +/networkd-gperf.c -- cgit v1.2.3-54-g00ecf From 7c2da2ca8824693c7eeb83e4b22174c33b2a480a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 2 Apr 2016 17:46:49 -0400 Subject: test-compress-benchmark: fix argument parsing on 32bit The patch is not minimal, but a function to parse size_t is probably going to come in handy in other places, so I think it's nicer to define a proper parsing function than to open-code the cast. --- src/basic/copy.c | 2 +- src/basic/parse-util.h | 12 ++++++++++++ src/journal/test-compress-benchmark.c | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index 41dc8ca79a..10c03a8b52 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -71,7 +71,7 @@ static ssize_t try_copy_file_range(int fd_in, loff_t *off_in, int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { bool try_cfr = true, try_sendfile = true, try_splice = true; int r; - size_t m = SSIZE_MAX; /* that the maximum that sendfile and c_f_r accept */ + size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */ assert(fdf >= 0); assert(fdt >= 0); diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index d8dc26a36e..c407263e16 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -90,6 +90,18 @@ static inline int safe_atoli(const char *s, long int *ret_u) { } #endif +#if SIZE_MAX == UINT_MAX +static inline int safe_atozu(const char *s, size_t *ret_u) { + assert_cc(sizeof(size_t) == sizeof(unsigned)); + return safe_atou(s, ret_u); +} +#else +static inline int safe_atozu(const char *s, size_t *ret_u) { + assert_cc(sizeof(size_t) == sizeof(long unsigned)); + return safe_atolu(s, ret_u); +} +#endif + int safe_atod(const char *s, double *ret_d); int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c index 0ef6d36a50..6f6d71435d 100644 --- a/src/journal/test-compress-benchmark.c +++ b/src/journal/test-compress-benchmark.c @@ -164,7 +164,7 @@ int main(int argc, char *argv[]) { arg_duration = x * USEC_PER_SEC; } if (argc == 3) - (void) safe_atolu(argv[2], &arg_start); + (void) safe_atozu(argv[2], &arg_start); else arg_start = getpid(); -- cgit v1.2.3-54-g00ecf From d219849e60db7096bfb111c9ec2555d825bf0c95 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 2 Apr 2016 18:20:12 -0400 Subject: basic/copy: remove unnecessary cast Both types are unsigned, so the cast to the longer type is automatic. --- src/basic/copy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index 10c03a8b52..e2db4be9ff 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -94,8 +94,8 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { if (max_bytes <= 0) return 1; /* return > 0 if we hit the max_bytes limit */ - if ((uint64_t) m > max_bytes) - m = (size_t) max_bytes; + if (m > max_bytes) + m = max_bytes; } /* First try copy_file_range(), unless we already tried */ -- cgit v1.2.3-54-g00ecf From 8e170d29091464caead7b2c989a50bf0e6f1c605 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 2 Apr 2016 18:51:16 -0400 Subject: compress: fix gcc warnings about void* used in arithmetic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit src/journal/compress.c: In function ‘compress_blob_lz4’: src/journal/compress.c:115:49: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] r = LZ4_compress_limitedOutput(src, dst + 8, src_size, (int) dst_alloc_size - 8); ^ src/journal/compress.c: In function ‘decompress_blob_xz’: src/journal/compress.c:179:35: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] s.next_out = *dst + used; ^ src/journal/compress.c: In function ‘decompress_blob_lz4’: src/journal/compress.c:218:37: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] r = LZ4_decompress_safe(src + 8, out, src_size - 8, size); ^ src/journal/compress.c: In function ‘decompress_startswith_xz’: src/journal/compress.c:294:38: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] s.next_out = *buffer + *buffer_size - s.avail_out; ^ src/journal/compress.c:294:53: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] s.next_out = *buffer + *buffer_size - s.avail_out; ^ src/journal/compress.c: In function ‘decompress_startswith_lz4’: src/journal/compress.c:327:45: warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arith] r = LZ4_decompress_safe_partial(src + 8, *buffer, src_size - 8, ^ LZ4 and XZ functions use char* and unsigned char*, respectively, so keep void* in our internal APIs and add casts. --- src/journal/compress.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/journal/compress.c b/src/journal/compress.c index c43849c46a..ba734b5561 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -112,7 +112,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size, if (src_size < 9) return -ENOBUFS; - r = LZ4_compress_limitedOutput(src, dst + 8, src_size, (int) dst_alloc_size - 8); + r = LZ4_compress_limitedOutput(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8); if (r <= 0) return -ENOBUFS; @@ -176,7 +176,7 @@ int decompress_blob_xz(const void *src, uint64_t src_size, return -ENOMEM; s.avail_out = space - used; - s.next_out = *dst + used; + s.next_out = *(uint8_t**)dst + used; } *dst_size = space - s.avail_out; @@ -215,7 +215,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size, } else out = *dst; - r = LZ4_decompress_safe(src + 8, out, src_size - 8, size); + r = LZ4_decompress_safe((char*)src + 8, out, src_size - 8, size); if (r < 0 || r != size) return -EBADMSG; @@ -291,7 +291,7 @@ int decompress_startswith_xz(const void *src, uint64_t src_size, if (!(greedy_realloc(buffer, buffer_size, *buffer_size * 2, 1))) return -ENOMEM; - s.next_out = *buffer + *buffer_size - s.avail_out; + s.next_out = *(uint8_t**)buffer + *buffer_size - s.avail_out; } #else @@ -324,7 +324,7 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size, if (!(greedy_realloc(buffer, buffer_size, ALIGN_8(prefix_len + 1), 1))) return -ENOMEM; - r = LZ4_decompress_safe_partial(src + 8, *buffer, src_size - 8, + r = LZ4_decompress_safe_partial((char*)src + 8, *buffer, src_size - 8, prefix_len + 1, *buffer_size); if (r >= 0) size = (unsigned) r; -- cgit v1.2.3-54-g00ecf From 68a9c7c4f0c06fb413a3830212f5e06d8dd5089c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 3 Mar 2016 15:07:02 -0500 Subject: nss-myhostname: trivial style fixes --- src/libsystemd/sd-netlink/local-addresses.c | 3 +-- src/nss-myhostname/nss-myhostname.c | 30 +++++++++++++---------------- 2 files changed, 14 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c index 6abd8fd0cc..ed9ee041ab 100644 --- a/src/libsystemd/sd-netlink/local-addresses.c +++ b/src/libsystemd/sd-netlink/local-addresses.c @@ -155,8 +155,7 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre n_list++; }; - if (n_list > 0) - qsort(list, n_list, sizeof(struct local_address), address_compare); + qsort_safe(list, n_list, sizeof(struct local_address), address_compare); *ret = list; list = NULL; diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 2536ad2898..460a613b9d 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -127,7 +127,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r( memcpy(r_name, canonical, l+1); idx = ALIGN(l+1); - if (n_addresses <= 0) { + assert(n_addresses >= 0); + if (n_addresses == 0) { /* Second, fill in IPv6 tuple */ r_tuple = (struct gaih_addrtuple*) (buffer + idx); r_tuple->next = r_tuple_prev; @@ -453,34 +454,29 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r( } n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses); - if (n_addresses > 0) { - for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) { - if (af != a->family) - continue; + for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) { + if (af != a->family) + continue; - if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) - goto found; - } + if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) + goto found; } addresses = mfree(addresses); n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses); - if (n_addresses > 0) { - for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) { - if (af != a->family) - continue; + for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) { + if (af != a->family) + continue; - if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) { - canonical = "gateway"; - goto found; - } + if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) { + canonical = "gateway"; + goto found; } } *errnop = ENOENT; *h_errnop = HOST_NOT_FOUND; - return NSS_STATUS_NOTFOUND; found: -- cgit v1.2.3-54-g00ecf From cf2d43e7f47aaa5ea295b40fb80478883e74a48a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 3 Mar 2016 15:35:34 -0500 Subject: Move nss typedefs into nss-util.h In preparation for subsequent changes. --- src/basic/nss-util.h | 24 +++++++++++++ src/nss-resolve/nss-resolve.c | 79 ++++++++++++++----------------------------- 2 files changed, 49 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index df565a3593..14e950869d 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -154,3 +154,27 @@ enum nss_status _nss_##module##_getgrgid_r( \ struct group *gr, \ char *buffer, size_t buflen, \ int *errnop) _public_ + +typedef enum nss_status (*_nss_gethostbyname4_r_t)( + const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + +typedef enum nss_status (*_nss_gethostbyname3_r_t)( + const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp); + +typedef enum nss_status (*_nss_gethostbyaddr2_r_t)( + const void* addr, socklen_t len, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index 0de6bd2241..5ce10f1cbd 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -117,13 +117,6 @@ enum nss_status _nss_resolve_gethostbyname4_r( int *errnop, int *h_errnop, int32_t *ttlp) { - enum nss_status (*fallback)( - const char *name, - struct gaih_addrtuple **pat, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp); - _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; @@ -275,15 +268,15 @@ enum nss_status _nss_resolve_gethostbyname4_r( return NSS_STATUS_SUCCESS; fallback: - fallback = (enum nss_status (*)(const char *name, - struct gaih_addrtuple **pat, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp)) - find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r"); + { + _nss_gethostbyname4_r_t fallback; + + fallback = (_nss_gethostbyname4_r_t) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r"); - if (fallback) - return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp); + if (fallback) + return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp); + } fail: *errnop = -r; @@ -300,15 +293,6 @@ enum nss_status _nss_resolve_gethostbyname3_r( int32_t *ttlp, char **canonp) { - enum nss_status (*fallback)( - const char *name, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp, - char **canonp); - _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; @@ -480,16 +464,14 @@ enum nss_status _nss_resolve_gethostbyname3_r( return NSS_STATUS_SUCCESS; fallback: - fallback = (enum nss_status (*)(const char *name, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp, - char **canonp)) - find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r"); - if (fallback) - return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp); + { + _nss_gethostbyname3_r_t fallback; + + fallback = (_nss_gethostbyname3_r_t) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r"); + if (fallback) + return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp); + } fail: *errnop = -r; @@ -505,15 +487,6 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( int *errnop, int *h_errnop, int32_t *ttlp) { - enum nss_status (*fallback)( - const void* addr, socklen_t len, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp); - - _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; @@ -682,17 +655,15 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( return NSS_STATUS_SUCCESS; fallback: - fallback = (enum nss_status (*)( - const void* addr, socklen_t len, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp)) - find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r"); - - if (fallback) - return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp); + { + _nss_gethostbyaddr2_r_t fallback; + + fallback = (_nss_gethostbyaddr2_r_t) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r"); + + if (fallback) + return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp); + } fail: *errnop = -r; -- cgit v1.2.3-54-g00ecf From f3ea87af4f88b94d346cf806778a9517eb80ae86 Mon Sep 17 00:00:00 2001 From: Iago López Galeiras Date: Mon, 4 Apr 2016 11:28:14 +0200 Subject: run: add colon before printing started units In 110ceee58e5bc796c03a7db2109f85a999d5bc2e we removed the period after printing the started units. This makes copying the unit name easier but results in improper English. This adds a colon before printing the units, which makes the output look better. --- man/systemd-run.xml | 6 +++--- src/run/run.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/man/systemd-run.xml b/man/systemd-run.xml index a92dfb402a..473f83eac6 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -345,7 +345,7 @@ provided by systemd to services: # systemd-run env -Running as unit run-19945.service +Running as unit: run-19945.service # journalctl -u run-19945.service Sep 08 07:37:21 bupkis systemd[1]: Starting /usr/bin/env... Sep 08 07:37:21 bupkis systemd[1]: Started /usr/bin/env. @@ -366,8 +366,8 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20. # date; systemd-run --on-active=30 --timer-property=AccuracySec=100ms /bin/touch /tmp/foo Mon Dec 8 20:44:24 KST 2014 -Running as unit run-71.timer -Will run service as unit run-71.service +Running as unit: run-71.timer +Will run service as unit: run-71.service # 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. diff --git a/src/run/run.c b/src/run/run.c index 540a612fdf..f92a7f4e2e 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -878,7 +878,7 @@ static int start_transient_service( (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); if (!arg_quiet) - log_info("Running as unit %s\nPress ^] three times within 1s to disconnect TTY.", service); + log_info("Running as unit: %s\nPress ^] three times within 1s to disconnect TTY.", service); r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward); if (r < 0) @@ -896,7 +896,7 @@ static int start_transient_service( fputc('\n', stdout); } else if (!arg_quiet) - log_info("Running as unit %s", service); + log_info("Running as unit: %s", service); return 0; } @@ -1038,7 +1038,7 @@ static int start_transient_scope( return r; if (!arg_quiet) - log_info("Running scope as unit %s", scope); + log_info("Running scope as unit: %s", scope); execvpe(argv[0], argv, env); @@ -1189,9 +1189,9 @@ static int start_transient_timer( if (r < 0) return r; - log_info("Running timer as unit %s", timer); + log_info("Running timer as unit: %s", timer); if (argv[0]) - log_info("Will run service as unit %s", service); + log_info("Will run service as unit: %s", service); return 0; } -- cgit v1.2.3-54-g00ecf From 331fb4ca51cc88a2822bb213c3fc1756b886ac15 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 4 Apr 2016 14:07:56 +0300 Subject: basic: fallback to fstatat if entry->d_type is DT_UNKNOWN * tests-functions: improve FSTYPE-support make clean setup FSTYPE=reiserfs is working fine now :) * basic: fallback to fstatat if entry->d_type is DT_UNKNOWN Fixes localectl on reiserfs: -bash-4.3# mkdir -p /usr/lib/locale -bash-4.3# stat -f /usr/lib/locale/ File: "/usr/lib/locale/" ID: bdb0322715b5366e Namelen: 255 Type: reiserfs Block size: 4096 Blocks: Total: 99835 Free: 60262 Available: 60262 Inodes: Total: 0 Free: 0 -bash-4.3# mkdir /usr/lib/locale/HeyHo -bash-4.3# localectl list-locales --no-pager -bash-4.3# mount -t tmpfs tmpfs /usr/lib/locale -bash-4.3# mkdir /usr/lib/locale/HeyHo -bash-4.3# localectl list-locales --no-pager HeyHo --- src/basic/locale-util.c | 2 ++ test/test-functions | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index cda6b2895d..eaad25e65b 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -153,6 +153,8 @@ static int add_locales_from_libdir (Set *locales) { FOREACH_DIRENT(entry, dir, return -errno) { char *z; + dirent_ensure_type(dir, entry); + if (entry->d_type != DT_DIR) continue; diff --git a/test/test-functions b/test/test-functions index 29f647ece4..8bbcddab59 100644 --- a/test/test-functions +++ b/test/test-functions @@ -213,6 +213,9 @@ EOF install_fsck() { dracut_install /sbin/fsck* dracut_install -o /bin/fsck* + + # fskc.reiserfs calls reiserfsck. so, install it + dracut_install -o reiserfsck } install_dmevent() { @@ -257,7 +260,13 @@ create_empty_image() { , EOF - mkfs -t "$FSTYPE" -L systemd "${LOOPDEV}p1" + local _label="-L systemd" + # mkfs.reiserfs doesn't know -L. so, use --label instead + [[ "$FSTYPE" == "reiserfs" ]] && _label="--label systemd" + if ! mkfs -t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then + dfatal "Failed to mkfs -t ${FSTYPE}" + exit 1 + fi } check_result_nspawn() { @@ -351,7 +360,7 @@ install_config_files() { echo systemd-testsuite > $initdir/etc/hostname # fstab cat >$initdir/etc/fstab < Date: Mon, 4 Apr 2016 07:08:26 -0400 Subject: import: Preserve xattrs in tar files Resolves #2908 --- src/import/import-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/import/import-common.c b/src/import/import-common.c index 18a30be36d..287a3382a1 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -136,7 +136,7 @@ int import_fork_tar_x(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", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL); log_error_errno(errno, "Failed to execute tar: %m"); _exit(EXIT_FAILURE); } @@ -210,7 +210,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) { if (r < 0) log_error_errno(r, "Failed to drop capabilities, ignoring: %m"); - execlp("tar", "tar", "-C", path, "-c", ".", NULL); + execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL); log_error_errno(errno, "Failed to execute tar: %m"); _exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From 63003524cb7c27b50583cc4d90b5d81af5f7a7f6 Mon Sep 17 00:00:00 2001 From: "David R. Hedges" Date: Thu, 18 Feb 2016 21:31:38 -0600 Subject: *.localdomain != localhost ".localdomain" is not a reserved suffix (or prefix). I'm not aware of any product expecting *.localdomain to resolve to localhost, however I am aware of at least one product that defaults to ".localdomain" as its DNS suffix provided via DHCP (pfSense). This leads to unexpected results when attempting to access a host that's offline (or a host that's online, when nsswitch.conf is [mis-]configured to have myhostname ahead of DNS). Operate on: localhost (and localhost.) *.localhost (and *.localhost.) localhost.localdomain (and localhost.localdomain.) *.localhost.localdomain (and *.localhost.localdomain.) We should not cover: *.localdomain (nor *.localdomain.) localdomain (nor localdomain.) --- man/nss-myhostname.xml | 7 ++++--- man/systemd-resolved.service.xml | 7 ++++--- src/basic/hostname-util.c | 10 +++++----- 3 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml index 251bdecbad..e339e6b44e 100644 --- a/man/nss-myhostname.xml +++ b/man/nss-myhostname.xml @@ -71,9 +71,10 @@ is on the local loopback) and the IPv6 address ::1 (which is the local host). - The hostname localhost (as well as any hostname ending in - .localhost, .localdomain or equal to localdomain) is - resolved to the IP addresses 127.0.0.1 and ::1. + The hostnames localhost and + localhost.localdomain (as well as any hostname + ending in .localhost or .localhost.localdomain) + are resolved to the IP addresses 127.0.0.1 and ::1. The hostname gateway is resolved to all current default routing gateway addresses, diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 7a9e23a2c6..829729ca09 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -87,9 +87,10 @@ is on the local loopback) and the IPv6 address ::1 (which is the local host). - The hostname localhost (as well as any hostname ending in - .localhost, .localdomain or equal to localdomain) is - resolved to the IP addresses 127.0.0.1 and ::1. + The hostnames localhost and + localhost.localdomain (as well as any hostname + ending in .localhost or .localhost.localdomain) + are resolved to the IP addresses 127.0.0.1 and ::1. The hostname gateway is resolved to all current default routing gateway addresses, diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 7bb23448ed..4fe6a725aa 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -150,16 +150,16 @@ 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 */ + * described in RFC6761 plus the redhatism of localdomain */ return strcaseeq(hostname, "localhost") || strcaseeq(hostname, "localhost.") || - strcaseeq(hostname, "localdomain.") || - strcaseeq(hostname, "localdomain") || + strcaseeq(hostname, "localhost.localdomain") || + strcaseeq(hostname, "localhost.localdomain.") || endswith_no_case(hostname, ".localhost") || endswith_no_case(hostname, ".localhost.") || - endswith_no_case(hostname, ".localdomain") || - endswith_no_case(hostname, ".localdomain."); + endswith_no_case(hostname, ".localhost.localdomain") || + endswith_no_case(hostname, ".localhost.localdomain."); } bool is_gateway_hostname(const char *hostname) { -- cgit v1.2.3-54-g00ecf From 4f9a91055ce83be9b6a81bdeab6d360f13ff897a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 2 Aug 2015 14:22:10 -0400 Subject: systemctl: add --value option With this option, systemctl will only print the rhs in show: $ systemctl show -p Wants,After systemd-journald --value systemd-journald.socket ... systemd-journald-dev-log.socket ... This is useful in scripts, because the need to call awk or similar is removed. --- man/systemctl.xml | 10 ++++++ src/login/loginctl.c | 2 +- src/shared/bus-util.c | 42 +++++++++++++++---------- src/shared/bus-util.h | 2 +- src/systemctl/systemctl.c | 78 +++++++++++++++++++++++++++++------------------ 5 files changed, 87 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/man/systemctl.xml b/man/systemctl.xml index 1480bf8380..089fb0f5c3 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -232,6 +232,16 @@ + + + + + When printing properties with show, + only print the value, and skip the property name and + =. + + + diff --git a/src/login/loginctl.c b/src/login/loginctl.c index c9a5cd796b..2e8405a946 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -757,7 +757,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte break; } - r = bus_print_property(name, m, arg_all); + r = bus_print_property(name, m, false, arg_all); if (r < 0) return bus_log_parse_error(r); diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index b102a79da8..85f8280773 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -712,7 +712,15 @@ int bus_connect_user_systemd(sd_bus **_bus) { return 0; } -int bus_print_property(const char *name, sd_bus_message *property, bool all) { +#define print_property(name, fmt, ...) \ + do { \ + if (value) \ + printf(fmt "\n", __VA_ARGS__); \ + else \ + printf("%s=" fmt "\n", name, __VA_ARGS__); \ + } while(0) + +int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all) { char type; const char *contents; int r; @@ -740,7 +748,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (!escaped) return -ENOMEM; - printf("%s=%s\n", name, escaped); + print_property(name, "%s", escaped); } return 1; @@ -753,7 +761,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - printf("%s=%s\n", name, yes_no(b)); + print_property(name, "%s", yes_no(b)); return 1; } @@ -773,14 +781,14 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { t = format_timestamp(timestamp, sizeof(timestamp), u); if (t || all) - printf("%s=%s\n", name, strempty(t)); + print_property(name, "%s", strempty(t)); } else if (strstr(name, "USec")) { char timespan[FORMAT_TIMESPAN_MAX]; - printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0)); + print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0)); } else - printf("%s=%llu\n", name, (unsigned long long) u); + print_property(name, "%"PRIu64, u); return 1; } @@ -792,7 +800,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - printf("%s=%lld\n", name, (long long) i); + print_property(name, "%"PRIi64, i); return 1; } @@ -805,9 +813,9 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { return r; if (strstr(name, "UMask") || strstr(name, "Mode")) - printf("%s=%04o\n", name, u); + print_property(name, "%04o", u); else - printf("%s=%u\n", name, (unsigned) u); + print_property(name, "%"PRIu32, u); return 1; } @@ -819,7 +827,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - printf("%s=%i\n", name, (int) i); + print_property(name, "%"PRIi32, i); return 1; } @@ -830,7 +838,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - printf("%s=%g\n", name, d); + print_property(name, "%g", d); return 1; } @@ -846,7 +854,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) { _cleanup_free_ char *escaped = NULL; - if (first) + if (first && !value) printf("%s=", name); escaped = xescape(str, "\n "); @@ -860,7 +868,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (r < 0) return r; - if (first && all) + if (first && all && !value) printf("%s=", name); if (!first || all) puts(""); @@ -882,7 +890,8 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (all || n > 0) { unsigned int i; - printf("%s=", name); + if (!value) + printf("%s=", name); for (i = 0; i < n; i++) printf("%02x", u[i]); @@ -903,7 +912,8 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { if (all || n > 0) { unsigned int i; - printf("%s=", name); + if (!value) + printf("%s=", name); for (i = 0; i < n; i++) printf("%08x", u[i]); @@ -960,7 +970,7 @@ int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, ch if (r < 0) return r; - r = bus_print_property(name, reply, all); + r = bus_print_property(name, reply, false, all); if (r < 0) return r; if (r == 0) { diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index fcda1b2c6c..65eca9ac56 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -78,7 +78,7 @@ int bus_connect_user_systemd(sd_bus **_bus); int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus); int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus); -int bus_print_property(const char *name, sd_bus_message *property, bool all); +int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all); int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all); int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 180c8f9656..57e62a607b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -103,6 +103,7 @@ static bool arg_no_pager = false; static bool arg_no_wtmp = false; static bool arg_no_wall = false; static bool arg_no_reload = false; +static bool arg_value = false; static bool arg_show_types = false; static bool arg_ignore_inhibitors = false; static bool arg_dry = false; @@ -4111,6 +4112,14 @@ skip: return 0; } +#define print_prop(name, fmt, ...) \ + do { \ + if (arg_value) \ + printf(fmt "\n", __VA_ARGS__); \ + else \ + printf("%s=" fmt "\n", name, __VA_ARGS__); \ + } while(0) + static int print_property(const char *name, sd_bus_message *m, const char *contents) { int r; @@ -4138,9 +4147,9 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); if (u > 0) - printf("%s=%"PRIu32"\n", name, u); + print_prop(name, "%"PRIu32, u); else if (arg_all) - printf("%s=\n", name); + print_prop(name, "%s", ""); return 0; @@ -4152,7 +4161,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); if (arg_all || !isempty(s)) - printf("%s=%s\n", name, s); + print_prop(name, "%s", s); return 0; @@ -4164,7 +4173,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); if (arg_all || !isempty(a) || !isempty(b)) - printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b)); + print_prop(name, "%s \"%s\"", strempty(a), strempty(b)); return 0; } else if (streq_ptr(name, "SystemCallFilter")) { @@ -4191,8 +4200,10 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte bool first = true; char **i; - fputs(name, stdout); - fputc('=', stdout); + if (!arg_value) { + fputs(name, stdout); + fputc('=', stdout); + } if (!whitelist) fputc('~', stdout); @@ -4224,7 +4235,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0) - printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore)); + print_prop("EnvironmentFile", "%s (ignore_errors=%s)\n", path, yes_no(ignore)); if (r < 0) return bus_log_parse_error(r); @@ -4243,7 +4254,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) - printf("%s=%s\n", type, path); + print_prop(type, "%s", path); if (r < 0) return bus_log_parse_error(r); @@ -4261,7 +4272,10 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) - printf("Listen%s=%s\n", type, path); + if (arg_value) + puts(path); + else + printf("Listen%s=%s\n", type, path); if (r < 0) return bus_log_parse_error(r); @@ -4282,10 +4296,9 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) { char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX]; - printf("%s={ value=%s ; next_elapse=%s }\n", - base, - format_timespan(timespan1, sizeof(timespan1), value, 0), - format_timespan(timespan2, sizeof(timespan2), next_elapse, 0)); + print_prop(base, "{ value=%s ; next_elapse=%s }", + format_timespan(timespan1, sizeof(timespan1), value, 0), + format_timespan(timespan2, sizeof(timespan2), next_elapse, 0)); } if (r < 0) return bus_log_parse_error(r); @@ -4309,18 +4322,18 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte tt = strv_join(info.argv, " "); - printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }\n", - name, - strna(info.path), - strna(tt), - yes_no(info.ignore), - strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)), - strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)), - info.pid, - sigchld_code_to_string(info.code), - info.status, - info.code == CLD_EXITED ? "" : "/", - strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status))); + print_prop(name, + "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }", + strna(info.path), + strna(tt), + yes_no(info.ignore), + strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)), + strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)), + info.pid, + sigchld_code_to_string(info.code), + info.status, + info.code == CLD_EXITED ? "" : "/", + strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status))); free(info.path); strv_free(info.argv); @@ -4341,7 +4354,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0) - printf("%s=%s %s\n", name, strna(path), strna(rwm)); + print_prop(name, "%s %s", strna(path), strna(rwm)); if (r < 0) return bus_log_parse_error(r); @@ -4360,7 +4373,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0) - printf("%s=%s %" PRIu64 "\n", name, strna(path), weight); + print_prop(name, "%s %"PRIu64, strna(path), weight); if (r < 0) return bus_log_parse_error(r); @@ -4379,7 +4392,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0) - printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth); + print_prop(name, "%s %"PRIu64, strna(path), bandwidth); if (r < 0) return bus_log_parse_error(r); @@ -4393,7 +4406,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte break; } - r = bus_print_property(name, m, arg_all); + r = bus_print_property(name, m, arg_value, arg_all); if (r < 0) return bus_log_parse_error(r); @@ -6238,6 +6251,7 @@ static void systemctl_help(void) { " --job-mode=MODE Specify how to deal with already queued jobs, when\n" " queueing a new job\n" " --show-types When showing sockets, explicitly show their type\n" + " --value When showing properties, only print the value\n" " -i --ignore-inhibitors\n" " When shutting down or sleeping, ignore inhibitors\n" " --kill-who=WHO Who to send signal to\n" @@ -6489,6 +6503,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_SHOW_TYPES, ARG_IRREVERSIBLE, ARG_IGNORE_DEPENDENCIES, + ARG_VALUE, ARG_VERSION, ARG_USER, ARG_SYSTEM, @@ -6530,6 +6545,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */ { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */ { "ignore-inhibitors", no_argument, NULL, 'i' }, + { "value", no_argument, NULL, ARG_VALUE }, { "user", no_argument, NULL, ARG_USER }, { "system", no_argument, NULL, ARG_SYSTEM }, { "global", no_argument, NULL, ARG_GLOBAL }, @@ -6681,6 +6697,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_show_types = true; break; + case ARG_VALUE: + arg_value = true; + break; + case ARG_JOB_MODE: arg_job_mode = optarg; break; -- cgit v1.2.3-54-g00ecf From f4046fe06f859a37b233716485d572183af351ac Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 17 Mar 2016 12:48:02 -0400 Subject: loginctl: add --value option --- man/loginctl.xml | 10 ++++++++++ src/login/loginctl.c | 29 +++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/man/loginctl.xml b/man/loginctl.xml index f41acc6a1b..7f7252a5d9 100644 --- a/man/loginctl.xml +++ b/man/loginctl.xml @@ -93,6 +93,16 @@ shown. + + + + + When printing properties with show, + only print the value, and skip the property name and + =. + + + diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 2e8405a946..01f6fa5db0 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -48,6 +48,7 @@ static char **arg_property = NULL; static bool arg_all = false; +static bool arg_value = false; static bool arg_full = false; static bool arg_no_pager = false; static bool arg_legend = true; @@ -679,6 +680,14 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) return 0; } +#define property(name, fmt, ...) \ + do { \ + if (arg_value) \ + printf(fmt "\n", __VA_ARGS__); \ + else \ + printf("%s=" fmt "\n", name, __VA_ARGS__); \ + } while(0) + static int print_property(const char *name, sd_bus_message *m, const char *contents) { int r; @@ -702,7 +711,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); if (arg_all || !isempty(s)) - printf("%s=%s\n", name, s); + property(name, "%s", s); return 0; @@ -718,8 +727,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return -EINVAL; } - printf("%s=" UID_FMT "\n", name, uid); - + property(name, UID_FMT, uid); return 0; } @@ -735,14 +743,16 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte if (r < 0) return bus_log_parse_error(r); - printf("%s=", name); + if (!arg_value) + printf("%s=", name); while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) { printf("%s%s", space ? " " : "", s); space = true; } - printf("\n"); + if (space || !arg_value) + printf("\n"); if (r < 0) return bus_log_parse_error(r); @@ -757,7 +767,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte break; } - r = bus_print_property(name, m, false, arg_all); + r = bus_print_property(name, m, arg_value, arg_all); if (r < 0) return bus_log_parse_error(r); @@ -1330,6 +1340,7 @@ static int help(int argc, char *argv[], void *userdata) { " -M --machine=CONTAINER Operate on local container\n" " -p --property=NAME Show only properties by this name\n" " -a --all Show all properties, including empty ones\n" + " --value When showing properties, only print the value\n" " -l --full Do not ellipsize output\n" " --kill-who=WHO Who to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" @@ -1371,6 +1382,7 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_VALUE, ARG_NO_PAGER, ARG_NO_LEGEND, ARG_KILL_WHO, @@ -1382,6 +1394,7 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "property", required_argument, NULL, 'p' }, { "all", no_argument, NULL, 'a' }, + { "value", no_argument, NULL, ARG_VALUE }, { "full", no_argument, NULL, 'l' }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, @@ -1427,6 +1440,10 @@ static int parse_argv(int argc, char *argv[]) { arg_all = true; break; + case ARG_VALUE: + arg_value = true; + break; + case 'l': arg_full = true; break; -- cgit v1.2.3-54-g00ecf From b7f71444c01a9b4ac6f7072bf4f7d6d8098cb982 Mon Sep 17 00:00:00 2001 From: Vinay Kulkarni Date: Mon, 4 Apr 2016 15:13:06 -0700 Subject: Address code-review items for pull-request #2890 1. Replace strtol with unhexchar, verified with valid and invalid DUID strings. 2. Fix logging to use log_syntax instead of log_error. 3. On error reading DUID, ignore read and preserve previous state. 4. Fix man-pages to use markup, remove options not yet implemented. 5. Remove spurious header line in new files. --- man/networkd.conf.xml | 53 +++------------ man/systemd.network.xml | 53 +++------------ src/libsystemd-network/network-internal.c | 5 +- src/network/networkd-conf.c | 109 ++++++++++++++++-------------- src/network/networkd-conf.h | 2 - 5 files changed, 84 insertions(+), 138 deletions(-) (limited to 'src') diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index 30674e12bc..4f423b2b61 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -95,21 +95,17 @@ Type= The type of DUID specified in this section. The following values are supported: - raw : If Type=raw, then RawData= specifies - the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 - specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), - and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and - RawData is specified, Type defaults to 'raw'. - Type will support the following values in the future: - link-layer-and-time : If Type=link-layer-and-time, then - MACAddress= and TimeStamp= specify the hardware - address and time-stamp for DUID-LLT. - vendor : If Type=vendor, then EnterpriseNumber= - and RawData= specify the enterprise number and identifier for DUID-EN. - link-layer : If Type=link-layer, then MACAddress= - specifies the hardware address for DUID-LL. - uuid : If Type=uuid, then UUID= specifies DUID-UUID. - + + + + If Type=raw, then RawData= specifies the + entire DUID. For example, RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and + RawData is specified, Type defaults to 'raw'. + + + @@ -120,33 +116,6 @@ - - The following options will be supported in the future: - - - - MACAddress= - Specifies the link-layer address for DUID Type or . - - - TimeStamp= - Specifies the DUID generation time for DUID Type . - - - EnterpriseNumber= - Specifies the enterprise number for DUID Type - . - - - UUID= - Specifies the UUID for DUID Type . - - - - - See Also diff --git a/man/systemd.network.xml b/man/systemd.network.xml index b2e1d40287..a6d290cfb3 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -856,21 +856,17 @@ Type= The type of DUID specified in this section. The following values are supported: - raw : If Type=raw, then RawData= specifies - the entire DUID. For e.g: RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 - specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), - and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and - RawData is specified, Type defaults to 'raw'. - Type will support the following values in the future: - link-layer-and-time : If Type=link-layer-and-time, then - MACAddress= and TimeStamp= specify the hardware - address and time-stamp for DUID-LLT. - vendor : If Type=vendor, then EnterpriseNumber= - and RawData= specify the enterprise number and identifier for DUID-EN. - link-layer : If Type=link-layer, then MACAddress= - specifies the hardware address for DUID-LL. - uuid : If Type=uuid, then UUID= specifies DUID-UUID. - + + + + If Type=raw, then RawData= specifies the + entire DUID. For example, RawData=00:02:00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 + specifies a 14 byte long DUID-EN ("00:02"), with enterprise number 43793 ("00:00:ab:11"), + and identifier value "f9:2a:c2:77:29:f9:5c:00".If Type is not specified and + RawData is specified, Type defaults to 'raw'. + + + @@ -882,33 +878,6 @@ - - The following options will be supported in the future: - - - - MACAddress= - Specifies the link-layer address for DUID Type or . - - - TimeStamp= - Specifies the DUID generation time for DUID Type . - - - EnterpriseNumber= - Specifies the enterprise number for DUID Type . - - - UUID= - Specifies the UUID for DUID Type . - - - - - [DHCPServer] Section Options The [DHCPServer] section contains diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 0e2d757b2b..99b3a1d01f 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -355,8 +355,9 @@ int config_parse_iaid(const char *unit, r = safe_atou32(rvalue, &iaid); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); - return r; + log_syntax(unit, LOG_ERR, filename, line, r, + "Unable to read IAID, ignoring assignment: %s", rvalue); + return 0; } *((uint32_t *)data) = iaid; diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 8b149124b3..73a8d16b58 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,6 +22,7 @@ #include "conf-parser.h" #include "def.h" #include "dhcp-identifier.h" +#include "hexdecoct.h" #include "networkd-conf.h" #include "string-table.h" @@ -58,53 +57,39 @@ int config_parse_duid_rawdata( const char *rvalue, void *data, void *userdata) { - int r; - long byte; - char *cbyte, *pnext; + int r, n1, n2, byte; + char *cbyte; const char *pduid = rvalue; - size_t count = 0, duid_index = 0; - Manager *m; - Network *n; - DUIDType *duid_type; - uint16_t *dhcp_duid_type; - size_t *dhcp_duid_len; - uint8_t *dhcp_duid; + Manager *m = userdata; + Network *n = userdata; + DUIDType duidtype; + uint16_t dhcp_duid_type = 0; + uint8_t dhcp_duid[MAX_DUID_LEN]; + size_t len, count = 0, duid_start_offset = 0, dhcp_duid_len = 0; assert(filename); assert(lvalue); assert(rvalue); assert(userdata); - if (ltype == DUID_CONFIG_SOURCE_GLOBAL) { - m = userdata; - duid_type = &m->duid_type; - dhcp_duid_type = &m->dhcp_duid_type; - dhcp_duid_len = &m->dhcp_duid_len; - dhcp_duid = m->dhcp_duid; - } else { - /* DUID_CONFIG_SOURCE_NETWORK */ - n = userdata; - duid_type = &n->duid_type; - dhcp_duid_type = &n->dhcp_duid_type; - dhcp_duid_len = &n->dhcp_duid_len; - dhcp_duid = n->dhcp_duid; - } + duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type + : n->duid_type; - if (*duid_type == _DUID_TYPE_INVALID) - *duid_type = DUID_TYPE_RAW; + if (duidtype == _DUID_TYPE_INVALID) + duidtype = DUID_TYPE_RAW; - switch (*duid_type) { + switch (duidtype) { case DUID_TYPE_LLT: /* RawData contains DUID-LLT link-layer address (offset 6) */ - duid_index = 6; + duid_start_offset = 6; break; case DUID_TYPE_EN: /* RawData contains DUID-EN identifier (offset 4) */ - duid_index = 4; + duid_start_offset = 4; break; case DUID_TYPE_LL: /* RawData contains DUID-LL link-layer address (offset 2) */ - duid_index = 2; + duid_start_offset = 2; break; case DUID_TYPE_UUID: /* RawData specifies UUID (offset 0) - fall thru */ @@ -114,42 +99,66 @@ int config_parse_duid_rawdata( break; } - if (*duid_type != DUID_TYPE_RAW) - *dhcp_duid_type = (uint16_t)(*duid_type); + if (duidtype != DUID_TYPE_RAW) + dhcp_duid_type = (uint16_t)duidtype; /* RawData contains DUID in format " NN:NN:NN... " */ - while (true) { + for (;;) { r = extract_first_word(&pduid, &cbyte, ":", 0); if (r < 0) { - log_error("Failed to read DUID."); - return -EINVAL; + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to read DUID, ignoring assignment: %s.", rvalue); + goto exit; } if (r == 0) break; - if (duid_index >= MAX_DUID_LEN) { - log_error("DUID length exceeds maximum length."); - return -EINVAL; + if ((duid_start_offset + dhcp_duid_len) >= MAX_DUID_LEN) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Max DUID length exceeded, ignoring assignment: %s.", rvalue); + goto exit; } - errno = 0; - byte = strtol(cbyte, &pnext, 16); - if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) - || (errno != 0 && byte == 0) || (cbyte == pnext)) { - log_error("Invalid DUID byte: %s.", cbyte); - return -EINVAL; + len = strlen(cbyte); + if ((len == 0) || (len > 2)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue); + goto exit; } + n2 = 0; + n1 = unhexchar(cbyte[0]); + if (len == 2) + n2 = unhexchar(cbyte[1]); + if ((n1 < 0) || (n2 < 0)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue); + goto exit; + } + byte = (n1 << (4 * (len-1))) | n2; /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ - if ((*duid_type == DUID_TYPE_RAW) && (count < 2)) { - *dhcp_duid_type |= (byte << (8 * (1 - count))); + if ((duidtype == DUID_TYPE_RAW) && (count < 2)) { + dhcp_duid_type |= (byte << (8 * (1 - count))); count++; continue; } - dhcp_duid[duid_index++] = byte; + dhcp_duid[duid_start_offset + dhcp_duid_len] = byte; + dhcp_duid_len++; } - *dhcp_duid_len = duid_index; + if (ltype == DUID_CONFIG_SOURCE_GLOBAL) { + m->duid_type = duidtype; + m->dhcp_duid_type = dhcp_duid_type; + m->dhcp_duid_len = dhcp_duid_len; + memcpy(&m->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); + } else { + /* DUID_CONFIG_SOURCE_NETWORK */ + n->duid_type = duidtype; + n->dhcp_duid_type = dhcp_duid_type; + n->dhcp_duid_len = dhcp_duid_len; + memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); + } +exit: return 0; } diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h index efc370f839..671e656d7b 100644 --- a/src/network/networkd-conf.h +++ b/src/network/networkd-conf.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** -- cgit v1.2.3-54-g00ecf From 1d88a271a69119635158bdc4009c38fbc4199997 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 4 Apr 2016 11:09:00 +0200 Subject: sd-device: fix crash if a device has many tags or devlinks strjoina() is unsafe to be used in an unbounded loop as alloca() has no error reporting. Thus devices with a large number of tags or devlinks trigger a segfault in device_properties_prepare() due to overflowing the stack. Rewrite the building of the "tags" and "devlinks" strings using GREEDY_REALLOC() and strpcpy() to work with arbitrarily long strings. This also avoids re-copying the entire string in each loop iteration. Before this commit we always appended one final ":" to "tags". Change this to start with an iniital ":" and for each tag append instead of prepend a ":". This unifies what happens for the first and all subsequent tags so that we can use a for loop. Fixes #2954 --- src/libsystemd/sd-device/sd-device.c | 37 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 8657e61cd9..e9f8970d2c 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -1457,15 +1457,20 @@ static int device_properties_prepare(sd_device *device) { return r; if (device->property_devlinks_outdated) { - char *devlinks = NULL; + _cleanup_free_ char *devlinks = NULL; + size_t devlinks_allocated = 0, devlinks_len = 0; const char *devlink; - devlink = sd_device_get_devlink_first(device); - if (devlink) - devlinks = strdupa(devlink); + for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) { + char *e; - while ((devlink = sd_device_get_devlink_next(device))) - devlinks = strjoina(devlinks, " ", devlink); + if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2)) + return -ENOMEM; + if (devlinks_len > 0) + stpcpy(devlinks + devlinks_len++, " "); + e = stpcpy(devlinks + devlinks_len, devlink); + devlinks_len = e - devlinks; + } r = device_add_property_internal(device, "DEVLINKS", devlinks); if (r < 0) @@ -1475,17 +1480,23 @@ static int device_properties_prepare(sd_device *device) { } if (device->property_tags_outdated) { - char *tags = NULL; + _cleanup_free_ char *tags = NULL; + size_t tags_allocated = 0, tags_len = 0; const char *tag; - tag = sd_device_get_tag_first(device); - if (tag) - tags = strjoina(":", tag); + if (!GREEDY_REALLOC(tags, tags_allocated, 2)) + return -ENOMEM; + stpcpy(tags, ":"); + tags_len++; - while ((tag = sd_device_get_tag_next(device))) - tags = strjoina(tags, ":", tag); + for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) { + char *e; - tags = strjoina(tags, ":"); + if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 1)) + return -ENOMEM; + e = stpcpy(stpcpy(tags + tags_len, tag), ":"); + tags_len = e - tags; + } r = device_add_property_internal(device, "TAGS", tags); if (r < 0) -- cgit v1.2.3-54-g00ecf From 89d034822075dfa8d18af8182019028cc428a1b5 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Tue, 5 Apr 2016 10:30:45 +0200 Subject: polkit: don't start polkit agent when running as root On the server side we already bypass the polkit checks if the caller is root (see the sd_bus_query_sender_privilege() call in bus_verify_polkit_async()). So there is no reason to invoke polkit when running systemctl/machinectl/loginctl/timedatectl as root. Fixes #2748 --- src/shared/spawn-polkit-agent.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c index cf3c8ad5a3..7dae4d14fe 100644 --- a/src/shared/spawn-polkit-agent.c +++ b/src/shared/spawn-polkit-agent.c @@ -44,6 +44,10 @@ int polkit_agent_open(void) { if (agent_pid > 0) return 0; + /* Clients that run as root don't need to activate/query polkit */ + if (geteuid() == 0) + return 0; + /* We check STDIN here, not STDOUT, since this is about input, * not output */ if (!isatty(STDIN_FILENO)) -- cgit v1.2.3-54-g00ecf From 2ce8d27b1f4e7c53e57d345ba471fb1f547d390c Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Tue, 5 Apr 2016 06:13:41 +0000 Subject: tests: don't rely on underlying fs in udev-test, use tmpfs instead Fixes: #457 --- src/test/test-udev.c | 10 +++++----- test/udev-test.pl | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/test/test-udev.c b/src/test/test-udev.c index d01789fe08..64ef08652c 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -40,11 +40,11 @@ static int fake_filesystems(void) { const char *target; const char *error; } fakefss[] = { - { "test/sys", "/sys", "failed to mount test /sys" }, - { "test/dev", "/dev", "failed to mount test /dev" }, - { "test/run", "/run", "failed to mount test /run" }, - { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, - { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" }, + { "test/tmpfs/sys", "/sys", "failed to mount test /sys" }, + { "test/dev", "/dev", "failed to mount test /dev" }, + { "test/run", "/run", "failed to mount test /run" }, + { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, + { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" }, }; unsigned int i; int err; diff --git a/test/udev-test.pl b/test/udev-test.pl index b047493f6b..3c8a480d0f 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -29,6 +29,7 @@ my $udev_bin_gdb = "gdb --args $udev_bin"; my $udev_bin_strace = "strace -efile $udev_bin"; my $udev_dev = "test/dev"; my $udev_run = "test/run"; +my $udev_tmpfs = "test/tmpfs"; my $udev_rules_dir = "$udev_run/udev/rules.d"; my $udev_rules = "$udev_rules_dir/udev-test.rules"; my $EXIT_TEST_SKIP = 77; @@ -1412,6 +1413,12 @@ sub udev_setup { chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n"; chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n"; + system("umount", "$udev_tmpfs"); + system("rm", "-rf", "$udev_tmpfs"); + mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n"; + system("mount", "-o", "rw,mode=755,nosuid,noexec,nodev", "-t", "tmpfs", "tmpfs", "$udev_tmpfs") && die "unable to mount tmpfs"; + system("cp", "-r", "test/sys/", "$udev_tmpfs") && die "unable to copy test/sys"; + system("rm", "-rf", "$udev_run"); } @@ -1545,6 +1552,8 @@ print "$error errors occurred\n\n"; # cleanup system("rm", "-rf", "$udev_dev"); system("rm", "-rf", "$udev_run"); +system("umount", "$udev_tmpfs"); +system("rm", "-rf", "$udev_tmpfs"); if ($error > 0) { exit(1); -- cgit v1.2.3-54-g00ecf From 5488e52d285314c7535c87ee9aecadbc169db006 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Tue, 5 Apr 2016 00:27:15 +0000 Subject: activate: improve SIGCHLD handler * Don't lose children exit codes * Don't receive notification when child processes stop Eliminates annoying "Child died"-messages: $ ./systemd-socket-activate -l 2000 --inetd -a cat ^Z [1]+ Stopped ./systemd-socket-activate -l 2000 --inetd -a cat $ bg %1 [1]+ ./systemd-socket-activate -l 2000 --inetd -a cat & Child 15657 died with code 20 $ ps u 15657 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND ubuntu 15657 0.0 0.0 4540 680 pts/2 S 00:34 0:00 cat * Don't fail to reap some zombie children Fixes $ ./systemd-socket-activate -l 2000 --inetd -a cat & $ for i in {1..1000}; do echo a | nc localhost 2000 & done $ ps f ... 18235 pts/2 Ss 0:01 -bash 15849 pts/2 S 0:00 \_ ./systemd-socket-activate -l 2000 --inetd -a cat 16081 pts/2 Z 0:00 | \_ [cat] 16381 pts/2 Z 0:00 | \_ [cat] and many more zombies ... --- src/activate/activate.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/activate/activate.c b/src/activate/activate.c index 8ac8dd8e72..a0cfc22000 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -316,19 +316,31 @@ static int do_accept(const char* name, char **argv, char **envp, int fd) { } /* SIGCHLD handler. */ -static void sigchld_hdl(int sig, siginfo_t *t, void *data) { +static void sigchld_hdl(int sig) { PROTECT_ERRNO; - log_info("Child %d died with code %d", t->si_pid, t->si_status); + for (;;) { + siginfo_t si; + int r; - /* Wait for a dead child. */ - (void) waitpid(t->si_pid, NULL, 0); + si.si_pid = 0; + r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG); + if (r < 0) { + if (errno != ECHILD) + log_error_errno(errno, "Failed to reap children: %m"); + return; + } + if (si.si_pid == 0) + return; + + log_info("Child %d died with code %d", si.si_pid, si.si_status); + } } static int install_chld_handler(void) { static const struct sigaction act = { - .sa_flags = SA_SIGINFO, - .sa_sigaction = sigchld_hdl, + .sa_flags = SA_NOCLDSTOP, + .sa_handler = sigchld_hdl, }; int r; -- cgit v1.2.3-54-g00ecf From d79ca7a622abbb0df6f5166cc0e4669373d9a614 Mon Sep 17 00:00:00 2001 From: Klearchos Chaloulos Date: Tue, 5 Apr 2016 13:47:04 +0300 Subject: journal-upload: Update watchdog while in curl_easy_perform It is observed that a combination of high log throughput, low I/O speed on journal remote side and many nodes uploading simultaneously caused the journal-upload process to dump core because of watchdog starvation. This is caused because journal-upload stays in curl_easy_perform(), because it cannot upload fast enough to reach the end of the journal. Currently journal-upload will return from curl_easy_perform() only when the end of the journal is reached. Therefore a check is added in journal_input_callback(), which will update the watchdog if the elapsed time since the start of the uploading process is greater than WATCHDOG_USEC/2. --- src/journal-remote/journal-upload-journal.c | 25 +++++++++++++++++++++++++ src/journal-remote/journal-upload.c | 1 + src/journal-remote/journal-upload.h | 1 + 3 files changed, 27 insertions(+) (limited to 'src') diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index e61b6bc68f..ac6eb58a9f 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -25,6 +25,7 @@ #include "log.h" #include "utf8.h" #include "util.h" +#include "sd-daemon.h" /** * Write up to size bytes to buf. Return negative on error, and number of @@ -242,6 +243,28 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { assert_not_reached("WTF?"); } +static inline void check_update_watchdog(Uploader *u) { + usec_t watchdog_usec; + static usec_t before; + usec_t after; + usec_t elapsed_time; + + if (sd_watchdog_enabled(false, &watchdog_usec) < 0) + return; + if (u->reset_reference_timestamp) { + before = now(CLOCK_MONOTONIC); + u->reset_reference_timestamp = false; + } else { + after = now(CLOCK_MONOTONIC); + elapsed_time = usec_sub(after, before); + if (elapsed_time > watchdog_usec / 2) { + log_debug("Update watchdog timer"); + sd_notify(false, "WATCHDOG=1"); + u->reset_reference_timestamp = true; + } + } +} + static size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void *userp) { Uploader *u = userp; int r; @@ -252,6 +275,8 @@ static size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void assert(u); assert(nmemb <= SSIZE_MAX / size); + check_update_watchdog(u); + j = u->journal; while (j && filled < size * nmemb) { diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 6e1c3bb9ef..f2e9117f9f 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -494,6 +494,7 @@ static int perform_upload(Uploader *u) { assert(u); + u->reset_reference_timestamp = true; code = curl_easy_perform(u->easy); if (code) { if (u->error[0]) diff --git a/src/journal-remote/journal-upload.h b/src/journal-remote/journal-upload.h index b8cd04d527..a31735bd08 100644 --- a/src/journal-remote/journal-upload.h +++ b/src/journal-remote/journal-upload.h @@ -48,6 +48,7 @@ typedef struct Uploader { size_t entries_sent; char *last_cursor, *current_cursor; + bool reset_reference_timestamp; } Uploader; #define JOURNAL_UPLOAD_POLL_TIMEOUT (10 * USEC_PER_SEC) -- cgit v1.2.3-54-g00ecf From 0aa176a751a00b5645007c4d0763078ce2824aba Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 5 Apr 2016 20:27:48 -0400 Subject: journal-upload: make watchdog state non-static Also parse watchdog config when creating the Uploader object. --- src/journal-remote/journal-upload-journal.c | 22 ++++++++-------------- src/journal-remote/journal-upload.c | 4 +++- src/journal-remote/journal-upload.h | 4 +++- 3 files changed, 14 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index ac6eb58a9f..8ce8e1895e 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -244,24 +244,18 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) { } static inline void check_update_watchdog(Uploader *u) { - usec_t watchdog_usec; - static usec_t before; usec_t after; usec_t elapsed_time; - if (sd_watchdog_enabled(false, &watchdog_usec) < 0) + if (u->watchdog_usec <= 0) return; - if (u->reset_reference_timestamp) { - before = now(CLOCK_MONOTONIC); - u->reset_reference_timestamp = false; - } else { - after = now(CLOCK_MONOTONIC); - elapsed_time = usec_sub(after, before); - if (elapsed_time > watchdog_usec / 2) { - log_debug("Update watchdog timer"); - sd_notify(false, "WATCHDOG=1"); - u->reset_reference_timestamp = true; - } + + after = now(CLOCK_MONOTONIC); + elapsed_time = usec_sub(after, u->watchdog_timestamp); + if (elapsed_time > u->watchdog_usec / 2) { + log_debug("Update watchdog timer"); + sd_notify(false, "WATCHDOG=1"); + u->watchdog_timestamp = after; } } diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index f2e9117f9f..4647cfdeb3 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -463,6 +463,8 @@ static int setup_uploader(Uploader *u, const char *url, const char *state_file) if (r < 0) return log_error_errno(r, "Failed to set up signals: %m"); + (void) sd_watchdog_enabled(false, &u->watchdog_usec); + return load_cursor_state(u); } @@ -494,7 +496,7 @@ static int perform_upload(Uploader *u) { assert(u); - u->reset_reference_timestamp = true; + u->watchdog_timestamp = now(CLOCK_MONOTONIC); code = curl_easy_perform(u->easy); if (code) { if (u->error[0]) diff --git a/src/journal-remote/journal-upload.h b/src/journal-remote/journal-upload.h index a31735bd08..5711905f86 100644 --- a/src/journal-remote/journal-upload.h +++ b/src/journal-remote/journal-upload.h @@ -4,6 +4,7 @@ #include "sd-event.h" #include "sd-journal.h" +#include "time-util.h" typedef enum { ENTRY_CURSOR = 0, /* Nothing actually written yet. */ @@ -48,7 +49,8 @@ typedef struct Uploader { size_t entries_sent; char *last_cursor, *current_cursor; - bool reset_reference_timestamp; + usec_t watchdog_timestamp; + usec_t watchdog_usec; } Uploader; #define JOURNAL_UPLOAD_POLL_TIMEOUT (10 * USEC_PER_SEC) -- cgit v1.2.3-54-g00ecf From 855005230ba72d96ee6e82832f3776bdb1628db6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 5 Apr 2016 22:44:42 -0400 Subject: machinectl: add --value option --- man/machinectl.xml | 7 +++++++ src/machine/machinectl.c | 12 ++++++++++-- src/shared/bus-util.c | 4 ++-- src/shared/bus-util.h | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/man/machinectl.xml b/man/machinectl.xml index 967ca01470..cee4bb72ce 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -136,6 +136,13 @@ (.). + + + + When printing properties with show, only print the value, + and skip the property name and =. + + diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index e49c90fd1b..c71acbcaba 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -61,6 +61,7 @@ static char **arg_property = NULL; static bool arg_all = false; +static bool arg_value = false; static bool arg_full = false; static bool arg_no_pager = false; static bool arg_legend = true; @@ -680,7 +681,7 @@ static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line *new_line = true; - r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all); + r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all); if (r < 0) log_error_errno(r, "Could not get properties: %m"); @@ -929,7 +930,7 @@ static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) *new_line = true; - r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all); + r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all); if (r < 0) log_error_errno(r, "Could not get properties: %m"); @@ -2356,6 +2357,7 @@ static int help(int argc, char *argv[], void *userdata) { " -p --property=NAME Show only properties by this name\n" " -q --quiet Suppress output\n" " -a --all Show all properties, including empty ones\n" + " --value When showing properties, only print the value\n" " -l --full Do not ellipsize output\n" " --kill-who=WHO Who to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" @@ -2418,6 +2420,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION = 0x100, ARG_NO_PAGER, ARG_NO_LEGEND, + ARG_VALUE, ARG_KILL_WHO, ARG_READ_ONLY, ARG_MKDIR, @@ -2434,6 +2437,7 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "property", required_argument, NULL, 'p' }, { "all", no_argument, NULL, 'a' }, + { "value", no_argument, NULL, ARG_VALUE }, { "full", no_argument, NULL, 'l' }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, @@ -2485,6 +2489,10 @@ static int parse_argv(int argc, char *argv[]) { arg_all = true; break; + case ARG_VALUE: + arg_value = true; + break; + case 'l': arg_full = true; break; diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 85f8280773..0fa04da935 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -930,7 +930,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b return 0; } -int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) { +int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -970,7 +970,7 @@ int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, ch if (r < 0) return r; - r = bus_print_property(name, reply, false, all); + r = bus_print_property(name, reply, value, all); if (r < 0) return r; if (r == 0) { diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 65eca9ac56..1a0841ce81 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -79,7 +79,7 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus); int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all); -int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all); +int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all); int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); -- cgit v1.2.3-54-g00ecf From e138e7d7fc38021a63a913a840b21db2d15603ad Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 5 Apr 2016 23:03:46 -0400 Subject: machinectl: indentation fix --- src/machine/machinectl.c | 68 +++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index c71acbcaba..1d3264a1de 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -130,15 +130,14 @@ static int list_machines(int argc, char *argv[], void *userdata) { pager_open(arg_no_pager, false); - r = sd_bus_call_method( - bus, - "org.freedesktop.machine1", - "/org/freedesktop/machine1", - "org.freedesktop.machine1.Manager", - "ListMachines", - &error, - &reply, - NULL); + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "ListMachines", + &error, + &reply, + NULL); if (r < 0) { log_error("Could not get machines: %s", bus_error_message(&error, -r)); return r; @@ -233,15 +232,14 @@ static int list_images(int argc, char *argv[], void *userdata) { pager_open(arg_no_pager, false); - r = sd_bus_call_method( - bus, - "org.freedesktop.machine1", - "/org/freedesktop/machine1", - "org.freedesktop.machine1.Manager", - "ListImages", - &error, - &reply, - ""); + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "ListImages", + &error, + &reply, + ""); if (r < 0) { log_error("Could not get images: %s", bus_error_message(&error, -r)); return r; @@ -714,15 +712,14 @@ static int show_machine(int argc, char *argv[], void *userdata) { for (i = 1; i < argc; i++) { const char *path = NULL; - r = sd_bus_call_method( - bus, - "org.freedesktop.machine1", - "/org/freedesktop/machine1", - "org.freedesktop.machine1.Manager", - "GetMachine", - &error, - &reply, - "s", argv[i]); + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "GetMachine", + &error, + &reply, + "s", argv[i]); if (r < 0) { log_error("Could not get path to machine: %s", bus_error_message(&error, -r)); return r; @@ -2184,15 +2181,14 @@ static int list_transfers(int argc, char *argv[], void *userdata) { pager_open(arg_no_pager, false); - r = sd_bus_call_method( - bus, - "org.freedesktop.import1", - "/org/freedesktop/import1", - "org.freedesktop.import1.Manager", - "ListTransfers", - &error, - &reply, - NULL); + r = sd_bus_call_method(bus, + "org.freedesktop.import1", + "/org/freedesktop/import1", + "org.freedesktop.import1.Manager", + "ListTransfers", + &error, + &reply, + NULL); if (r < 0) { log_error("Could not get transfers: %s", bus_error_message(&error, -r)); return r; -- cgit v1.2.3-54-g00ecf From 8e98476e143519aa3f0a2e0db6fccfe9ef134cbc Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 4 Mar 2016 11:28:04 -0500 Subject: string-table: split long definitions --- src/basic/string-table.h | 54 +++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/basic/string-table.h b/src/basic/string-table.h index b180488fe8..d88625fca7 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -56,26 +56,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ } -#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) - -#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) - -/* For string conversions where numbers are also acceptable */ -#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ - int name##_to_string_alloc(type i, char **str) { \ +#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,scope) \ + scope int name##_to_string_alloc(type i, char **str) { \ char *s; \ if (i < 0 || i > max) \ return -ERANGE; \ @@ -89,7 +71,9 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k } \ *str = s; \ return 0; \ - } \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \ type name##_from_string(const char *s) { \ type i; \ unsigned u = 0; \ @@ -102,4 +86,32 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) u; \ return (type) -1; \ } \ + + +#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) + +#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) + +/* For string conversions where numbers are also acceptable */ +#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \ struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static) -- cgit v1.2.3-54-g00ecf From 2abb5b3b10e3a9ed8ffd0189e8a1828ec086f69e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 4 Mar 2016 10:50:45 -0500 Subject: test-nss: test the resolution of various names nss-dns is also "tested". It should be almost always available, and provides a reference for comparison. --- .gitignore | 1 + Makefile.am | 11 ++ configure.ac | 4 +- src/basic/nss-util.h | 19 +++ src/test/test-nss.c | 448 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 src/test/test-nss.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 18db046cac..0e467b0c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -230,6 +230,7 @@ /test-network /test-network-tables /test-ns +/test-nss /test-parse-util /test-path /test-path-lookup diff --git a/Makefile.am b/Makefile.am index 0f17bad8b1..dc9f9afa9c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4777,6 +4777,17 @@ EXTRA_DIST += \ units/systemd-timesyncd.service.in \ src/timesync/timesyncd.conf.in +# ------------------------------------------------------------------------------ +test_nss_SOURCES = \ + src/test/test-nss.c + +test_nss_LDADD = \ + libsystemd-internal.la \ + -ldl + +tests += \ + test-nss + # ------------------------------------------------------------------------------ if HAVE_MYHOSTNAME libnss_myhostname_la_SOURCES = \ diff --git a/configure.ac b/configure.ac index e55d1a02a6..a02185d252 100644 --- a/configure.ac +++ b/configure.ac @@ -1008,9 +1008,9 @@ have_machined=no AC_ARG_ENABLE(machined, AS_HELP_STRING([--disable-machined], [disable machine daemon])) if test "x$enable_machined" != "xno"; then have_machined=yes + AC_DEFINE(HAVE_MACHINED, [1], [systemd-machined is enabled]) fi AM_CONDITIONAL(ENABLE_MACHINED, [test "$have_machined" = "yes"]) -AS_IF([test "$have_machined" = "yes"], [ AC_DEFINE(HAVE_MACHINED, [1], [Machined support available]) ]) # ------------------------------------------------------------------------------ have_importd=no @@ -1120,6 +1120,7 @@ AS_IF([test "x$enable_resolved" != "xno"], [ have_resolved=yes M4_DEFINES="$M4_DEFINES -DENABLE_RESOLVED" + AC_DEFINE(HAVE_RESOLVED, [1], [systemd-resolved is enabled]) ]) AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"]) @@ -1321,6 +1322,7 @@ if test "x$enable_myhostname" != "xno"; then AC_CHECK_FUNCS([gethostbyaddr gethostbyname gettimeofday inet_ntoa memset select socket strcspn strdup strerror strncasecmp strcasecmp strspn]) have_myhostname=yes + AC_DEFINE(HAVE_MYHOSTNAME, [1], [nss-myhostname is enabled]) fi AM_CONDITIONAL(HAVE_MYHOSTNAME, [test "$have_myhostname" = "yes"]) diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index 14e950869d..bf7c4854fc 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -171,6 +171,19 @@ typedef enum nss_status (*_nss_gethostbyname3_r_t)( int32_t *ttlp, char **canonp); +typedef enum nss_status (*_nss_gethostbyname2_r_t)( + const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop); + +typedef enum nss_status (*_nss_gethostbyname_r_t)( + const char *name, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop); + typedef enum nss_status (*_nss_gethostbyaddr2_r_t)( const void* addr, socklen_t len, int af, @@ -178,3 +191,9 @@ typedef enum nss_status (*_nss_gethostbyaddr2_r_t)( char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp); +typedef enum nss_status (*_nss_gethostbyaddr_r_t)( + const void* addr, socklen_t len, + int af, + struct hostent *host, + char *buffer, size_t buflen, + int *errnop, int *h_errnop); diff --git a/src/test/test-nss.c b/src/test/test-nss.c new file mode 100644 index 0000000000..9c13288d2e --- /dev/null +++ b/src/test/test-nss.c @@ -0,0 +1,448 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#include +#include + +#include "log.h" +#include "nss-util.h" +#include "path-util.h" +#include "string-util.h" +#include "alloc-util.h" +#include "in-addr-util.h" +#include "hexdecoct.h" +#include "af-list.h" +#include "stdio-util.h" +#include "strv.h" +#include "errno-list.h" +#include "hostname-util.h" +#include "local-addresses.h" + +static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) { + switch (status) { + case NSS_STATUS_TRYAGAIN: + return "NSS_STATUS_TRYAGAIN"; + case NSS_STATUS_UNAVAIL: + return "NSS_STATUS_UNAVAIL"; + case NSS_STATUS_NOTFOUND: + return "NSS_STATUS_NOTFOUND"; + case NSS_STATUS_SUCCESS: + return "NSS_STATUS_SUCCESS"; + case NSS_STATUS_RETURN: + return "NSS_STATUS_RETURN"; + default: + snprintf(buf, buf_len, "%i", status); + return buf; + } +}; + +static const char* af_to_string(int family, char *buf, size_t buf_len) { + const char *name; + + if (family == AF_UNSPEC) + return "*"; + + name = af_to_name(family); + if (name) + return name; + + snprintf(buf, buf_len, "%i", family); + return buf; +} + +static void* open_handle(const char* dir, const char* module, int flags) { + const char *path; + void *handle; + + if (dir) + path = strjoina(dir, "/.libs/libnss_", module, ".so.2"); + else + path = strjoina("libnss_", module, ".so.2"); + + handle = dlopen(path, flags); + assert_se(handle); + return handle; +} + +static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) { + const struct gaih_addrtuple *it; + int n = 0; + + for (it = tuples; it; it = it->next) { + _cleanup_free_ char *a = NULL; + union in_addr_union u; + int r; + char family_name[DECIMAL_STR_MAX(int)]; + char ifname[IF_NAMESIZE]; + + memcpy(&u, it->addr, 16); + r = in_addr_to_string(it->family, &u, &a); + assert_se(r == 0 || r == -EAFNOSUPPORT); + if (r == -EAFNOSUPPORT) + assert_se((a = hexmem(it->addr, 16))); + + if (it->scopeid == 0) + goto numerical_index; + + if (if_indextoname(it->scopeid, ifname) == NULL) { + log_warning("if_indextoname(%d) failed: %m", it->scopeid); + numerical_index: + xsprintf(ifname, "%i", it->scopeid); + }; + + log_info(" \"%s\" %s %s %%%s", + it->name, + af_to_string(it->family, family_name, sizeof family_name), + a, + ifname); + n ++; + } + return n; +} + +static void print_struct_hostent(struct hostent *host, const char *canon) { + char **s; + + log_info(" \"%s\"", host->h_name); + STRV_FOREACH(s, host->h_aliases) + log_info(" alias \"%s\"", *s); + STRV_FOREACH(s, host->h_addr_list) { + union in_addr_union u; + _cleanup_free_ char *a = NULL; + char family_name[DECIMAL_STR_MAX(int)]; + int r; + + assert_se((unsigned) host->h_length == FAMILY_ADDRESS_SIZE(host->h_addrtype)); + memcpy(&u, *s, host->h_length); + r = in_addr_to_string(host->h_addrtype, &u, &a); + assert_se(r == 0); + log_info(" %s %s", + af_to_string(host->h_addrtype, family_name, sizeof family_name), + a); + } + if (canon) + log_info(" canonical: \"%s\"", canon); +} + +static void test_gethostbyname4_r(void *handle, const char *module, const char *name) { + const char *fname; + _nss_gethostbyname4_r_t f; + char buffer[2000]; + struct gaih_addrtuple *pat = NULL; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl, + and will access this variable through *ttlp, + so we need to set it to something. + I'm not sure if this is a bug in nss-dns + or not. */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + int n; + + fname = strjoina("_nss_", module, "_gethostbyname4_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl); + if (status == NSS_STATUS_SUCCESS) { + log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%tx errno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + pat ? (char*) pat - buffer : 0, + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + n = print_gaih_addrtuples(pat); + } else { + log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s", + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + pat, + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + n = 0; + } + + if (STR_IN_SET(module, "resolve", "mymachines") && status == NSS_STATUS_UNAVAIL) + return; + + if (STR_IN_SET(module, "myhostname", "resolve") && streq(name, "localhost")) { + assert_se(status == NSS_STATUS_SUCCESS); + assert_se(n == 2); + } +} + + +static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) { + const char *fname; + _nss_gethostbyname3_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl, + and will access this variable through *ttlp, + so we need to set it to something. + I'm not sure if this is a bug in nss-dns + or not. */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + char *canon; + char family_name[DECIMAL_STR_MAX(int)]; + + fname = strjoina("_nss_", module, "_gethostbyname3_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon); + log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, name, af_to_string(af, family_name, sizeof family_name), + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, canon); +} + +static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) { + const char *fname; + _nss_gethostbyname2_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + char family_name[DECIMAL_STR_MAX(int)]; + + fname = strjoina("_nss_", module, "_gethostbyname2_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, name, af_to_string(af, family_name, sizeof family_name), + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyname_r(void *handle, const char *module, const char *name) { + const char *fname; + _nss_gethostbyname_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + + fname = strjoina("_nss_", module, "_gethostbyname_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyaddr2_r(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + + const char *fname; + _nss_gethostbyaddr2_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + int32_t ttl = INT32_MAX; + _cleanup_free_ char *addr_pretty = NULL; + + fname = strjoina("_nss_", module, "_gethostbyaddr2_r"); + f = dlsym(handle, fname); + + log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno, + "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f); + if (!f) + return; + + assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0); + + status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, addr_pretty, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyaddr_r(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + + const char *fname; + _nss_gethostbyaddr_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + _cleanup_free_ char *addr_pretty = NULL; + + fname = strjoina("_nss_", module, "_gethostbyaddr_r"); + f = dlsym(handle, fname); + + log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno, + "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f); + if (!f) + return; + + assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0); + + status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, addr_pretty, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_byname(void *handle, const char *module, const char *name) { + test_gethostbyname4_r(handle, module, name); + puts(""); + + test_gethostbyname3_r(handle, module, name, AF_INET); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_INET6); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_UNSPEC); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_LOCAL); + puts(""); + + test_gethostbyname2_r(handle, module, name, AF_INET); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_INET6); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_UNSPEC); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_LOCAL); + puts(""); + + test_gethostbyname_r(handle, module, name); + puts(""); +} + +static void test_byaddr(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + test_gethostbyaddr2_r(handle, module, addr, len, af); + puts(""); + + test_gethostbyaddr_r(handle, module, addr, len, af); + puts(""); +} + +#ifdef HAVE_MYHOSTNAME +# define MODULE1 "myhostname\0" +#endif +#ifdef HAVE_RESOLVED +# define MODULE2 "resolve\0" +#endif +#ifdef HAVE_MACHINED +# define MODULE3 "mymachines\0" +#endif +#define MODULE4 "dns\0" + +int main(int argc, char **argv) { + _cleanup_free_ char *dir = NULL, *hostname = NULL; + const char *module; + + const uint32_t local_address_ipv4 = htonl(0x7F000001); + const uint32_t local_address_ipv4_2 = htonl(0x7F000002); + _cleanup_free_ struct local_address *addresses = NULL; + int n_addresses; + + log_set_max_level(LOG_INFO); + log_parse_environment(); + + dir = dirname_malloc(argv[0]); + assert_se(dir); + + hostname = gethostname_malloc(); + assert_se(hostname); + + n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses); + if (n_addresses < 0) { + log_info_errno(n_addresses, "Failed to query local addresses: %m"); + n_addresses = 0; + } + + NULSTR_FOREACH(module, MODULE1 MODULE2 MODULE3 MODULE4) { + void *handle; + const char *name; + int i; + + log_info("======== %s ========", module); + + handle = open_handle(streq(module, "dns") ? NULL : dir, + module, + RTLD_LAZY|RTLD_NODELETE); + NULSTR_FOREACH(name, "localhost\0" "gateway\0" "foo_no_such_host\0") + test_byname(handle, module, name); + + test_byname(handle, module, hostname); + + test_byaddr(handle, module, &local_address_ipv4, sizeof local_address_ipv4, AF_INET); + test_byaddr(handle, module, &local_address_ipv4_2, sizeof local_address_ipv4_2, AF_INET); + test_byaddr(handle, module, &in6addr_loopback, sizeof in6addr_loopback, AF_INET6); + + for (i = 0; i < n_addresses; i++) + test_byaddr(handle, module, + &addresses[i].address, + FAMILY_ADDRESS_SIZE(addresses[i].family), + addresses[i].family); + + dlclose(handle); + + log_info(" "); + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3-54-g00ecf From 82e4c2d656941a76d7c5f86d70cd8b435cb52860 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 15 Mar 2016 00:50:25 -0400 Subject: nss-myhostname: remove dead test of variable that was not set --- src/nss-myhostname/nss-myhostname.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 460a613b9d..2b83d127b7 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -480,7 +480,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r( return NSS_STATUS_NOTFOUND; found: - if (!canonical || (!additional && additional_from_hostname)) { + if (!canonical || additional_from_hostname) { hn = gethostname_malloc(); if (!hn) { *errnop = ENOMEM; @@ -490,8 +490,7 @@ found: if (!canonical) canonical = hn; - - if (!additional && additional_from_hostname) + else additional = hn; } -- cgit v1.2.3-54-g00ecf From 21d9e3f339659c82db950ff2b4c6b81956cfa917 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Wed, 6 Apr 2016 03:04:27 +0000 Subject: tests: don't rely on the underlying fs in test-udev (v2) * This reverts commit 646048b40a7b62c4e9bc59024ef6133613cda01b. Let's test really big numbers again * Don't be so brutal: use rmdir instead of rm -rf As suggested https://github.com/systemd/systemd/pull/2966#issuecomment-205751680 --- src/test/test-udev.c | 2 +- test/sys.tar.xz | Bin 261380 -> 165116 bytes test/udev-test.pl | 22 +++++++++++----------- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 64ef08652c..8522e9925c 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -41,7 +41,7 @@ static int fake_filesystems(void) { const char *error; } fakefss[] = { { "test/tmpfs/sys", "/sys", "failed to mount test /sys" }, - { "test/dev", "/dev", "failed to mount test /dev" }, + { "test/tmpfs/dev", "/dev", "failed to mount test /dev" }, { "test/run", "/run", "failed to mount test /run" }, { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" }, diff --git a/test/sys.tar.xz b/test/sys.tar.xz index 052c77d182..49ee8027b2 100644 Binary files a/test/sys.tar.xz and b/test/sys.tar.xz differ diff --git a/test/udev-test.pl b/test/udev-test.pl index 3c8a480d0f..87041b1c36 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -27,9 +27,10 @@ my $strace = 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_bin_strace = "strace -efile $udev_bin"; -my $udev_dev = "test/dev"; my $udev_run = "test/run"; my $udev_tmpfs = "test/tmpfs"; +my $udev_sys = "${udev_tmpfs}/sys"; +my $udev_dev = "${udev_tmpfs}/dev"; my $udev_rules_dir = "$udev_run/udev/rules.d"; my $udev_rules = "$udev_rules_dir/udev-test.rules"; my $EXIT_TEST_SKIP = 77; @@ -703,7 +704,7 @@ EOF desc => "big major number test", devpath => "/devices/virtual/misc/misc-fake1", exp_name => "node", - exp_majorminor => "511:1", + exp_majorminor => "4095:1", rules => < "big major and big minor number test", devpath => "/devices/virtual/misc/misc-fake89999", exp_name => "node", - exp_majorminor => "511:89999", + exp_majorminor => "4095:89999", rules => < 0) { exit(1); -- cgit v1.2.3-54-g00ecf From f5e754e0d78596a8ff41859b792099cf08c6a08d Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Wed, 6 Apr 2016 09:20:34 +0200 Subject: machine-id-setup: simplify by using prefix_roota --- src/core/machine-id-setup.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 9e6b3d3292..7b25349c07 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -120,10 +120,7 @@ static int generate_machine_id(char id[34], const char *root) { assert(id); - if (isempty(root)) - dbus_machine_id = "/var/lib/dbus/machine-id"; - else - dbus_machine_id = strjoina(root, "/var/lib/dbus/machine-id"); + dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id"); /* 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); @@ -203,18 +200,8 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) { 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); - } + etc_machine_id = prefix_roota(root, "/etc/machine-id"); + run_machine_id = prefix_roota(root, "/run/machine-id"); RUN_WITH_UMASK(0000) { /* We create this 0444, to indicate that this isn't really @@ -301,14 +288,7 @@ int machine_id_commit(const char *root) { char id[34]; /* 32 + \n + \0 */ int r; - if (isempty(root)) - etc_machine_id = "/etc/machine-id"; - else { - char *x; - - x = strjoina(root, "/etc/machine-id"); - etc_machine_id = path_kill_slashes(x); - } + etc_machine_id = prefix_roota(root, "/etc/machine-id"); r = path_is_mount_point(etc_machine_id, 0); if (r < 0) -- cgit v1.2.3-54-g00ecf From 817ec8cc819787240efda834483d8a7a512d2933 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Wed, 6 Apr 2016 23:50:39 +0200 Subject: sd-device: Allocate enough room for tags string Fix commit 1d88a2: We need to allocate another byte for building the "tags" string, as we append an extra ':' and still need the NUL terminator. --- src/libsystemd/sd-device/sd-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index e9f8970d2c..e787cb69d3 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -1492,7 +1492,7 @@ static int device_properties_prepare(sd_device *device) { for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) { char *e; - if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 1)) + if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2)) return -ENOMEM; e = stpcpy(stpcpy(tags + tags_len, tag), ":"); tags_len = e - tags; -- cgit v1.2.3-54-g00ecf From c8cf4dc1e52335eb67823c3c4fa066578e016608 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 7 Apr 2016 14:29:07 -0400 Subject: lldp: replace if with assert_cc LLDP_TX_HOLD or one of the other variables might be changed in the future resulting in a silent error here if the if was just removed. Replacement for #2983. --- src/network/networkd-lldp-tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index 5af2a31ea7..c940e63052 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -239,9 +239,8 @@ static int link_send_lldp(Link *link) { (void) gethostname_strict(&hostname); (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL); + assert_cc(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1 <= (UINT16_MAX - 1) * USEC_PER_SEC); ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC); - if (ttl > (usec_t) UINT16_MAX) - ttl = (usec_t) UINT16_MAX; caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ? SD_LLDP_SYSTEM_CAPABILITIES_ROUTER : -- cgit v1.2.3-54-g00ecf From 071e0b8b3a698e73bcaecba09ffccab5553d2365 Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Thu, 7 Apr 2016 23:48:29 +0000 Subject: core: downgrade warning about duplicate device names again Pull request #2412 seemed to have unintentionally reverted 5259bcf6a638d8d489db1ddefd55327aa15f3e51, thus reintroducing https://bugs.freedesktop.org/show_bug.cgi?id=90386. This commit reverts that part of the commit, changing the log level to debug again. --- src/core/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/device.c b/src/core/device.c index 28e4039da2..0671620a3e 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -322,7 +322,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa /* This unit is in plugged state: we're sure it's * attached to a device. */ if (!path_equal(DEVICE(u)->sysfs, sysfs)) { - log_unit_error(u, "Dev %s appeared twice with different sysfs paths %s and %s", + log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); return -EEXIST; } -- cgit v1.2.3-54-g00ecf From 0229100b6ccf13247f489da318293f21d2a51b40 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:02 -0400 Subject: network: check return value CID #1349698. --- src/network/networkd-address-pool.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c index d9d487d805..ebc6c9eb9e 100644 --- a/src/network/networkd-address-pool.c +++ b/src/network/networkd-address-pool.c @@ -148,8 +148,12 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union for (;;) { if (!address_pool_prefix_is_taken(p, &u, prefixlen)) { _cleanup_free_ char *s = NULL; + int r; + + r = in_addr_to_string(p->family, &u, &s); + if (r < 0) + return r; - in_addr_to_string(p->family, &u, &s); log_debug("Found range %s/%u", strna(s), prefixlen); *found = u; -- cgit v1.2.3-54-g00ecf From 164d025dd3c92b9643f5e1d01cb5c9a8987fc2dc Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:15 -0400 Subject: resolved: handle oom properly CID #1349699-1349700. --- src/resolve/resolved-bus.c | 5 +++-- src/resolve/resolved-dns-transaction.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 16cae8c1e5..33f7c61557 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -424,8 +424,9 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (added <= 0) { _cleanup_free_ char *ip = NULL; - in_addr_to_string(q->request_family, &q->request_address, &ip); - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip)); + (void) in_addr_to_string(q->request_family, &q->request_address, &ip); + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, + "Address '%s' does not have any RR of requested type", strnull(ip)); goto finish; } diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index a5129c201e..081131ede0 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -262,7 +262,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { if (manager_our_packet(t->scope->manager, p) != 0) return; - in_addr_to_string(p->family, &p->sender, &pretty); + (void) in_addr_to_string(p->family, &p->sender, &pretty); log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.", t->id, @@ -270,7 +270,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", af_to_name_short(t->scope->family), - pretty); + strnull(pretty)); /* RFC 4795, Section 4.1 says that the peer with the * lexicographically smaller IP address loses */ -- cgit v1.2.3-54-g00ecf From 045e00cf16c47bc516c0823d059b7548f3ce9c7c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:18 -0400 Subject: udevd: use (void) to silence coverity CID #1351429. --- src/udev/udevd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 243df7386f..e9dd2f47c7 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -400,10 +400,11 @@ static void worker_spawn(Manager *manager, struct event *event) { goto out; } - /* request TERM signal if parent exits */ - prctl(PR_SET_PDEATHSIG, SIGTERM); + /* Request TERM signal if parent exits. + Ignore error, not much we can do in that case. */ + (void) prctl(PR_SET_PDEATHSIG, SIGTERM); - /* reset OOM score, we only protect the main daemon */ + /* Reset OOM score, we only protect the main daemon. */ write_string_file("/proc/self/oom_score_adj", "0", 0); for (;;) { -- cgit v1.2.3-54-g00ecf From b3b90a25f3fcae12b2752ed85ec1a669e11208d8 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:21 -0400 Subject: udevadm: assert return value This mirrors what we do in now(). CID #1351755. --- src/udev/udevadm-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index b5f7f0d512..c0ef073476 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -40,7 +40,7 @@ static void sig_handler(int signum) { static void print_device(struct udev_device *device, const char *source, int prop) { struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); + assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); printf("%-6s[%"PRI_TIME".%06ld] %-8s %s (%s)\n", source, ts.tv_sec, ts.tv_nsec/1000, -- cgit v1.2.3-54-g00ecf From edfd706d9cb85a1195b6b575468db90744e13a6e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:23 -0400 Subject: import: use (void) more CID #1299018-9. --- src/core/path.c | 8 +++----- src/import/curl-util.c | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/path.c b/src/core/path.c index 6ac9b8b90d..426c4ad299 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -110,16 +110,14 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) { } else { exists = true; - /* Path exists, we don't need to watch parent - too closely. */ + /* Path exists, we don't need to watch parent too closely. */ if (oldslash) { char *cut2 = oldslash + (oldslash == s->path); char tmp2 = *cut2; *cut2 = '\0'; - inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF); - /* Error is ignored, the worst can happen is - we get spurious events. */ + (void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF); + /* Error is ignored, the worst can happen is we get spurious events. */ *cut2 = tmp2; } diff --git a/src/import/curl-util.c b/src/import/curl-util.c index a04c8c49ff..6990c47f48 100644 --- a/src/import/curl-util.c +++ b/src/import/curl-util.c @@ -137,7 +137,7 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0) return -1; - sd_event_source_set_description(io, "curl-io"); + (void) sd_event_source_set_description(io, "curl-io"); r = hashmap_put(g->ios, FD_TO_PTR(s), io); if (r < 0) { @@ -204,7 +204,7 @@ static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata if (sd_event_add_time(g->event, &g->timer, clock_boottime_or_monotonic(), usec, 0, curl_glue_on_timer, g) < 0) return -1; - sd_event_source_set_description(g->timer, "curl-timer"); + (void) sd_event_source_set_description(g->timer, "curl-timer"); } return 0; -- cgit v1.2.3-54-g00ecf From 94edd38e1d2559f6685629eba71669ab24023c5d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:29 -0400 Subject: basic/util: check return value of dup2 in fork_agent() CID #1304689. --- src/basic/util.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/util.c b/src/basic/util.c index ea1bed7ceb..f1e3bd5b48 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -419,13 +419,17 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa _exit(EXIT_FAILURE); } - if (!stdout_is_tty) - dup2(fd, STDOUT_FILENO); + if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) { + log_error_errno(errno, "Failed to dup2 /dev/tty: %m"); + _exit(EXIT_FAILURE); + } - if (!stderr_is_tty) - dup2(fd, STDERR_FILENO); + if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) { + log_error_errno(errno, "Failed to dup2 /dev/tty: %m"); + _exit(EXIT_FAILURE); + } - if (fd > 2) + if (fd > STDERR_FILENO) close(fd); } -- cgit v1.2.3-54-g00ecf From 9d4e7d1380927da67c25b57344f50ea1692aad96 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:42 -0400 Subject: sd-resolve: ignore error in pthread_join() CID #1338424. --- src/libsystemd/sd-resolve/sd-resolve.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 37585048b8..d8303e2e69 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -579,9 +579,10 @@ static void resolve_free(sd_resolve *resolve) { (void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL); } - /* Now terminate them and wait until they are gone. */ + /* Now terminate them and wait until they are gone. + If we get an error than most likely the thread already exited. */ for (i = 0; i < resolve->n_valid_workers; i++) - pthread_join(resolve->workers[i], NULL); + (void) pthread_join(resolve->workers[i], NULL); /* Close all communication channels */ for (i = 0; i < _FD_MAX; i++) -- cgit v1.2.3-54-g00ecf From ddea446252fad05bc28ede2ee2043f8d96addd65 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:08:54 -0400 Subject: journal: assert gcry_mpi_scan succeeded It might be nicer to propagate the error to the caller, but that'd be a bigger refactoring. This shouldn't really fail, so just add an assert. CID #1349697. --- src/journal/fsprg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c index 8956eb1d58..612b10f3a9 100644 --- a/src/journal/fsprg.c +++ b/src/journal/fsprg.c @@ -58,7 +58,7 @@ static gcry_mpi_t mpi_import(const void *buf, size_t buflen) { gcry_mpi_t h; unsigned len; - gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL); + assert_se(gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0); len = (gcry_mpi_get_nbits(h) + 7) / 8; assert(len <= buflen); assert(gcry_mpi_cmp_ui(h, 0) >= 0); -- cgit v1.2.3-54-g00ecf From d929b0f98bf2c3b1698f760799a1999b878724f6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:09:06 -0400 Subject: nspawn: ignore failure to chdir CID #1322380. --- src/nspawn/nspawn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index eb89916b7e..c96a04cd5e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2648,7 +2648,8 @@ static int inner_child( execvpe(arg_parameters[0], arg_parameters, env_use); else { if (!arg_chdir) - chdir(home ?: "/root"); + /* If we cannot change the directory, we'll end up in /, that is expected. */ + (void) chdir(home ?: "/root"); execle("/bin/bash", "-bash", NULL, env_use); execle("/bin/sh", "-sh", NULL, env_use); -- cgit v1.2.3-54-g00ecf From 0b9aa2701636bb7f068f7d4d254f820834bf6ede Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:09:09 -0400 Subject: shutdown: use (void) NULL cgroup is handled below. --- src/core/shutdown.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 6296b4c94a..96679c920f 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) { goto error; } - cg_get_root_path(&cgroup); + (void) cg_get_root_path(&cgroup); use_watchdog = !!getenv("WATCHDOG_USEC"); -- cgit v1.2.3-54-g00ecf From 783e05d637540f36cb9b7e08d137ddd9d110c98f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:09:11 -0400 Subject: core/service: drop return value that is always ignored anyway --- src/core/service.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/core/service.c b/src/core/service.c index 5d58b0b752..8f59c411b8 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -832,7 +832,7 @@ static int service_load_pid_file(Service *s, bool may_warn) { return 0; } -static int service_search_main_pid(Service *s) { +static void service_search_main_pid(Service *s) { pid_t pid = 0; int r; @@ -841,30 +841,24 @@ static int service_search_main_pid(Service *s) { /* If we know it anyway, don't ever fallback to unreliable * heuristics */ if (s->main_pid_known) - return 0; + return; if (!s->guess_main_pid) - return 0; + return; assert(s->main_pid <= 0); - r = unit_search_main_pid(UNIT(s), &pid); - if (r < 0) - return r; + if (unit_search_main_pid(UNIT(s), &pid) < 0) + return; log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid); - r = service_set_main_pid(s, pid); - if (r < 0) - return r; + if (service_set_main_pid(s, pid) < 0) + return; r = unit_watch_pid(UNIT(s), pid); - if (r < 0) { + if (r < 0) /* FIXME: we need to do something here */ log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid); - return r; - } - - return 0; } static void service_set_state(Service *s, ServiceState state) { @@ -2729,7 +2723,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; } } else - (void) service_search_main_pid(s); + service_search_main_pid(s); service_enter_start_post(s); break; @@ -2751,7 +2745,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; } } else - (void) service_search_main_pid(s); + service_search_main_pid(s); service_enter_running(s, SERVICE_SUCCESS); break; @@ -2759,7 +2753,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { case SERVICE_RELOAD: if (f == SERVICE_SUCCESS) { service_load_pid_file(s, true); - (void) service_search_main_pid(s); + service_search_main_pid(s); } s->reload_result = f; -- cgit v1.2.3-54-g00ecf From 7236ce6e9e379948217c31f38b48de6448521162 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 21:09:17 -0400 Subject: core/service: only search for pid if loading from file failed CID #1237511. --- src/core/service.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/service.c b/src/core/service.c index 8f59c411b8..c5cbf0f152 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2751,10 +2751,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; case SERVICE_RELOAD: - if (f == SERVICE_SUCCESS) { - service_load_pid_file(s, true); - service_search_main_pid(s); - } + if (f == SERVICE_SUCCESS) + if (service_load_pid_file(s, true) < 0) + service_search_main_pid(s); s->reload_result = f; service_enter_running(s, SERVICE_SUCCESS); -- cgit v1.2.3-54-g00ecf From ad43ccb09675b0fa21bbeffc88adf79be1edde27 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sun, 10 Apr 2016 19:29:17 +0000 Subject: tests: ignore some mount errors in test-udev Fixes: $ sudo make distcheck ... FAIL: test/udev-test.pl ... $ vi systemd-229/_build/sub/test/udev-test.pl.log ... failed to mount empty /home/ubuntu/systemd/systemd-229/_inst/lib/udev/rules.d No such file or directory ... failed to mount empty /home/ubuntu/systemd/systemd-229/_inst/lib/udev/rules.d No such file or directory ... 414 errors occurred --- src/test/test-udev.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 8522e9925c..e5f0d00b94 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -39,12 +39,13 @@ static int fake_filesystems(void) { const char *src; const char *target; const char *error; + bool ignore_mount_error; } fakefss[] = { - { "test/tmpfs/sys", "/sys", "failed to mount test /sys" }, - { "test/tmpfs/dev", "/dev", "failed to mount test /dev" }, - { "test/run", "/run", "failed to mount test /run" }, - { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, - { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" }, + { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false }, + { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false }, + { "test/run", "/run", "failed to mount test /run", false }, + { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true }, + { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true }, }; unsigned int i; int err; @@ -66,8 +67,10 @@ static int fake_filesystems(void) { err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL); if (err < 0) { err = -errno; - fprintf(stderr, "%s %m\n", fakefss[i].error); - return err; + fprintf(stderr, "%s %m%s\n", fakefss[i].error, fakefss[i].ignore_mount_error ? ", ignoring" : ""); + if (!fakefss[i].ignore_mount_error) + return err; + err = 0; } } out: -- cgit v1.2.3-54-g00ecf From d2528deb44222f9bd57239e5bbaf5998e9a2469a Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sun, 10 Apr 2016 23:41:04 +0000 Subject: tests: don't silently skip `test-namespace` --- src/test/test-namespace.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 0b2f9e9173..ff9f35cecd 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -69,8 +69,10 @@ static void test_netns(void) { int r, n = 0; siginfo_t si; - if (geteuid() > 0) - return; + if (geteuid() > 0) { + log_info("Skipping test: not root"); + exit(EXIT_TEST_SKIP); + } assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0); @@ -124,6 +126,9 @@ int main(int argc, char *argv[]) { char boot_id[SD_ID128_STRING_MAX]; _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL; + log_parse_environment(); + log_open(); + assert_se(sd_id128_get_boot(&bid) >= 0); sd_id128_to_string(bid, boot_id); -- cgit v1.2.3-54-g00ecf From e01ff70a77e781734e1e73a2238af2e9bf7967a8 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Fri, 8 Apr 2016 13:22:54 +0200 Subject: nspawn: always setup machine id We check /etc/machine-id of the container and if it is already populated we use value from there, possibly ignoring value of --uuid option from the command line. When dealing with R/O image we setup transient machine id. Once we determined machine id of the container, we use this value for registration with systemd-machined and we also export it via container_uuid environment variable. As registration with systemd-machined is done by the main nspawn process we communicate container machine id established by setup_machine_id from outer child to the main process by unix domain socket. Similarly to PID of inner child. --- Makefile.am | 4 +- TODO | 2 - man/systemd-nspawn.xml | 4 +- src/nspawn/nspawn.c | 108 ++++++++++++++++++++++++++++++++++++------------- 4 files changed, 87 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index d670ae1984..eb99c34fb3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3028,7 +3028,9 @@ systemd_nspawn_SOURCES = \ src/core/mount-setup.c \ src/core/mount-setup.h \ src/core/loopback-setup.c \ - src/core/loopback-setup.h + src/core/loopback-setup.h \ + src/core/machine-id-setup.c \ + src/core/machine-id-setup.h nodist_systemd_nspawn_SOURCES = \ src/nspawn/nspawn-gperf.c diff --git a/TODO b/TODO index b2840ba4ab..9547b6e6e3 100644 --- a/TODO +++ b/TODO @@ -564,8 +564,6 @@ Features: - 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 - - refuses to boot containers without /etc/machine-id (OK?), and with empty - /etc/machine-id (not OK). - nspawn -x should support ephemeral instances of gpt images - emulate /dev/kmsg using CUSE and turn off the syslog syscall with seccomp. That should provide us with a useful log buffer that diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 7e87865ba8..3f3bd38900 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -355,7 +355,9 @@ Set the specified UUID for the container. The init system will initialize /etc/machine-id from this if this file is - not set yet. + not set yet. Note that this option takes effect only if + /etc/machine-id in the container is + unpopulated. diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index eb89916b7e..1197802779 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -64,6 +64,7 @@ #include "hostname-util.h" #include "log.h" #include "loopback-setup.h" +#include "machine-id-setup.h" #include "machine-image.h" #include "macro.h" #include "missing.h" @@ -1375,11 +1376,11 @@ static int setup_hostname(void) { } static int setup_journal(const char *directory) { - sd_id128_t machine_id, this_id; + sd_id128_t this_id; _cleanup_free_ char *b = NULL, *d = NULL; - const char *etc_machine_id, *p, *q; + const char *p, *q; bool try; - char *id; + char id[33]; int r; /* Don't link journals in ephemeral mode */ @@ -1391,28 +1392,11 @@ static int setup_journal(const char *directory) { try = arg_link_journal_try || arg_link_journal == LINK_AUTO; - etc_machine_id = prefix_roota(directory, "/etc/machine-id"); - - r = read_one_line_file(etc_machine_id, &b); - if (r == -ENOENT && try) - return 0; - else if (r < 0) - return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id); - - id = strstrip(b); - if (isempty(id) && try) - return 0; - - /* 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", etc_machine_id); - r = sd_id128_get_machine(&this_id); if (r < 0) return log_error_errno(r, "Failed to retrieve machine ID: %m"); - if (sd_id128_equal(machine_id, this_id)) { + if (sd_id128_equal(arg_uuid, this_id)) { log_full(try ? LOG_WARNING : LOG_ERR, "Host and machine ids are equal (%s): refusing to link journals", id); if (try) @@ -1432,6 +1416,8 @@ static int setup_journal(const char *directory) { if (r < 0) return log_error_errno(r, "Failed to create /var/log/journal: %m"); + (void) sd_id128_to_string(arg_uuid, id); + p = strjoina("/var/log/journal/", id); q = prefix_roota(directory, p); @@ -2201,6 +2187,38 @@ static int mount_device(const char *what, const char *where, const char *directo #endif } +static int setup_machine_id(const char *directory) { + int r; + const char *etc_machine_id, *t; + _cleanup_free_ char *s = NULL; + + etc_machine_id = prefix_roota(directory, "/etc/machine-id"); + + r = read_one_line_file(etc_machine_id, &s); + if (r < 0) + return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id); + + t = strstrip(s); + + if (!isempty(t)) { + r = sd_id128_from_string(t, &arg_uuid); + if (r < 0) + return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id); + } else { + if (sd_id128_is_null(arg_uuid)) { + r = sd_id128_randomize(&arg_uuid); + if (r < 0) + return log_error_errno(r, "Failed to generate random machine ID: %m"); + } + } + + r = machine_id_setup(directory, arg_uuid); + if (r < 0) + return log_error_errno(r, "Failed to setup machine ID: %m"); + + return 0; +} + static int mount_devices( const char *where, const char *root_device, bool root_device_rw, @@ -2458,6 +2476,7 @@ static int inner_child( FDSet *fds) { _cleanup_free_ char *home = NULL; + char as_uuid[37]; unsigned n_env = 1; const char *envp[] = { "PATH=" DEFAULT_PATH_SPLIT_USR, @@ -2575,12 +2594,10 @@ static int inner_child( (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]; + assert(!sd_id128_equal(arg_uuid, SD_ID128_NULL)); - if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0) - return log_oom(); - } + 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); @@ -2669,6 +2686,7 @@ static int outer_child( bool interactive, bool secondary, int pid_socket, + int uuid_socket, int kmsg_socket, int rtnl_socket, int uid_shift_socket, @@ -2682,6 +2700,7 @@ static int outer_child( assert(directory); assert(console); assert(pid_socket >= 0); + assert(uuid_socket >= 0); assert(kmsg_socket >= 0); cg_unified_flush(); @@ -2796,6 +2815,10 @@ static int outer_child( if (r < 0) return r; + r = setup_machine_id(directory); + if (r < 0) + return r; + r = setup_journal(directory); if (r < 0) return r; @@ -2821,6 +2844,7 @@ static int outer_child( return log_error_errno(errno, "Failed to fork inner child: %m"); if (pid == 0) { pid_socket = safe_close(pid_socket); + uuid_socket = safe_close(uuid_socket); uid_shift_socket = safe_close(uid_shift_socket); /* The inner child has all namespaces that are @@ -2842,7 +2866,16 @@ static int outer_child( return -EIO; } + l = send(uuid_socket, &arg_uuid, sizeof(arg_uuid), MSG_NOSIGNAL); + if (l < 0) + return log_error_errno(errno, "Failed to send machine ID: %m"); + if (l != sizeof(arg_uuid)) { + log_error("Short write while sending machine ID."); + return -EIO; + } + pid_socket = safe_close(pid_socket); + uuid_socket = safe_close(uuid_socket); kmsg_socket = safe_close(kmsg_socket); rtnl_socket = safe_close(rtnl_socket); @@ -3318,7 +3351,8 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_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 }, uuid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }; ContainerStatus container_status; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; static const struct sigaction sa = { @@ -3353,6 +3387,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uuid_socket_pair) < 0) { + r = log_error_errno(errno, "Failed to create id socket pair: %m"); + goto finish; + } + if (arg_userns) if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) { r = log_error_errno(errno, "Failed to create uid shift socket pair: %m"); @@ -3393,6 +3432,7 @@ int main(int argc, char *argv[]) { 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]); + uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]); uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); (void) reset_all_signal_handlers(); @@ -3407,6 +3447,7 @@ int main(int argc, char *argv[]) { interactive, secondary, pid_socket_pair[1], + uuid_socket_pair[1], kmsg_socket_pair[1], rtnl_socket_pair[1], uid_shift_socket_pair[1], @@ -3424,6 +3465,7 @@ int main(int argc, char *argv[]) { 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]); + uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]); uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); /* Wait for the outer child. */ @@ -3448,6 +3490,18 @@ int main(int argc, char *argv[]) { goto finish; } + /* We also retrieve container UUID in case it was generated by outer child */ + l = recv(uuid_socket_pair[0], &arg_uuid, sizeof(arg_uuid), 0); + if (l < 0) { + r = log_error_errno(errno, "Failed to read container machine ID: %m"); + goto finish; + } + if (l != sizeof(arg_uuid)) { + log_error("Short read while reading container machined ID."); + r = EIO; + goto finish; + } + log_debug("Init process invoked as PID " PID_FMT, pid); if (arg_userns) { -- cgit v1.2.3-54-g00ecf From 3de1521427dee61000c1c124a521182b301a50de Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 11 Apr 2016 21:03:29 +0200 Subject: Install: correctly report symlink creations All callers of create_symlink(), such as install_info_symlink_wants(), expect that to return > 0 if it actually did something, and then return that number. unit_file_enable() uses that to determine if any action was done (carries_install_info != 0) and if not, show a "The unit files have no [Install] section" warning. Return 1 instead of 0 in the two code paths of create_symlink() when the link was created or replaced with a new value. This fixes getting a bogus "No [Install] section" warning when enabling a unit with full path, like "systemctl enable /some/path/myunit.service". --- src/shared/install.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index ef8f485cae..0f08137f19 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -294,7 +294,7 @@ static int create_symlink( if (symlink(old_path, new_path) >= 0) { unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); - return 0; + return 1; } if (errno != EEXIST) @@ -317,7 +317,7 @@ static int create_symlink( 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; + return 1; } static int mark_symlink_for_removal( -- cgit v1.2.3-54-g00ecf From dbab702a2a2ba942d75f9682e2ab11f9b55df683 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Mon, 11 Apr 2016 22:31:57 +0300 Subject: tests: port udev-test to log_*_errno (#3015) SYSTEMD_LOG_LEVEL=debug test/udev-test.pl is working now Also, fixes CID 1354602 --- src/test/test-udev.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/test/test-udev.c b/src/test/test-udev.c index e5f0d00b94..e965b4494a 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -27,6 +27,7 @@ #include #include "fs-util.h" +#include "log.h" #include "missing.h" #include "selinux-util.h" #include "signal-util.h" @@ -48,33 +49,22 @@ static int fake_filesystems(void) { { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true }, }; unsigned int i; - int err; - err = unshare(CLONE_NEWNS); - if (err < 0) { - err = -errno; - fprintf(stderr, "failed to call unshare(): %m\n"); - goto out; - } + if (unshare(CLONE_NEWNS) < 0) + return log_error_errno(errno, "failed to call unshare(): %m"); - if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) { - err = -errno; - fprintf(stderr, "failed to mount / as private: %m\n"); - goto out; - } + if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) + return log_error_errno(errno, "failed to mount / as private: %m"); for (i = 0; i < ELEMENTSOF(fakefss); i++) { - err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL); - if (err < 0) { - err = -errno; - fprintf(stderr, "%s %m%s\n", fakefss[i].error, fakefss[i].ignore_mount_error ? ", ignoring" : ""); + if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) { + log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error); if (!fakefss[i].ignore_mount_error) - return err; - err = 0; + return -errno; } } -out: - return err; + + return 0; } int main(int argc, char *argv[]) { @@ -87,6 +77,9 @@ int main(int argc, char *argv[]) { const char *action; int err; + log_parse_environment(); + log_open(); + err = fake_filesystems(); if (err < 0) return EXIT_FAILURE; -- cgit v1.2.3-54-g00ecf From 6d10d308c6cd16528ef58fa4f5822aef936862d3 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 12 Apr 2016 05:10:57 -0400 Subject: Do not report masked units as changed (#2921) * core/unit: extract checking of stat paths into helper function The same code was repeated three times. * core: treat masked files as "unchanged" systemctl prints the "unit file changed on disk" warning for a masked unit. I think it's better to print nothing in that case. When a masked unit is loaded, set mtime as 0. When checking if a unit with mtime of 0 needs reload, check that the mask is still in place. * test-dnssec: fix build without gcrypt Also reorder the test functions to follow the way they are called from main(). --- src/core/load-fragment.c | 8 +- src/core/unit.c | 62 +++++------ src/resolve/test-dnssec.c | 274 +++++++++++++++++++++++----------------------- 3 files changed, 173 insertions(+), 171 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d078924c5b..f1a874cfdf 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3620,10 +3620,12 @@ static int load_from_path(Unit *u, const char *path) { if (fstat(fileno(f), &st) < 0) return -errno; - if (null_or_empty(&st)) + if (null_or_empty(&st)) { u->load_state = UNIT_MASKED; - else { + u->fragment_mtime = 0; + } else { u->load_state = UNIT_LOADED; + u->fragment_mtime = timespec_load(&st.st_mtim); /* Now, parse the file contents */ r = config_parse(u->id, filename, f, @@ -3638,8 +3640,6 @@ static int load_from_path(Unit *u, const char *path) { u->fragment_path = filename; filename = NULL; - u->fragment_mtime = timespec_load(&st.st_mtim); - if (u->source_path) { if (stat(u->source_path, &st) >= 0) u->source_mtime = timespec_load(&st.st_mtim); diff --git a/src/core/unit.c b/src/core/unit.c index af38beb0c3..70175557f7 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2924,34 +2924,36 @@ int unit_coldplug(Unit *u) { return 0; } +static bool fragment_mtime_changed(const char *path, usec_t mtime) { + struct stat st; + + if (!path) + return false; + + if (stat(path, &st) < 0) + /* What, cannot access this anymore? */ + return true; + + if (mtime > 0) + /* For non-empty files check the mtime */ + return timespec_load(&st.st_mtim) != mtime; + else if (!null_or_empty(&st)) + /* For masked files check if they are still so */ + return true; + + return false; +} + bool unit_need_daemon_reload(Unit *u) { _cleanup_strv_free_ char **t = NULL; char **path; - struct stat st; unsigned loaded_cnt, current_cnt; assert(u); - if (u->fragment_path) { - zero(st); - if (stat(u->fragment_path, &st) < 0) - /* What, cannot access this anymore? */ - return true; - - if (u->fragment_mtime > 0 && - timespec_load(&st.st_mtim) != u->fragment_mtime) - return true; - } - - if (u->source_path) { - zero(st); - if (stat(u->source_path, &st) < 0) - return true; - - if (u->source_mtime > 0 && - timespec_load(&st.st_mtim) != u->source_mtime) - return true; - } + if (fragment_mtime_changed(u->fragment_path, u->fragment_mtime) || + fragment_mtime_changed(u->source_path, u->source_mtime)) + return true; (void) unit_find_dropin_paths(u, &t); loaded_cnt = strv_length(t); @@ -2962,21 +2964,15 @@ bool unit_need_daemon_reload(Unit *u) { return false; if (strv_overlap(u->dropin_paths, t)) { - STRV_FOREACH(path, u->dropin_paths) { - zero(st); - if (stat(*path, &st) < 0) - return true; - - if (u->dropin_mtime > 0 && - timespec_load(&st.st_mtim) > u->dropin_mtime) + STRV_FOREACH(path, u->dropin_paths) + if (fragment_mtime_changed(*path, u->dropin_mtime)) return true; - } return false; - } else - return true; - } else - return true; + } + } + + return true; } void unit_reset_failed(Unit *u) { diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index c9b5ffa62b..155be9946f 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -27,77 +27,89 @@ #include "string-util.h" #include "hexdecoct.h" -static void test_dnssec_verify_rrset2(void) { +static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { + char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; - static const uint8_t signature_blob[] = { - 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, - 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, - 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca, - 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2, - 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda, - 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27, - 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50, - 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22, - }; + assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); + if (r < 0) + return; + assert_se(streq(canonicalized, canonical)); +} + +static void test_dnssec_canonicalize(void) { + test_dnssec_canonicalize_one("", ".", 1); + test_dnssec_canonicalize_one(".", ".", 1); + test_dnssec_canonicalize_one("foo", "foo.", 4); + test_dnssec_canonicalize_one("foo.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); + test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); +} + +#ifdef HAVE_GCRYPT + +static void test_dnssec_verify_dns_key(void) { + + static const uint8_t ds1_fprint[] = { + 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, + 0x80, 0x67, 0x14, 0x01, + }; + static const uint8_t ds2_fprint[] = { + 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, + 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, + }; static const uint8_t dnskey_blob[] = { - 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea, - 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3, - 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07, - 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5, - 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7, - 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56, - 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e, - 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49, - 0x74, 0x62, 0xfe, 0xd7, + 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, + 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, + 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, + 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, + 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, + 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, + 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, + 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, + 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, + 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, + 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, + 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, + 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, + 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, + 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, + 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, + 0xe7, 0xea, 0x77, 0x03, }; - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - DnssecResult result; - - nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); - assert_se(nsec); + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; - nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov"); - assert_se(nsec->nsec.next_domain_name); + /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ + ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); + assert_se(ds1); - nsec->nsec.types = bitmap_new(); - assert_se(nsec->nsec.types); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0); - assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0); + ds1->ds.key_tag = 47857; + ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; + ds1->ds.digest_size = sizeof(ds1_fprint); + ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); + assert_se(ds1->ds.digest); - log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec))); + log_info("DS1: %s", strna(dns_resource_record_to_string(ds1))); - rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); - assert_se(rrsig); + ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); + assert_se(ds2); - rrsig->rrsig.type_covered = DNS_TYPE_NSEC; - rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; - rrsig->rrsig.labels = 2; - rrsig->rrsig.original_ttl = 300; - rrsig->rrsig.expiration = 0x5689002f; - rrsig->rrsig.inception = 0x56617230; - rrsig->rrsig.key_tag = 30390; - rrsig->rrsig.signer = strdup("Nasa.Gov."); - assert_se(rrsig->rrsig.signer); - rrsig->rrsig.signature_size = sizeof(signature_blob); - rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); - assert_se(rrsig->rrsig.signature); + ds2->ds.key_tag = 47857; + ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; + ds2->ds.digest_size = sizeof(ds2_fprint); + ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); + assert_se(ds2->ds.digest); - log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + log_info("DS2: %s", strna(dns_resource_record_to_string(ds2))); - dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); assert_se(dnskey); - dnskey->dnskey.flags = 256; + dnskey->dnskey.flags = 257; dnskey->dnskey.protocol = 3; dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; dnskey->dnskey.key_size = sizeof(dnskey_blob); @@ -107,16 +119,8 @@ static void test_dnssec_verify_rrset2(void) { log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); - assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0); - assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); - - answer = dns_answer_new(1); - assert_se(answer); - assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); - - /* Validate the RR as it if was 2015-12-11 today */ - assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); - assert_se(result == DNSSEC_VALIDATED); + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0); + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); } static void test_dnssec_verify_rrset(void) { @@ -198,67 +202,78 @@ static void test_dnssec_verify_rrset(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_verify_dns_key(void) { +static void test_dnssec_verify_rrset2(void) { - static const uint8_t ds1_fprint[] = { - 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, - 0x80, 0x67, 0x14, 0x01, - }; - static const uint8_t ds2_fprint[] = { - 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, - 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, + static const uint8_t signature_blob[] = { + 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, + 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, + 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca, + 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2, + 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda, + 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27, + 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50, + 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22, }; + static const uint8_t dnskey_blob[] = { - 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, - 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, - 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, - 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, - 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, - 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, - 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, - 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, - 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, - 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, - 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, - 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, - 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, - 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, - 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, - 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, - 0xe7, 0xea, 0x77, 0x03, + 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea, + 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3, + 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07, + 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5, + 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7, + 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56, + 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e, + 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49, + 0x74, 0x62, 0xfe, 0xd7, }; - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnssecResult result; + int r; - /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ - ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); - assert_se(ds1); + nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); + assert_se(nsec); - ds1->ds.key_tag = 47857; - ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; - ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; - ds1->ds.digest_size = sizeof(ds1_fprint); - ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); - assert_se(ds1->ds.digest); + nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov"); + assert_se(nsec->nsec.next_domain_name); - log_info("DS1: %s", strna(dns_resource_record_to_string(ds1))); + nsec->nsec.types = bitmap_new(); + assert_se(nsec->nsec.types); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0); + assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0); - ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); - assert_se(ds2); + log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec))); - ds2->ds.key_tag = 47857; - ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; - ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; - ds2->ds.digest_size = sizeof(ds2_fprint); - ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); - assert_se(ds2->ds.digest); + rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); + assert_se(rrsig); - log_info("DS2: %s", strna(dns_resource_record_to_string(ds2))); + rrsig->rrsig.type_covered = DNS_TYPE_NSEC; + rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; + rrsig->rrsig.labels = 2; + rrsig->rrsig.original_ttl = 300; + rrsig->rrsig.expiration = 0x5689002f; + rrsig->rrsig.inception = 0x56617230; + rrsig->rrsig.key_tag = 30390; + rrsig->rrsig.signer = strdup("Nasa.Gov."); + assert_se(rrsig->rrsig.signer); + rrsig->rrsig.signature_size = sizeof(signature_blob); + rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); + assert_se(rrsig->rrsig.signature); - dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); + log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); assert_se(dnskey); - dnskey->dnskey.flags = 257; + dnskey->dnskey.flags = 256; dnskey->dnskey.protocol = 3; dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; dnskey->dnskey.key_size = sizeof(dnskey_blob); @@ -268,28 +283,16 @@ static void test_dnssec_verify_dns_key(void) { log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); - assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0); - assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); -} - -static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { - char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; - - assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); - if (r < 0) - return; + assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0); + assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); - assert_se(streq(canonicalized, canonical)); -} + answer = dns_answer_new(1); + assert_se(answer); + assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); -static void test_dnssec_canonicalize(void) { - test_dnssec_canonicalize_one("", ".", 1); - test_dnssec_canonicalize_one(".", ".", 1); - test_dnssec_canonicalize_one("foo", "foo.", 4); - test_dnssec_canonicalize_one("foo.", "foo.", 4); - test_dnssec_canonicalize_one("FOO.", "foo.", 4); - test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); - test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); + /* Validate the RR as it if was 2015-12-11 today */ + assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); + assert_se(result == DNSSEC_VALIDATED); } static void test_dnssec_nsec3_hash(void) { @@ -324,9 +327,12 @@ static void test_dnssec_nsec3_hash(void) { assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0); } +#endif + int main(int argc, char*argv[]) { test_dnssec_canonicalize(); + #ifdef HAVE_GCRYPT test_dnssec_verify_dns_key(); test_dnssec_verify_rrset(); -- cgit v1.2.3-54-g00ecf From 03ce175f4ce24269e5e7328b7c1909c5d6156e84 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Feb 2016 20:29:06 +0100 Subject: import: drop unused definition --- src/import/pull-job.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'src') diff --git a/src/import/pull-job.h b/src/import/pull-job.h index 998857035a..3a152a50e3 100644 --- a/src/import/pull-job.h +++ b/src/import/pull-job.h @@ -44,15 +44,6 @@ typedef enum PullJobState { #define PULL_JOB_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; -- cgit v1.2.3-54-g00ecf From 4143c6c305fb7075aa071bcc8e7cf0f92f41e146 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Feb 2016 20:37:37 +0100 Subject: sysv-generator: don't use LookupPath logic for determining SysV paths The sysv-generator is the only user of the SysV paths these days, let's make it figure out the right paths on its own. (In a subsequent commit we can then drop the same logic from LookupPath). --- src/sysv-generator/sysv-generator.c | 47 ++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 59e1a3e921..ca28c724dd 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -729,14 +729,50 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { return 0; } +static int acquire_search_path(const char *def, const char *envvar, char ***ret) { + _cleanup_strv_free_ char **l = NULL; + const char *e; + int r; + + assert(def); + assert(envvar); + + e = getenv(envvar); + if (e) { + r = path_split_and_make_absolute(e, &l); + if (r < 0) + return log_error_errno(r, "Failed to make $%s search path absolute: %m", envvar); + } + + if (strv_isempty(l)) { + strv_free(l); + + l = strv_new(def, NULL); + if (!l) + return log_oom(); + } + + if (!path_strv_resolve_uniq(l, NULL)) + return log_oom(); + + *ret = l; + l = NULL; + + return 0; +} + static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + _cleanup_strv_free_ char **sysvinit_path = NULL; char **path; int r; assert(lp); - assert(all_services); - STRV_FOREACH(path, lp->sysvinit_path) { + r = acquire_search_path(SYSTEM_SYSVINIT_PATH, "SYSTEMD_SYSVINIT_PATH", &sysvinit_path); + if (r < 0) + return r; + + STRV_FOREACH(path, sysvinit_path) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -806,6 +842,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) { Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {}; _cleanup_set_free_ Set *shutdown_services = NULL; + _cleanup_strv_free_ char **sysvrcnd_path = NULL; SysvStub *service; unsigned i; Iterator j; @@ -814,7 +851,11 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic assert(lp); - STRV_FOREACH(p, lp->sysvrcnd_path) { + r = acquire_search_path(SYSTEM_SYSVRCND_PATH, "SYSTEMD_SYSVRCND_PATH", &sysvrcnd_path); + if (r < 0) + return r; + + STRV_FOREACH(p, sysvrcnd_path) { for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { _cleanup_closedir_ DIR *d = NULL; -- cgit v1.2.3-54-g00ecf From 1dfa3076cfbb00c48a26892b72148265ea3b69f3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Feb 2016 20:38:53 +0100 Subject: core: drop SysV paths from path-lookup logic We don't need it anymore, give that sysv-generator can determine the path on its own now. --- src/shared/path-lookup.c | 76 ------------------------------------------------ src/shared/path-lookup.h | 4 --- 2 files changed, 80 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 5410620725..ac22a27ccb 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -338,77 +338,6 @@ int lookup_paths_init( p->unit_path = strv_free(p->unit_path); } - if (running_as == MANAGER_SYSTEM) { -#ifdef HAVE_SYSV_COMPAT - /* /etc/init.d/ compatibility does not matter to users */ - - e = getenv("SYSTEMD_SYSVINIT_PATH"); - if (e) { - r = path_split_and_make_absolute(e, &p->sysvinit_path); - if (r < 0) - return r; - } else - p->sysvinit_path = NULL; - - if (strv_isempty(p->sysvinit_path)) { - strv_free(p->sysvinit_path); - - p->sysvinit_path = strv_new( - SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ - NULL); - if (!p->sysvinit_path) - return -ENOMEM; - } - - e = getenv("SYSTEMD_SYSVRCND_PATH"); - if (e) { - r = path_split_and_make_absolute(e, &p->sysvrcnd_path); - if (r < 0) - return r; - } else - p->sysvrcnd_path = NULL; - - if (strv_isempty(p->sysvrcnd_path)) { - strv_free(p->sysvrcnd_path); - - p->sysvrcnd_path = strv_new( - SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ - NULL); - if (!p->sysvrcnd_path) - return -ENOMEM; - } - - if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir)) - return -ENOMEM; - - if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir)) - return -ENOMEM; - - if (!strv_isempty(p->sysvinit_path)) { - _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t"); - if (!t) - return -ENOMEM; - log_debug("Looking for SysV init scripts in:\n\t%s", t); - } else { - log_debug("Ignoring SysV init scripts."); - p->sysvinit_path = strv_free(p->sysvinit_path); - } - - if (!strv_isempty(p->sysvrcnd_path)) { - _cleanup_free_ char *t = - strv_join(p->sysvrcnd_path, "\n\t"); - if (!t) - return -ENOMEM; - - log_debug("Looking for SysV rcN.d links in:\n\t%s", t); - } else { - log_debug("Ignoring SysV rcN.d links."); - p->sysvrcnd_path = strv_free(p->sysvrcnd_path); - } -#else - log_debug("SysV init scripts and rcN.d links support disabled"); -#endif - } return 0; } @@ -417,11 +346,6 @@ void lookup_paths_free(LookupPaths *p) { assert(p); p->unit_path = strv_free(p->unit_path); - -#ifdef HAVE_SYSV_COMPAT - p->sysvinit_path = strv_free(p->sysvinit_path); - p->sysvrcnd_path = strv_free(p->sysvrcnd_path); -#endif } int lookup_paths_init_from_scope(LookupPaths *paths, diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 26c83d6111..c53d293072 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -24,10 +24,6 @@ typedef struct LookupPaths { char **unit_path; -#ifdef HAVE_SYSV_COMPAT - char **sysvinit_path; - char **sysvrcnd_path; -#endif } LookupPaths; typedef enum ManagerRunningAs { -- cgit v1.2.3-54-g00ecf From a3c4eb07106b29f7366113764cb1c8c4d6dd5646 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 15:31:33 +0100 Subject: core: rework generator dir logic, move the dirs into LookupPaths structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A long time ago – when generators where first introduced – the directories for them were randomly created via mkdtemp(). This was changed later so that they use fixed name directories now. Let's make use of this, and add the genrator dirs to the LookupPaths structure and into the unit file search path maintained in it. This has the benefit that the generator dirs are now normal part of the search path for all tools, and thus are shown in "systemctl list-unit-files" too. --- src/core/dbus-manager.c | 2 +- src/core/load-dropin.c | 2 +- src/core/load-dropin.h | 2 +- src/core/load-fragment.c | 2 +- src/core/manager.c | 142 +++++---------------------- src/core/manager.h | 4 - src/shared/install.c | 12 +-- src/shared/install.h | 2 +- src/shared/path-lookup.c | 191 ++++++++++++++++++++++++++++-------- src/shared/path-lookup.h | 33 +++---- src/systemctl/systemctl.c | 8 +- src/sysv-generator/sysv-generator.c | 2 +- src/test/test-path-lookup.c | 17 ++-- 13 files changed, 211 insertions(+), 208 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 00372b92b4..739bd14b9e 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1924,7 +1924,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0), SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0), diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index 22b71b6f5e..1c65055a3f 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -55,7 +55,7 @@ int unit_load_dropin(Unit *u) { SET_FOREACH(t, u->names, i) { char **p; - STRV_FOREACH(p, u->manager->lookup_paths.unit_path) { + STRV_FOREACH(p, u->manager->lookup_paths.search_path) { unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".wants", UNIT_WANTS, add_dependency_consumer, u, NULL); unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".requires", UNIT_REQUIRES, diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h index d8a4aefbb3..942d26724e 100644 --- a/src/core/load-dropin.h +++ b/src/core/load-dropin.h @@ -25,7 +25,7 @@ /* Read service data supplementary drop-in directories */ static inline int unit_find_dropin_paths(Unit *u, char ***paths) { - return unit_file_find_dropin_paths(u->manager->lookup_paths.unit_path, + return unit_file_find_dropin_paths(u->manager->lookup_paths.search_path, u->manager->unit_path_cache, u->names, paths); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index f1a874cfdf..3a77ceb551 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3574,7 +3574,7 @@ static int load_from_path(Unit *u, const char *path) { } else { char **p; - STRV_FOREACH(p, u->manager->lookup_paths.unit_path) { + STRV_FOREACH(p, u->manager->lookup_paths.search_path) { /* Instead of opening the path right away, we manually * follow all symlinks and add their name to our unit diff --git a/src/core/manager.c b/src/core/manager.c index e739795e70..79dc77d50e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1053,7 +1053,7 @@ static void manager_build_unit_path_cache(Manager *m) { /* This simply builds a list of files we know exist, so that * we don't always have to go to disk */ - STRV_FOREACH(i, m->lookup_paths.unit_path) { + STRV_FOREACH(i, m->lookup_paths.search_path) { struct dirent *de; d = opendir(*i); @@ -1116,18 +1116,13 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { assert(m); - dual_timestamp_get(&m->generators_start_timestamp); - r = manager_run_generators(m); - dual_timestamp_get(&m->generators_finish_timestamp); + r = lookup_paths_init(&m->lookup_paths, m->running_as, true, NULL); if (r < 0) return r; - r = lookup_paths_init( - &m->lookup_paths, m->running_as, true, - NULL, - m->generator_unit_path, - m->generator_unit_path_early, - m->generator_unit_path_late); + dual_timestamp_get(&m->generators_start_timestamp); + r = manager_run_generators(m); + dual_timestamp_get(&m->generators_finish_timestamp); if (r < 0) return r; @@ -2542,17 +2537,12 @@ int manager_reload(Manager *m) { manager_undo_generators(m); lookup_paths_free(&m->lookup_paths); - /* Find new unit paths */ - q = manager_run_generators(m); + q = lookup_paths_init(&m->lookup_paths, m->running_as, true, NULL); if (q < 0 && r >= 0) r = q; - q = lookup_paths_init( - &m->lookup_paths, m->running_as, true, - NULL, - m->generator_unit_path, - m->generator_unit_path_early, - m->generator_unit_path_late); + /* Find new unit paths */ + q = manager_run_generators(m); if (q < 0 && r >= 0) r = q; @@ -2732,77 +2722,6 @@ void manager_check_finished(Manager *m) { manager_invalidate_startup_units(m); } -static int create_generator_dir(Manager *m, char **generator, const char *name) { - char *p; - int r; - - assert(m); - assert(generator); - assert(name); - - if (*generator) - return 0; - - if (m->running_as == MANAGER_SYSTEM && getpid() == 1) { - /* systemd --system, not running --test */ - - p = strappend("/run/systemd/", name); - if (!p) - return log_oom(); - - r = mkdir_p_label(p, 0755); - if (r < 0) { - log_error_errno(r, "Failed to create generator directory %s: %m", p); - free(p); - return r; - } - } else if (m->running_as == MANAGER_USER) { - const char *s = NULL; - - s = getenv("XDG_RUNTIME_DIR"); - if (!s) - return -EINVAL; - p = strjoin(s, "/systemd/", name, NULL); - if (!p) - return log_oom(); - - r = mkdir_p_label(p, 0755); - if (r < 0) { - log_error_errno(r, "Failed to create generator directory %s: %m", p); - free(p); - return r; - } - } else { - /* systemd --system --test */ - - p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL); - if (!p) - return log_oom(); - - if (!mkdtemp(p)) { - log_error_errno(errno, "Failed to create generator directory %s: %m", p); - free(p); - return -errno; - } - } - - *generator = p; - return 0; -} - -static void trim_generator_dir(Manager *m, char **generator) { - assert(m); - assert(generator); - - if (!*generator) - return; - - if (rmdir(*generator) >= 0) - *generator = mfree(*generator); - - return; -} - static int manager_run_generators(Manager *m) { _cleanup_strv_free_ char **paths = NULL; const char *argv[5]; @@ -2821,62 +2740,53 @@ static int manager_run_generators(Manager *m) { /* Optimize by skipping the whole process by not creating output directories * if no generators are found. */ STRV_FOREACH(path, paths) { - r = access(*path, F_OK); - if (r == 0) + if (access(*path, F_OK) >= 0) goto found; if (errno != ENOENT) log_warning_errno(errno, "Failed to open generator directory %s: %m", *path); } + return 0; found: - r = create_generator_dir(m, &m->generator_unit_path, "generator"); + r = mkdir_p_label(m->lookup_paths.generator, 0755); if (r < 0) goto finish; - r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early"); + r = mkdir_p_label(m->lookup_paths.generator_early, 0755); if (r < 0) goto finish; - r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late"); + r = mkdir_p_label(m->lookup_paths.generator_late, 0755); if (r < 0) goto finish; argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */ - argv[1] = m->generator_unit_path; - argv[2] = m->generator_unit_path_early; - argv[3] = m->generator_unit_path_late; + argv[1] = m->lookup_paths.generator; + argv[2] = m->lookup_paths.generator_early; + argv[3] = m->lookup_paths.generator_late; argv[4] = NULL; RUN_WITH_UMASK(0022) execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv); finish: - trim_generator_dir(m, &m->generator_unit_path); - trim_generator_dir(m, &m->generator_unit_path_early); - trim_generator_dir(m, &m->generator_unit_path_late); + /* Trim empty dirs */ + (void) rmdir(m->lookup_paths.generator); + (void) rmdir(m->lookup_paths.generator_early); + (void) rmdir(m->lookup_paths.generator_late); return r; } -static void remove_generator_dir(Manager *m, char **generator) { - assert(m); - assert(generator); - - if (!*generator) - return; - - strv_remove(m->lookup_paths.unit_path, *generator); - (void) rm_rf(*generator, REMOVE_ROOT); - - *generator = mfree(*generator); -} - static void manager_undo_generators(Manager *m) { assert(m); - remove_generator_dir(m, &m->generator_unit_path); - remove_generator_dir(m, &m->generator_unit_path_early); - remove_generator_dir(m, &m->generator_unit_path_late); + if (m->lookup_paths.generator) + (void) rm_rf(m->lookup_paths.generator, REMOVE_ROOT); + if (m->lookup_paths.generator_early) + (void) rm_rf(m->lookup_paths.generator_early, REMOVE_ROOT); + if (m->lookup_paths.generator_late) + (void) rm_rf(m->lookup_paths.generator_late, REMOVE_ROOT); } int manager_environment_add(Manager *m, char **minus, char **plus) { diff --git a/src/core/manager.h b/src/core/manager.h index 9803f73129..5471bd7a0d 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -162,10 +162,6 @@ struct Manager { dual_timestamp units_load_start_timestamp; dual_timestamp units_load_finish_timestamp; - char *generator_unit_path; - char *generator_unit_path_early; - char *generator_unit_path_late; - struct udev* udev; /* Data specific to the device subsystem */ diff --git a/src/shared/install.c b/src/shared/install.c index 0f08137f19..e232d76dd7 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1060,7 +1060,7 @@ static int unit_file_search( assert(info->name); - STRV_FOREACH(p, paths->unit_path) { + STRV_FOREACH(p, paths->search_path) { _cleanup_free_ char *path = NULL; path = strjoin(*p, "/", info->name, NULL); @@ -1090,7 +1090,7 @@ static int unit_file_search( if (r < 0) return r; - STRV_FOREACH(p, paths->unit_path) { + STRV_FOREACH(p, paths->search_path) { _cleanup_free_ char *path = NULL; path = strjoin(*p, "/", template, NULL); @@ -1348,7 +1348,7 @@ static int install_info_symlink_link( assert(config_path); assert(i->path); - r = in_search_path(i->path, paths->unit_path); + r = in_search_path(i->path, paths->search_path); if (r != 0) return r; @@ -1672,7 +1672,7 @@ int unit_file_link( if (!S_ISREG(st.st_mode)) return -ENOTTY; - q = in_search_path(*i, paths.unit_path); + q = in_search_path(*i, paths.search_path); if (q < 0) return q; if (q > 0) @@ -2313,7 +2313,7 @@ int unit_file_preset_all( if (r < 0) return r; - STRV_FOREACH(i, paths.unit_path) { + STRV_FOREACH(i, paths.search_path) { _cleanup_closedir_ DIR *d = NULL; _cleanup_free_ char *units_dir; struct dirent *de; @@ -2389,7 +2389,7 @@ int unit_file_get_list( if (r < 0) return r; - STRV_FOREACH(i, paths.unit_path) { + STRV_FOREACH(i, paths.search_path) { _cleanup_closedir_ DIR *d = NULL; _cleanup_free_ char *units_dir; struct dirent *de; diff --git a/src/shared/install.h b/src/shared/install.h index c1a43e23e7..82b6d425eb 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -135,7 +135,7 @@ 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, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret); +int unit_file_lookup_state(UnitFileScope scope, const char *root_dir, const LookupPaths *paths, const char *name, UnitFileState *ret); int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index ac22a27ccb..ec3f5b53f4 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -235,43 +235,119 @@ char **generator_paths(ManagerRunningAs running_as) { NULL); } +static int acquire_generator_dirs( + ManagerRunningAs running_as, + char **generator, + char **generator_early, + char **generator_late) { + + _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL; + const char *prefix; + + assert(generator); + assert(generator_early); + assert(generator_late); + + if (running_as == MANAGER_SYSTEM) + prefix = "/run/systemd/"; + else { + const char *e; + + assert(running_as == MANAGER_USER); + + e = getenv("XDG_RUNTIME_DIR"); + if (!e) + return -EINVAL; + + prefix = strjoina(e, "/systemd/", NULL); + } + + x = strappend(prefix, "generator"); + if (!x) + return -ENOMEM; + + y = strappend(prefix, "generator.early"); + if (!y) + return -ENOMEM; + + z = strappend(prefix, "generator.late"); + if (!z) + return -ENOMEM; + + *generator = x; + *generator_early = y; + *generator_late = z; + + x = y = z = NULL; + return 0; +} + +static int patch_root_prefix(char **p, const char *root_dir) { + char *c; + + assert(p); + + if (!*p) + return 0; + + if (isempty(root_dir) || path_equal(root_dir, "/")) + return 0; + + c = prefix_root(root_dir, *p); + if (!c) + return -ENOMEM; + + free(*p); + *p = c; + + return 0; +} + int lookup_paths_init( LookupPaths *p, ManagerRunningAs running_as, bool personal, - const char *root_dir, - const char *generator, - const char *generator_early, - const char *generator_late) { + const char *root_dir) { - const char *e; + _cleanup_free_ char *generator = NULL, *generator_early = NULL, *generator_late = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ + char **l = NULL; + const char *e; int r; assert(p); + assert(running_as >= 0); + assert(running_as < _MANAGER_RUNNING_AS_MAX); + + r = acquire_generator_dirs(running_as, &generator, &generator_early, &generator_late); + if (r < 0) + return r; /* First priority is whatever has been passed to us via env * vars */ e = getenv("SYSTEMD_UNIT_PATH"); if (e) { - if (endswith(e, ":")) { - e = strndupa(e, strlen(e) - 1); + const char *k; + + k = endswith(e, ":"); + if (k) { + e = strndupa(e, k - e); append = true; } /* FIXME: empty components in other places should be * rejected. */ - r = path_split_and_make_absolute(e, &p->unit_path); + r = path_split_and_make_absolute(e, &l); if (r < 0) return r; } else - p->unit_path = NULL; + l = NULL; - if (!p->unit_path || append) { + if (!l || append) { /* Let's figure something out. */ - _cleanup_strv_free_ char **unit_path; + _cleanup_strv_free_ char **add = NULL; /* For the user units we include share/ in the search * path in order to comply with the XDG basedir spec. @@ -281,85 +357,114 @@ int lookup_paths_init( if (running_as == MANAGER_USER) { if (personal) - unit_path = user_dirs(generator, generator_early, generator_late); + add = user_dirs(generator, generator_early, generator_late); else - unit_path = strv_new( + add = strv_new( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and * the arrays in user_dirs() above! */ - STRV_IFNOTNULL(generator_early), + generator_early, USER_CONFIG_UNIT_PATH, "/etc/systemd/user", "/run/systemd/user", - STRV_IFNOTNULL(generator), + generator, "/usr/local/lib/systemd/user", "/usr/local/share/systemd/user", USER_DATA_UNIT_PATH, "/usr/lib/systemd/user", "/usr/share/systemd/user", - STRV_IFNOTNULL(generator_late), + generator_late, NULL); } else - unit_path = strv_new( + add = strv_new( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ - STRV_IFNOTNULL(generator_early), + generator_early, SYSTEM_CONFIG_UNIT_PATH, "/etc/systemd/system", "/run/systemd/system", - STRV_IFNOTNULL(generator), + generator, "/usr/local/lib/systemd/system", SYSTEM_DATA_UNIT_PATH, "/usr/lib/systemd/system", #ifdef HAVE_SPLIT_USR "/lib/systemd/system", #endif - STRV_IFNOTNULL(generator_late), + generator_late, NULL); - if (!unit_path) + if (!add) return -ENOMEM; - r = strv_extend_strv(&p->unit_path, unit_path, false); - if (r < 0) - return r; + if (l) { + r = strv_extend_strv(&l, add, false); + if (r < 0) + return r; + } else { + l = add; + add = NULL; + } } - if (!path_strv_resolve_uniq(p->unit_path, root_dir)) + r = patch_root_prefix(&generator, root_dir); + if (r < 0) + return r; + r = patch_root_prefix(&generator_early, root_dir); + if (r < 0) + return r; + r = patch_root_prefix(&generator_late, root_dir); + if (r < 0) + return r; + + if (!path_strv_resolve_uniq(l, root_dir)) return -ENOMEM; - if (!strv_isempty(p->unit_path)) { - _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t"); + if (strv_isempty(l)) { + log_debug("Ignoring unit files."); + l = strv_free(l); + } else { + _cleanup_free_ char *t; + + t = strv_join(l, "\n\t"); if (!t) return -ENOMEM; + log_debug("Looking for unit files in (higher priority first):\n\t%s", t); - } else { - log_debug("Ignoring unit files."); - p->unit_path = strv_free(p->unit_path); } + p->search_path = l; + l = NULL; + + p->generator = generator; + p->generator_early = generator_early; + p->generator_late = generator_late; + generator = generator_early = generator_late = NULL; return 0; } void lookup_paths_free(LookupPaths *p) { - assert(p); + if (!p) + return; - p->unit_path = strv_free(p->unit_path); + p->search_path = strv_free(p->search_path); + p->generator = mfree(p->generator); + p->generator_early = mfree(p->generator_early); + p->generator_late = mfree(p->generator_late); } -int lookup_paths_init_from_scope(LookupPaths *paths, - UnitFileScope scope, - const char *root_dir) { - assert(paths); +int lookup_paths_init_from_scope( + LookupPaths *p, + UnitFileScope scope, + const char *root_dir) { + + assert(p); assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - zero(*paths); - - return lookup_paths_init(paths, - scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER, - scope == UNIT_FILE_USER, - root_dir, - NULL, NULL, NULL); + return lookup_paths_init( + p, + scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER, + scope == UNIT_FILE_USER, + root_dir); } diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index c53d293072..1e3bce21a4 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -20,37 +20,34 @@ ***/ #include + +typedef struct LookupPaths LookupPaths; +typedef enum ManagerRunningAs ManagerRunningAs; + +#include "install.h" #include "macro.h" -typedef struct LookupPaths { - char **unit_path; -} LookupPaths; +struct LookupPaths { + char **search_path; + char *generator; + char *generator_early; + char *generator_late; +}; -typedef enum ManagerRunningAs { +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(ManagerRunningAs running_as); -int lookup_paths_init(LookupPaths *p, - ManagerRunningAs running_as, - bool personal, - const char *root_dir, - const char *generator, - const char *generator_early, - const char *generator_late); - -#include "install.h" - -int lookup_paths_init_from_scope(LookupPaths *paths, - UnitFileScope scope, - const char *root_dir); +int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal, const char *root_dir); +int lookup_paths_init_from_scope(LookupPaths *p, 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/systemctl/systemctl.c b/src/systemctl/systemctl.c index 62cff3a677..4d0b4754ae 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2295,7 +2295,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un assert(unit_name); assert(unit_path); - STRV_FOREACH(p, lp->unit_path) { + STRV_FOREACH(p, lp->search_path) { _cleanup_free_ char *path; path = path_join(arg_root, *p, unit_name); @@ -2395,7 +2395,7 @@ static int unit_find_paths( } if (dropin_paths) { - r = unit_file_find_dropin_paths(lp->unit_path, NULL, names, &dropins); + r = unit_file_find_dropin_paths(lp->search_path, NULL, names, &dropins); if (r < 0) return r; } @@ -5271,7 +5271,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, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL); + r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root); if (r < 0) return r; @@ -5295,7 +5295,7 @@ static int enable_sysv_units(const char *verb, char **args) { if (path_is_absolute(name)) continue; - STRV_FOREACH(k, paths.unit_path) { + STRV_FOREACH(k, paths.search_path) { _cleanup_free_ char *path = NULL; path = path_join(arg_root, *k, name); diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index ca28c724dd..b82c877dc7 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -1004,7 +1004,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL); + r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL); if (r < 0) { log_error_errno(r, "Failed to find lookup paths: %m"); goto finish; diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index 268da002a9..ebb11dcb6d 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -31,25 +31,20 @@ static void test_paths(ManagerRunningAs running_as, bool personal) { _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {}; _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {}; - char *exists, *not, *systemd_unit_path; + char *systemd_unit_path; assert_se(mkdtemp(template)); - exists = strjoina(template, "/exists"); - assert_se(mkdir(exists, 0755) == 0); - not = strjoina(template, "/not"); assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); - assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0); + assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL) == 0); - assert_se(!strv_isempty(lp_without_env.unit_path)); - assert_se(strv_contains(lp_without_env.unit_path, exists)); - assert_se(strv_contains(lp_without_env.unit_path, not)); + assert_se(!strv_isempty(lp_without_env.search_path)); systemd_unit_path = strjoina(template, "/systemd-unit-path"); assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); - assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0); - assert_se(strv_length(lp_with_env.unit_path) == 1); - assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path)); + assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL) == 0); + assert_se(strv_length(lp_with_env.search_path) == 1); + assert_se(streq(lp_with_env.search_path[0], systemd_unit_path)); assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -- cgit v1.2.3-54-g00ecf From f413930863ab3b98cb7bf9e761081b4e88a5d7d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 15:44:46 +0100 Subject: core: add a new unit file state "generated" Now that we store the generator directories in LookupPaths we can use this to intrdouce a new unit file state called "generated", for units in these directories. Fixes: #2348 --- man/systemctl.xml | 13 +++++++++---- src/shared/install.c | 23 +++++++++++++++++++++++ src/shared/install.h | 1 + src/systemctl/systemctl.c | 7 ++++--- 4 files changed, 37 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/man/systemctl.xml b/man/systemctl.xml index 089fb0f5c3..0febdfd4de 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1168,22 +1168,27 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service static - The unit file is not enabled, and has no provisions for enabling in the [Install] section. + The unit file is not enabled, and has no provisions for enabling in the [Install] unit file section. 0 indirect - The unit file itself is not enabled, but it has a non-empty Also= setting in the [Install] section, listing other unit files that might be enabled. + The unit file itself is not enabled, but it has a non-empty Also= setting in the [Install] unit file section, listing other unit files that might be enabled. 0 disabled - Unit file is not enabled, but contains an [Install] section with installation instructions. + The unit file is not enabled, but contains an [Install] section with installation instructions. > 0 + + generated + The unit file was generated dynamically via a generator tool. See systemd.generator7. Generated unit files may not be enabled, they are enabled implicitly by their generator. + 0 + bad - Unit file is invalid or another error occurred. Note that is-enabled will not actually return this state, but print an error message instead. However the unit file listing printed by list-unit-files might show it. + The unit file is invalid or another error occurred. Note that is-enabled will not actually return this state, but print an error message instead. However the unit file listing printed by list-unit-files might show it. > 0 diff --git a/src/shared/install.c b/src/shared/install.c index e232d76dd7..202d16e129 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -82,6 +82,20 @@ static int in_search_path(const char *path, char **search) { return false; } +static int unit_file_is_generated(const LookupPaths *p, const char *path) { + _cleanup_free_ char *parent = NULL; + + assert(path); + + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; + + return path_equal(p->generator, parent) || + path_equal(p->generator_early, parent) || + path_equal(p->generator_late, parent); +} + static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { char *p = NULL; int r; @@ -2023,6 +2037,14 @@ int unit_file_lookup_state( break; case UNIT_FILE_TYPE_REGULAR: + r = unit_file_is_generated(paths, i->path); + if (r < 0) + return r; + if (r > 0) { + state = UNIT_FILE_GENERATED; + break; + } + r = find_symlinks_in_scope(scope, root_dir, i->name, &state); if (r < 0) return r; @@ -2453,6 +2475,7 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { [UNIT_FILE_STATIC] = "static", [UNIT_FILE_DISABLED] = "disabled", [UNIT_FILE_INDIRECT] = "indirect", + [UNIT_FILE_GENERATED] = "generated", [UNIT_FILE_BAD] = "bad", }; diff --git a/src/shared/install.h b/src/shared/install.h index 82b6d425eb..18aad65d50 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -54,6 +54,7 @@ enum UnitFileState { UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_INDIRECT, + UNIT_FILE_GENERATED, UNIT_FILE_BAD, _UNIT_FILE_STATE_MAX, _UNIT_FILE_STATE_INVALID = -1 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 4d0b4754ae..6394b4749e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5783,7 +5783,8 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { UNIT_FILE_ENABLED, UNIT_FILE_ENABLED_RUNTIME, UNIT_FILE_STATIC, - UNIT_FILE_INDIRECT)) + UNIT_FILE_INDIRECT, + UNIT_FILE_GENERATED)) enabled = true; if (!arg_quiet) @@ -5818,7 +5819,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect")) + if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated")) enabled = true; if (!arg_quiet) @@ -5826,7 +5827,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { } } - return !enabled; + return enabled ? EXIT_SUCCESS : EXIT_FAILURE; } static int is_system_running(int argc, char *argv[], void *userdata) { -- cgit v1.2.3-54-g00ecf From 7bfe3d44d008f46d65ebdf5adc0c847b45fd4ab2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 16:02:48 +0100 Subject: core: when enabling a generated unit file, return a clean error Let's be precise when the user tries to invoke an "enable" operation on a generated unit file. --- src/core/dbus-manager.c | 8 ++++++-- src/libsystemd/sd-bus/bus-common-errors.c | 1 + src/libsystemd/sd-bus/bus-common-errors.h | 1 + src/shared/install.c | 10 ++++++++++ src/systemctl/systemctl.c | 4 ++++ 5 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 739bd14b9e..e187e19d03 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1648,7 +1648,9 @@ static int method_enable_unit_files_generic( r = call(scope, runtime, NULL, l, force, &changes, &n_changes); if (r == -ESHUTDOWN) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked"); + return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); + if (r == -EADDRNOTAVAIL) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is generated."); if (r < 0) return r; @@ -1886,7 +1888,9 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); if (r == -ESHUTDOWN) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked"); + return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); + if (r == -EADDRNOTAVAIL) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is generated."); if (r < 0) return r; diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 6370061daf..f16878cd1a 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -38,6 +38,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { 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, ESHUTDOWN), + SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_GENERATED, EADDRNOTAVAIL), SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR), SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM), SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 464834979a..c16605ba87 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -34,6 +34,7 @@ #define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic" #define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" #define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" +#define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated" #define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" #define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" diff --git a/src/shared/install.c b/src/shared/install.c index 202d16e129..1e497d1492 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1761,6 +1761,8 @@ int unit_file_add_dependency( return r; if (target_info->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; + if (unit_file_is_generated(&paths, target_info->path)) + return -EADDRNOTAVAIL; assert(target_info->type == UNIT_FILE_TYPE_REGULAR); @@ -1772,6 +1774,8 @@ int unit_file_add_dependency( return r; if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; + if (unit_file_is_generated(&paths, i->path)) + return -EADDRNOTAVAIL; assert(i->type == UNIT_FILE_TYPE_REGULAR); @@ -1830,6 +1834,8 @@ int unit_file_enable( return r; if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; + if (unit_file_is_generated(&paths, i->path)) + return -EADDRNOTAVAIL; assert(i->type == UNIT_FILE_TYPE_REGULAR); } @@ -1957,6 +1963,8 @@ int unit_file_set_default( return r; if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; + if (unit_file_is_generated(&paths, i->path)) + return -EADDRNOTAVAIL; path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET); @@ -2254,6 +2262,8 @@ static int preset_prepare_one( if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; + if (unit_file_is_generated(paths, i->path)) + return -EADDRNOTAVAIL; } else r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 6394b4749e..4103a5da6d 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5473,6 +5473,8 @@ static int enable_unit(int argc, char *argv[], void *userdata) { if (r == -ESHUTDOWN) return log_error_errno(r, "Unit file is masked."); + if (r == -EADDRNOTAVAIL) + return log_error_errno(r, "Unit file is generated."); if (r < 0) return log_error_errno(r, "Operation failed: %m"); @@ -5639,6 +5641,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) { r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); if (r == -ESHUTDOWN) return log_error_errno(r, "Unit file is masked."); + if (r == -EADDRNOTAVAIL) + return log_error_errno(r, "Unit file is generated."); if (r < 0) return log_error_errno(r, "Can't add dependency: %m"); -- cgit v1.2.3-54-g00ecf From a0f84a104c537bb3143212796cb9d8a1b61d8b3e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 17:18:42 +0100 Subject: core: add configuration directories to LookupPaths Let's add a seperate fields for the directories where we place runtime and persistent configuration, so that we can use this in install.c (to be added in a later commit), and we store path information in the same place everywhere. --- src/shared/path-lookup.c | 82 +++++++++++++++++++++++++++++++++++++++++++----- src/shared/path-lookup.h | 6 ++++ 2 files changed, 81 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index ec3f5b53f4..5766053cef 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -106,6 +106,8 @@ static int user_data_home_dir(char **dir, const char *suffix) { } static char** user_dirs( + const char *persistent_config, + const char *runtime_config, const char *generator, const char *generator_early, const char *generator_late) { @@ -116,8 +118,6 @@ static char** user_dirs( NULL }; - const char * const runtime_unit_path = "/run/systemd/user"; - const char * const data_unit_paths[] = { "/usr/local/lib/systemd/user", "/usr/local/share/systemd/user", @@ -183,6 +183,9 @@ static char** user_dirs( if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0) return NULL; + if (strv_extend(&res, persistent_config) < 0) + return NULL; + if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0) return NULL; @@ -190,7 +193,7 @@ static char** user_dirs( if (strv_extend(&res, runtime_dir) < 0) return NULL; - if (strv_extend(&res, runtime_unit_path) < 0) + if (strv_extend(&res, runtime_config) < 0) return NULL; if (generator) @@ -282,6 +285,48 @@ static int acquire_generator_dirs( return 0; } +static int acquire_config_dirs(ManagerRunningAs running_as, bool personal, char **persistent, char **runtime) { + _cleanup_free_ char *a = NULL, *b = NULL; + int r; + + assert(persistent); + assert(runtime); + + if (running_as == MANAGER_SYSTEM) { + a = strdup(SYSTEM_CONFIG_UNIT_PATH); + b = strdup("/run/systemd/system"); + } else if (personal) { + assert(running_as == MANAGER_USER); + + r = user_config_home(&a); + if (r < 0) + return r; + + r = user_runtime_dir(runtime); + if (r < 0) + return r; + + *persistent = a; + a = NULL; + + return 0; + } else { + assert(running_as == MANAGER_USER); + + a = strdup(USER_CONFIG_UNIT_PATH); + b = strdup("/run/systemd/user"); + } + + if (!a || !b) + return -ENOMEM; + + *persistent = a; + *runtime = b; + a = b = NULL; + + return 0; +} + static int patch_root_prefix(char **p, const char *root_dir) { char *c; @@ -309,7 +354,8 @@ int lookup_paths_init( bool personal, const char *root_dir) { - _cleanup_free_ char *generator = NULL, *generator_early = NULL, *generator_late = NULL; + _cleanup_free_ char *generator = NULL, *generator_early = NULL, *generator_late = NULL, + *persistent_config = NULL, *runtime_config = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ char **l = NULL; const char *e; @@ -319,6 +365,10 @@ int lookup_paths_init( assert(running_as >= 0); assert(running_as < _MANAGER_RUNNING_AS_MAX); + r = acquire_config_dirs(running_as, personal, &persistent_config, &runtime_config); + if (r < 0) + return r; + r = acquire_generator_dirs(running_as, &generator, &generator_early, &generator_late); if (r < 0) return r; @@ -357,15 +407,17 @@ int lookup_paths_init( if (running_as == MANAGER_USER) { if (personal) - add = user_dirs(generator, generator_early, generator_late); + add = user_dirs(persistent_config, runtime_config, + generator, generator_early, generator_late); else add = strv_new( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and * the arrays in user_dirs() above! */ generator_early, - USER_CONFIG_UNIT_PATH, + persistent_config, "/etc/systemd/user", + runtime_config, "/run/systemd/user", generator, "/usr/local/lib/systemd/user", @@ -380,8 +432,9 @@ int lookup_paths_init( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ generator_early, - SYSTEM_CONFIG_UNIT_PATH, + persistent_config, "/etc/systemd/system", + runtime_config, "/run/systemd/system", generator, "/usr/local/lib/systemd/system", @@ -406,6 +459,13 @@ int lookup_paths_init( } } + r = patch_root_prefix(&persistent_config, root_dir); + if (r < 0) + return r; + r = patch_root_prefix(&runtime_config, root_dir); + if (r < 0) + return r; + r = patch_root_prefix(&generator, root_dir); if (r < 0) return r; @@ -435,6 +495,10 @@ int lookup_paths_init( p->search_path = l; l = NULL; + p->persistent_config = persistent_config; + p->runtime_config = runtime_config; + persistent_config = runtime_config = NULL; + p->generator = generator; p->generator_early = generator_early; p->generator_late = generator_late; @@ -448,6 +512,10 @@ void lookup_paths_free(LookupPaths *p) { return; p->search_path = strv_free(p->search_path); + + p->persistent_config = mfree(p->persistent_config); + p->runtime_config = mfree(p->runtime_config); + p->generator = mfree(p->generator); p->generator_early = mfree(p->generator_early); p->generator_late = mfree(p->generator_late); diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 1e3bce21a4..64c8035c2b 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -29,6 +29,12 @@ typedef enum ManagerRunningAs ManagerRunningAs; struct LookupPaths { char **search_path; + + /* Where we shall create or remove our installation symlinks, aka "configuration". */ + char *persistent_config; + char *runtime_config; + + /* Where to place generated unit files */ char *generator; char *generator_early; char *generator_late; -- cgit v1.2.3-54-g00ecf From e1c5c2b0d258e60ec20af748f69f0394d30f8644 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 17:52:45 +0100 Subject: install: make use of configuration directory paths in LookupPaths Now that the LookupPaths structure contains the directory paths, let's make use of that everywhere instead of duplicating the logic. --- src/shared/install.c | 197 +++++++++++++-------------------------------------- 1 file changed, 51 insertions(+), 146 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 1e497d1492..2cec6ba76f 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -85,6 +85,7 @@ static int in_search_path(const char *path, char **search) { static int unit_file_is_generated(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; + assert(p); assert(path); parent = dirname_malloc(path); @@ -96,110 +97,27 @@ static int unit_file_is_generated(const LookupPaths *p, const char *path) { path_equal(p->generator_late, parent); } -static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { - char *p = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(ret); - - /* This determines where we shall create or remove our - * installation ("configuration") symlinks */ - - switch (scope) { - - case UNIT_FILE_SYSTEM: - - if (runtime) - p = path_join(root_dir, "/run/systemd/system", NULL); - else - p = path_join(root_dir, SYSTEM_CONFIG_UNIT_PATH, NULL); - break; - - case UNIT_FILE_GLOBAL: - - if (root_dir) - return -EINVAL; - - if (runtime) - p = strdup("/run/systemd/user"); - else - p = strdup(USER_CONFIG_UNIT_PATH); - break; - - case UNIT_FILE_USER: - - if (root_dir) - return -EINVAL; - - if (runtime) - r = user_runtime_dir(&p); - else - r = user_config_home(&p); - if (r < 0) - return r; - if (r == 0) - return -ENOENT; - - break; - - default: - assert_not_reached("Bad scope"); - } - - if (!p) - return -ENOMEM; - - *ret = p; - return 0; -} - -static bool is_config_path(UnitFileScope scope, const char *path) { - int r; +static int path_is_config(const LookupPaths *p, const char *path) { + _cleanup_free_ char *parent = NULL; - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(p); assert(path); - /* Checks whether the specified path is intended for - * configuration or is outside of it */ - - switch (scope) { - - case UNIT_FILE_SYSTEM: - case UNIT_FILE_GLOBAL: - return path_startswith(path, "/etc") || - path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) || - path_startswith(path, "/run"); - - - case UNIT_FILE_USER: { - _cleanup_free_ char *p = NULL; - - r = user_config_home(&p); - if (r < 0) - return r; - if (r > 0 && path_startswith(path, p)) - return true; - - p = mfree(p); + /* Checks whether the specified path is intended for configuration or is outside of it. We check both the + * top-level directory and the one actually configured. The latter is particularly relevant for cases where we + * operate on a root directory. */ - r = user_runtime_dir(&p); - if (r < 0) - return r; - if (r > 0 && path_startswith(path, p)) - return true; + if (path_startswith(path, "/etc") || path_startswith(path, "/run")) + return true; - return false; - } + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; - default: - assert_not_reached("Bad scope"); - } + return path_equal(parent, p->persistent_config) || + path_equal(parent, p->runtime_config); } - static int verify_root_dir(UnitFileScope scope, const char **root_dir) { int r; @@ -659,24 +577,21 @@ static int find_symlinks( static int find_symlinks_in_scope( UnitFileScope scope, + const LookupPaths *paths, const char *root_dir, const char *name, UnitFileState *state) { - _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL; bool same_name_link_runtime = false, same_name_link = false; int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(paths); assert(name); - /* First look in the normal config path */ - r = get_config_path(scope, false, root_dir, &normal_path); - if (r < 0) - return r; - - r = find_symlinks(root_dir, name, normal_path, &same_name_link); + /* First look in the persistent config path */ + r = find_symlinks(root_dir, name, paths->persistent_config, &same_name_link); if (r < 0) return r; if (r > 0) { @@ -685,11 +600,7 @@ static int find_symlinks_in_scope( } /* Then look in runtime config path */ - r = get_config_path(scope, true, root_dir, &runtime_path); - if (r < 0) - return r; - - r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime); + r = find_symlinks(root_dir, name, paths->runtime_config, &same_name_link_runtime); if (r < 0) return r; if (r > 0) { @@ -1182,8 +1093,13 @@ static int install_info_traverse( if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX) return -ELOOP; - if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path)) - return -ELOOP; + if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) { + r = path_is_config(paths, i->path); + if (r < 0) + return r; + if (r > 0) + return -ELOOP; + } r = install_info_follow(c, i, root_dir, flags); if (r < 0) { @@ -1514,7 +1430,8 @@ int unit_file_mask( UnitFileChange **changes, unsigned *n_changes) { - _cleanup_free_ char *prefix = NULL; + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + const char *config_path; char **i; int r; @@ -1525,10 +1442,12 @@ int unit_file_mask( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &prefix); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; + STRV_FOREACH(i, files) { _cleanup_free_ char *path = NULL; int q; @@ -1539,7 +1458,7 @@ int unit_file_mask( continue; } - path = path_make_absolute(*i, prefix); + path = path_make_absolute(*i, config_path); if (!path) return -ENOMEM; @@ -1559,10 +1478,11 @@ int unit_file_unmask( UnitFileChange **changes, unsigned *n_changes) { + _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - _cleanup_free_ char *config_path = NULL; _cleanup_free_ char **todo = NULL; size_t n_todo = 0, n_allocated = 0; + const char *config_path; char **i; int r, q; @@ -1573,10 +1493,12 @@ int unit_file_unmask( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &config_path); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; + STRV_FOREACH(i, files) { _cleanup_free_ char *path = NULL; @@ -1640,9 +1562,9 @@ int unit_file_link( unsigned *n_changes) { _cleanup_lookup_paths_free_ LookupPaths paths = {}; - _cleanup_free_ char *config_path = NULL; _cleanup_free_ char **todo = NULL; size_t n_todo = 0, n_allocated = 0; + const char *config_path; char **i; int r, q; @@ -1657,9 +1579,7 @@ int unit_file_link( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { _cleanup_free_ char *full = NULL; @@ -1729,8 +1649,8 @@ int unit_file_add_dependency( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; - _cleanup_free_ char *config_path = NULL; UnitFileInstallInfo *i, *target_info; + const char *config_path; char **f; int r; @@ -1752,9 +1672,7 @@ int unit_file_add_dependency( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); if (r < 0) @@ -1808,7 +1726,7 @@ int unit_file_enable( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; - _cleanup_free_ char *config_path = NULL; + const char *config_path; UnitFileInstallInfo *i; char **f; int r; @@ -1824,9 +1742,7 @@ int unit_file_enable( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(f, files) { r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i); @@ -1858,8 +1774,8 @@ int unit_file_disable( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; - _cleanup_free_ char *config_path = NULL; _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + const char *config_path; char **i; int r; @@ -1874,9 +1790,7 @@ int unit_file_disable( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) @@ -1932,7 +1846,6 @@ int unit_file_set_default( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; - _cleanup_free_ char *config_path = NULL; UnitFileInstallInfo *i; const char *path; int r; @@ -1954,10 +1867,6 @@ int unit_file_set_default( if (r < 0) return r; - r = get_config_path(scope, false, root_dir, &config_path); - if (r < 0) - return r; - r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i); if (r < 0) return r; @@ -1966,7 +1875,7 @@ int unit_file_set_default( if (unit_file_is_generated(&paths, i->path)) return -EADDRNOTAVAIL; - path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET); + path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); return create_symlink(i->path, path, force, changes, n_changes); } @@ -2053,7 +1962,7 @@ int unit_file_lookup_state( break; } - r = find_symlinks_in_scope(scope, root_dir, i->name, &state); + r = find_symlinks_in_scope(scope, paths, root_dir, i->name, &state); if (r < 0) return r; if (r == 0) { @@ -2282,7 +2191,7 @@ int unit_file_preset( _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; _cleanup_lookup_paths_free_ LookupPaths paths = {}; - _cleanup_free_ char *config_path = NULL; + const char *config_path; char **i; int r; @@ -2298,9 +2207,7 @@ int unit_file_preset( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) @@ -2325,7 +2232,7 @@ int unit_file_preset_all( _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; _cleanup_lookup_paths_free_ LookupPaths paths = {}; - _cleanup_free_ char *config_path = NULL; + const char *config_path = NULL; char **i; int r; @@ -2341,9 +2248,7 @@ int unit_file_preset_all( if (r < 0) return r; - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - return r; + config_path = runtime ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, paths.search_path) { _cleanup_closedir_ DIR *d = NULL; -- cgit v1.2.3-54-g00ecf From c51932be73e9cfc96e7bcaea1b31347133e1f3ed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 18:17:42 +0100 Subject: systemctl: port systemctl over to the new LookupPaths configuration directory fields --- src/systemctl/systemctl.c | 104 +++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 4103a5da6d..bab34986e3 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4780,34 +4780,6 @@ static int show(int argc, char *argv[], void *userdata) { return ret; } -static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) { - int r; - - assert(user_home); - assert(user_runtime); - assert(lp); - - if (arg_scope == UNIT_FILE_USER) { - r = user_config_home(user_home); - if (r < 0) - return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m"); - else if (r == 0) - return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set."); - - r = user_runtime_dir(user_runtime); - if (r < 0) - return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m"); - else if (r == 0) - return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set."); - } - - r = lookup_paths_init_from_scope(lp, arg_scope, arg_root); - if (r < 0) - return log_error_errno(r, "Failed to query unit lookup paths: %m"); - - return 0; -} - static int cat_file(const char *filename, bool newline) { _cleanup_close_ int fd; @@ -4826,8 +4798,6 @@ static int cat_file(const char *filename, bool newline) { } static int cat(int argc, char *argv[], void *userdata) { - _cleanup_free_ char *user_home = NULL; - _cleanup_free_ char *user_runtime = NULL; _cleanup_lookup_paths_free_ LookupPaths lp = {}; _cleanup_strv_free_ char **names = NULL; char **name; @@ -4840,9 +4810,9 @@ static int cat(int argc, char *argv[], void *userdata) { return -EINVAL; } - r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp); + r = lookup_paths_init_from_scope(&lp, arg_scope, arg_root); if (r < 0) - return r; + return log_error_errno(r, "Failed to determine unit paths: %m"); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -5901,52 +5871,32 @@ static int create_edit_temp_file(const char *new_path, const char *original_path return 0; } -static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) { - _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL; +static int get_file_to_edit( + const LookupPaths *paths, + const char *name, + char **ret_path) { + + _cleanup_free_ char *path = NULL, *run = NULL; assert(name); assert(ret_path); - switch (arg_scope) { - case UNIT_FILE_SYSTEM: - path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name); - if (arg_runtime) - run = path_join(arg_root, "/run/systemd/system/", name); - break; - case UNIT_FILE_GLOBAL: - path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name); - if (arg_runtime) - run = path_join(arg_root, "/run/systemd/user/", name); - break; - case UNIT_FILE_USER: - assert(user_home); - assert(user_runtime); - - path = path_join(arg_root, user_home, name); - if (arg_runtime) { - path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name); - if (!path2) - return log_oom(); - run = path_join(arg_root, user_runtime, name); - } - break; - default: - assert_not_reached("Invalid scope"); - } - if (!path || (arg_runtime && !run)) + path = strjoin(paths->persistent_config, "/", name, NULL); + if (!path) return log_oom(); + if (arg_runtime) { + run = strjoin(paths->runtime_config, name, NULL); + if (!run) + return log_oom(); + } + if (arg_runtime) { if (access(path, F_OK) >= 0) { log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path); return -EEXIST; } - if (path2 && access(path2, F_OK) >= 0) { - log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2); - return -EEXIST; - } - *ret_path = run; run = NULL; } else { @@ -5957,7 +5907,12 @@ 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) { +static int unit_file_create_dropin( + const LookupPaths *paths, + const char *unit_name, + char **ret_new_path, + char **ret_tmp_path) { + char *tmp_new_path, *tmp_tmp_path, *ending; int r; @@ -5966,7 +5921,7 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home, assert(ret_tmp_path); ending = strjoina(unit_name, ".d/override.conf"); - r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path); + r = get_file_to_edit(paths, ending, &tmp_new_path); if (r < 0) return r; @@ -5983,10 +5938,9 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home, } static int unit_file_create_copy( + const LookupPaths *paths, const char *unit_name, const char *fragment_path, - const char *user_home, - const char *user_runtime, char **ret_new_path, char **ret_tmp_path) { @@ -5998,7 +5952,7 @@ static int unit_file_create_copy( assert(ret_new_path); assert(ret_tmp_path); - r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path); + r = get_file_to_edit(paths, unit_name, &tmp_new_path); if (r < 0) return r; @@ -6113,8 +6067,6 @@ static int run_editor(char **paths) { } static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { - _cleanup_free_ char *user_home = NULL; - _cleanup_free_ char *user_runtime = NULL; _cleanup_lookup_paths_free_ LookupPaths lp = {}; char **name; int r; @@ -6122,7 +6074,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { assert(names); assert(paths); - r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp); + r = lookup_paths_init_from_scope(&lp, arg_scope, arg_root); if (r < 0) return r; @@ -6142,9 +6094,9 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { } if (arg_full) - r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path); + r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path); else - r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path); + r = unit_file_create_dropin(&lp, *name, &new_path, &tmp_path); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 463d0d15690c7abe2172a23ae23c5547693dd71f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 21:24:23 +0100 Subject: core: remove ManagerRunningAs enum Previously, we had two enums ManagerRunningAs and UnitFileScope, that were mostly identical and converted from one to the other all the time. The latter had one more value UNIT_FILE_GLOBAL however. Let's simplify things, and remove ManagerRunningAs and replace it by UnitFileScope everywhere, thus making the translation unnecessary. Introduce two new macros MANAGER_IS_SYSTEM() and MANAGER_IS_USER() to simplify checking if we are running in one or the user context. --- src/analyze/analyze-verify.c | 8 +- src/analyze/analyze-verify.h | 2 +- src/analyze/analyze.c | 2 +- src/core/automount.c | 2 +- src/core/busname.c | 4 +- src/core/cgroup.c | 4 +- src/core/dbus-manager.c | 54 ++++-------- src/core/dbus.c | 16 ++-- src/core/device.c | 2 +- src/core/failure-action.c | 2 +- src/core/job.c | 2 +- src/core/load-fragment.c | 2 +- src/core/main.c | 44 +++++----- src/core/manager.c | 89 +++++++++----------- src/core/manager.h | 9 +- src/core/mount.c | 11 ++- src/core/path.c | 2 +- src/core/service.c | 4 +- src/core/socket.c | 2 +- src/core/swap.c | 4 +- src/core/timer.c | 4 +- src/core/unit-printf.c | 2 +- src/core/unit.c | 18 ++-- src/shared/install.c | 24 +++--- src/shared/path-lookup.c | 163 ++++++++++++++++++++---------------- src/shared/path-lookup.h | 13 +-- src/systemctl/systemctl.c | 6 +- src/sysv-generator/sysv-generator.c | 2 +- src/test/test-cgroup-mask.c | 2 +- src/test/test-engine.c | 2 +- src/test/test-execute.c | 8 +- src/test/test-path-lookup.c | 23 +++-- src/test/test-path.c | 2 +- src/test/test-sched-prio.c | 2 +- src/test/test-unit-file.c | 2 +- src/test/test-unit-name.c | 2 +- 36 files changed, 258 insertions(+), 282 deletions(-) (limited to 'src') diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index b83f559e7d..5fd3ee49eb 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -231,14 +231,12 @@ static int verify_unit(Unit *u, bool check_man) { return r; } -int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) { +int verify_units(char **filenames, UnitFileScope scope, bool check_man) { _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_free_ char *var = NULL; Manager *m = NULL; FILE *serial = NULL; FDSet *fdset = NULL; - - _cleanup_free_ char *var = NULL; - char **filename; int r = 0, k; @@ -255,7 +253,7 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) assert_se(set_unit_path(var) >= 0); - r = manager_new(running_as, true, &m); + r = manager_new(scope, true, &m); if (r < 0) return log_error_errno(r, "Failed to initialize manager: %m"); diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h index 27c253a562..d8204dc69c 100644 --- a/src/analyze/analyze-verify.h +++ b/src/analyze/analyze-verify.h @@ -23,4 +23,4 @@ #include "path-lookup.h" -int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man); +int verify_units(char **filenames, UnitFileScope scope, bool check_man); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 42754a2741..5e03c0c5e0 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -1443,7 +1443,7 @@ int main(int argc, char *argv[]) { if (streq_ptr(argv[optind], "verify")) r = verify_units(argv+optind+1, - arg_user ? MANAGER_USER : MANAGER_SYSTEM, + arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM, arg_man); else { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; diff --git a/src/core/automount.c b/src/core/automount.c index 5dc6fd98e7..7c55d7bc49 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -149,7 +149,7 @@ static int automount_add_default_dependencies(Automount *a) { if (!UNIT(a)->default_dependencies) return 0; - if (UNIT(a)->manager->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(UNIT(a)->manager)) return 0; r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); diff --git a/src/core/busname.c b/src/core/busname.c index de2a21ccde..bbe61af4f0 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -149,7 +149,7 @@ static int busname_add_default_default_dependencies(BusName *n) { if (r < 0) return r; - if (UNIT(n)->manager->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(UNIT(n)->manager)) { r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); if (r < 0) return r; @@ -318,7 +318,7 @@ static int busname_open_fd(BusName *n) { if (n->starter_fd >= 0) return 0; - mode = UNIT(n)->manager->running_as == MANAGER_SYSTEM ? "system" : "user"; + mode = MANAGER_IS_SYSTEM(UNIT(n)->manager) ? "system" : "user"; n->starter_fd = bus_kernel_open_bus_fd(mode, &path); if (n->starter_fd < 0) return log_unit_warning_errno(UNIT(n), n->starter_fd, "Failed to open %s: %m", path ?: "kdbus"); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 9c34928052..25cc6962f9 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1265,7 +1265,7 @@ int manager_setup_cgroup(Manager *m) { * it. This is to support live upgrades from older systemd * versions where PID 1 was moved there. Also see * cg_get_root_path(). */ - if (!e && m->running_as == MANAGER_SYSTEM) { + if (!e && MANAGER_IS_SYSTEM(m)) { e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE); if (!e) e = endswith(m->cgroup_root, "/system"); /* even more legacy */ @@ -1318,7 +1318,7 @@ int manager_setup_cgroup(Manager *m) { (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify"); - } else if (m->running_as == MANAGER_SYSTEM) { + } else if (MANAGER_IS_SYSTEM(m)) { /* On the legacy hierarchy we only get * notifications via cgroup agents. (Which diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index e187e19d03..5fc3526751 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1187,7 +1187,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * if (r < 0) return r; - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers."); m->exit_code = MANAGER_REBOOT; @@ -1206,7 +1206,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error if (r < 0) return r; - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers."); m->exit_code = MANAGER_POWEROFF; @@ -1225,7 +1225,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er if (r < 0) return r; - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers."); m->exit_code = MANAGER_HALT; @@ -1244,7 +1244,7 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e if (r < 0) return r; - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers."); m->exit_code = MANAGER_KEXEC; @@ -1265,7 +1265,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er if (r < 0) return r; - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) 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); @@ -1433,7 +1433,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_ if (r < 0) return r; - if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0) + if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers."); m->return_value = code; @@ -1466,7 +1466,7 @@ static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bu if (!h) return -ENOMEM; - r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h); + r = unit_file_get_list(m->unit_file_scope, NULL, h); if (r < 0) goto fail; @@ -1498,7 +1498,6 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s Manager *m = userdata; const char *name; UnitFileState state; - UnitFileScope scope; int r; assert(message); @@ -1514,9 +1513,7 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s if (r < 0) return r; - scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - - r = unit_file_get_state(scope, NULL, name, &state); + r = unit_file_get_state(m->unit_file_scope, NULL, name, &state); if (r < 0) return r; @@ -1526,7 +1523,6 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s 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(message); @@ -1538,9 +1534,7 @@ static int method_get_default_target(sd_bus_message *message, void *userdata, sd if (r < 0) return r; - scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - - r = unit_file_get_default(scope, NULL, &default_target); + r = unit_file_get_default(m->unit_file_scope, NULL, &default_target); if (r < 0) return r; @@ -1624,7 +1618,6 @@ static int method_enable_unit_files_generic( _cleanup_strv_free_ char **l = NULL; UnitFileChange *changes = NULL; unsigned n_changes = 0; - UnitFileScope scope; int runtime, force, r; assert(message); @@ -1644,9 +1637,7 @@ static int method_enable_unit_files_generic( 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); + r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes); if (r == -ESHUTDOWN) return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); if (r == -EADDRNOTAVAIL) @@ -1688,7 +1679,6 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use unsigned n_changes = 0; Manager *m = userdata; UnitFilePresetMode mm; - UnitFileScope scope; int runtime, force, r; const char *mode; @@ -1717,9 +1707,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use 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); + r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes); if (r < 0) return r; @@ -1736,7 +1724,6 @@ static int method_disable_unit_files_generic( _cleanup_strv_free_ char **l = NULL; UnitFileChange *changes = NULL; unsigned n_changes = 0; - UnitFileScope scope; int r, runtime; assert(message); @@ -1750,15 +1737,13 @@ static int method_disable_unit_files_generic( if (r < 0) return r; - 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; 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); + r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes); if (r < 0) return r; @@ -1777,7 +1762,6 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd UnitFileChange *changes = NULL; unsigned n_changes = 0; Manager *m = userdata; - UnitFileScope scope; const char *name; int force, r; @@ -1798,9 +1782,7 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd 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_set_default(scope, NULL, name, force, &changes, &n_changes); + r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes); if (r < 0) return r; @@ -1812,7 +1794,6 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, unsigned n_changes = 0; Manager *m = userdata; UnitFilePresetMode mm; - UnitFileScope scope; const char *mode; int force, runtime, r; @@ -1841,9 +1822,7 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, 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); + r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes); if (r < 0) { unit_file_changes_free(changes, n_changes); return r; @@ -1857,7 +1836,6 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd Manager *m = userdata; UnitFileChange *changes = NULL; unsigned n_changes = 0; - UnitFileScope scope; int runtime, force, r; char *target; char *type; @@ -1884,9 +1862,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd if (dep < 0) return -EINVAL; - 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); + r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); if (r == -ESHUTDOWN) return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); if (r == -EADDRNOTAVAIL) diff --git a/src/core/dbus.c b/src/core/dbus.c index 413489373f..263955d874 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -112,7 +112,7 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus manager_notify_cgroup_empty(m, cgroup); /* if running as system-instance, forward under our name */ - if (m->running_as == MANAGER_SYSTEM && m->system_bus) { + if (MANAGER_IS_SYSTEM(m) && m->system_bus) { r = sd_bus_message_rewind(message, 1); if (r >= 0) r = sd_bus_send(m->system_bus, message, NULL); @@ -690,7 +690,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } - if (m->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(m)) { /* When we run as system instance we get the Released * signal via a direct connection */ @@ -864,10 +864,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 == MANAGER_SYSTEM && m->system_bus) + if (MANAGER_IS_SYSTEM(m) && m->system_bus) bus = sd_bus_ref(m->system_bus); else { - if (m->running_as == MANAGER_SYSTEM) + if (MANAGER_IS_SYSTEM(m)) r = sd_bus_open_system(&bus); else r = sd_bus_open_user(&bus); @@ -907,7 +907,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) { assert(bus); /* 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) { + if (MANAGER_IS_USER(m) || m->kdbus_fd >= 0) { r = sd_bus_add_match( bus, NULL, @@ -932,7 +932,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 == MANAGER_SYSTEM && m->api_bus) { + if (MANAGER_IS_SYSTEM(m) && m->api_bus) { m->system_bus = sd_bus_ref(m->api_bus); return 0; } @@ -983,7 +983,7 @@ static int bus_init_private(Manager *m) { if (m->kdbus_fd >= 0) return 0; - if (m->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(m)) { /* We want the private bus only when running as init */ if (getpid() != 1) @@ -1082,7 +1082,7 @@ static void destroy_bus(Manager *m, sd_bus **bus) { /* Possibly flush unwritten data, but only if we are * unprivileged, since we don't want to sync here */ - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) sd_bus_flush(*bus); /* And destroy the object */ diff --git a/src/core/device.c b/src/core/device.c index 0671620a3e..d01bec53d8 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -265,7 +265,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) { assert(u); assert(dev); - property = u->manager->running_as == MANAGER_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS"; + property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS"; wants = udev_device_get_property_value(dev, property); if (!wants) return 0; diff --git a/src/core/failure-action.c b/src/core/failure-action.c index bb2bc3f399..d4aae4b6e7 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -47,7 +47,7 @@ int failure_action( if (action == FAILURE_ACTION_NONE) return -ECANCELED; - if (m->running_as == MANAGER_USER) { + if (!MANAGER_IS_SYSTEM(m)) { /* Downgrade all options to simply exiting if we run * in user mode */ diff --git a/src/core/job.c b/src/core/job.c index 5557a6a942..2e30431163 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1156,7 +1156,7 @@ void job_shutdown_magic(Job *j) { if (j->type != JOB_START) return; - if (j->unit->manager->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(j->unit->manager)) return; if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET)) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 3a77ceb551..79f13f135d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2495,7 +2495,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 == MANAGER_USER) + if (!c->no_new_privileges_set && MANAGER_IS_USER(u->manager)) c->no_new_privileges = true; return 0; diff --git a/src/core/main.c b/src/core/main.c index 56df32426a..a428e345e0 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -94,7 +94,7 @@ static enum { ACTION_DONE } arg_action = ACTION_RUN; static char *arg_default_unit = NULL; -static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID; +static bool arg_system = false; static bool arg_dump_core = true; static int arg_crash_chvt = -1; static bool arg_crash_shell = false; @@ -688,11 +688,11 @@ static int parse_config_file(void) { const char *fn, *conf_dirs_nulstr; - fn = arg_running_as == MANAGER_SYSTEM ? + fn = arg_system ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf"; - conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? + conf_dirs_nulstr = arg_system ? CONF_PATHS_NULSTR("systemd/system.conf.d") : CONF_PATHS_NULSTR("systemd/user.conf.d"); @@ -866,11 +866,11 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_SYSTEM: - arg_running_as = MANAGER_SYSTEM; + arg_system = true; break; case ARG_USER: - arg_running_as = MANAGER_USER; + arg_system = false; break; case ARG_TEST: @@ -1346,7 +1346,7 @@ int main(int argc, char *argv[]) { if (getpid() == 1 && detect_container() <= 0) { /* Running outside of a container as PID 1 */ - arg_running_as = MANAGER_SYSTEM; + arg_system = true; make_null_stdio(); log_set_target(LOG_TARGET_KMSG); log_open(); @@ -1430,7 +1430,7 @@ int main(int argc, char *argv[]) { } else if (getpid() == 1) { /* Running inside a container, as PID 1 */ - arg_running_as = MANAGER_SYSTEM; + arg_system = true; log_set_target(LOG_TARGET_CONSOLE); log_close_console(); /* force reopen of /dev/console */ log_open(); @@ -1443,7 +1443,7 @@ int main(int argc, char *argv[]) { kernel_timestamp = DUAL_TIMESTAMP_NULL; } else { /* Running as user instance */ - arg_running_as = MANAGER_USER; + arg_system = false; log_set_target(LOG_TARGET_AUTO); log_open(); @@ -1501,7 +1501,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_running_as == MANAGER_SYSTEM) { + if (arg_system) { r = parse_proc_cmdline(parse_proc_cmdline_item); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); @@ -1522,14 +1522,14 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_running_as == MANAGER_USER && + if (!arg_system && 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 == MANAGER_SYSTEM && + if (arg_system && arg_action == ACTION_RUN && running_in_chroot() > 0) { log_error("Cannot be run in a chroot() environment."); @@ -1557,7 +1557,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_running_as == MANAGER_USER && + if (!arg_system && !getenv("XDG_RUNTIME_DIR")) { log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set."); goto finish; @@ -1580,7 +1580,7 @@ int main(int argc, char *argv[]) { if (arg_serialization) assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0); - if (arg_running_as == MANAGER_SYSTEM) + if (arg_system) /* Become a session leader if we aren't one yet. */ setsid(); @@ -1589,7 +1589,7 @@ int main(int argc, char *argv[]) { /* Reset the console, but only if this is really init and we * are freshly booted */ - if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) { + if (arg_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 @@ -1616,7 +1616,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_running_as == MANAGER_SYSTEM) { + if (arg_system) { int v; log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")", @@ -1652,7 +1652,7 @@ int main(int argc, char *argv[]) { arg_action == ACTION_TEST ? " test" : "", getuid(), t); } - if (arg_running_as == MANAGER_SYSTEM && !skip_setup) { + if (arg_system && !skip_setup) { if (arg_show_status > 0) status_welcome(); @@ -1664,7 +1664,7 @@ int main(int argc, char *argv[]) { test_usr(); } - if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY) + if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY) watchdog_set_timeout(&arg_runtime_watchdog); if (arg_timer_slack_nsec != NSEC_INFINITY) @@ -1694,12 +1694,12 @@ int main(int argc, char *argv[]) { } } - if (arg_running_as == MANAGER_USER) + if (!arg_system) /* Become reaper of our children */ if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) log_warning_errno(errno, "Failed to make us a subreaper: %m"); - if (arg_running_as == MANAGER_SYSTEM) { + if (arg_system) { bump_rlimit_nofile(&saved_rlimit_nofile); if (empty_etc) { @@ -1711,7 +1711,7 @@ int main(int argc, char *argv[]) { } } - r = manager_new(arg_running_as, arg_action == ACTION_TEST, &m); + r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, arg_action == ACTION_TEST, &m); if (r < 0) { log_emergency_errno(r, "Failed to allocate manager object: %m"); error_message = "Failed to allocate manager object"; @@ -1874,7 +1874,7 @@ int main(int argc, char *argv[]) { case MANAGER_EXIT: retval = m->return_value; - if (m->running_as == MANAGER_USER) { + if (MANAGER_IS_USER(m)) { log_debug("Exit."); goto finish; } @@ -1970,7 +1970,7 @@ finish: args[i++] = SYSTEMD_BINARY_PATH; if (switch_root_dir) args[i++] = "--switched-root"; - args[i++] = arg_running_as == MANAGER_SYSTEM ? "--system" : "--user"; + args[i++] = arg_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 79dc77d50e..1412d6718a 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -491,7 +491,7 @@ static int manager_setup_signals(Manager *m) { if (r < 0) return r; - if (m->running_as == MANAGER_SYSTEM) + if (MANAGER_IS_SYSTEM(m)) return enable_special_signals(m); return 0; @@ -518,7 +518,7 @@ static void manager_clean_environment(Manager *m) { static int manager_default_environment(Manager *m) { assert(m); - if (m->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(m)) { /* The system manager always starts with a clean * environment for its children. It does not import * the kernel or the parents exported variables. @@ -547,43 +547,36 @@ static int manager_default_environment(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", - }; - +int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { Manager *m; int r; assert(_m); - assert(running_as >= 0); - assert(running_as < _MANAGER_RUNNING_AS_MAX); + assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER)); m = new0(Manager, 1); if (!m) return -ENOMEM; -#ifdef ENABLE_EFI - if (running_as == MANAGER_SYSTEM && detect_container() <= 0) - boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp); -#endif - - m->running_as = running_as; + m->unit_file_scope = scope; m->exit_code = _MANAGER_EXIT_CODE_INVALID; m->default_timer_accuracy_usec = USEC_PER_MINUTE; m->default_tasks_accounting = true; m->default_tasks_max = UINT64_C(512); +#ifdef ENABLE_EFI + if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) + boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp); +#endif + /* 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]; + if (MANAGER_IS_SYSTEM(m)) { + m->unit_log_field = "UNIT="; + m->unit_log_format_string = "UNIT=%s"; + } else { + m->unit_log_field = "USER_UNIT="; + m->unit_log_format_string = "USER_UNIT=%s"; + } m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; @@ -694,7 +687,7 @@ static int manager_setup_notify(Manager *m) { fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE); - if (m->running_as == MANAGER_SYSTEM) + if (MANAGER_IS_SYSTEM(m)) m->notify_socket = strdup("/run/systemd/notify"); else { const char *e; @@ -756,8 +749,8 @@ static int manager_setup_kdbus(Manager *m) { return -ESOCKTNOSUPPORT; m->kdbus_fd = bus_kernel_create_bus( - m->running_as == MANAGER_SYSTEM ? "system" : "user", - m->running_as == MANAGER_SYSTEM, &p); + MANAGER_IS_SYSTEM(m) ? "system" : "user", + MANAGER_IS_SYSTEM(m), &p); if (m->kdbus_fd < 0) return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m"); @@ -778,7 +771,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) { try_bus_connect = m->kdbus_fd >= 0 || reexecuting || - (m->running_as == MANAGER_USER && getenv("DBUS_SESSION_BUS_ADDRESS")); + (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS")); /* Try to connect to the buses, if possible. */ return bus_init(m, try_bus_connect); @@ -1116,7 +1109,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { assert(m); - r = lookup_paths_init(&m->lookup_paths, m->running_as, true, NULL); + r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, NULL); if (r < 0) return r; @@ -1739,7 +1732,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 == MANAGER_USER) + (sfsi.ssi_signo == SIGTERM && MANAGER_IS_USER(m)) ? LOG_DEBUG : LOG_INFO, &sfsi); @@ -1750,7 +1743,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t break; case SIGTERM: - if (m->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(m)) { /* This is for compatibility with the * original sysvinit */ m->exit_code = MANAGER_REEXECUTE; @@ -1760,7 +1753,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t /* Fall through */ case SIGINT: - if (m->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(m)) { /* If the user presses C-A-D more than * 7 times within 2s, we reboot @@ -1786,14 +1779,14 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t break; case SIGWINCH: - if (m->running_as == MANAGER_SYSTEM) + if (MANAGER_IS_SYSTEM(m)) manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE); /* This is a nop on non-init */ break; case SIGPWR: - if (m->running_as == MANAGER_SYSTEM) + if (MANAGER_IS_SYSTEM(m)) manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE); /* This is a nop on non-init */ @@ -1901,7 +1894,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t break; case 24: - if (m->running_as == MANAGER_USER) { + if (MANAGER_IS_USER(m)) { m->exit_code = MANAGER_EXIT; return 0; } @@ -2017,7 +2010,7 @@ int manager_loop(Manager *m) { while (m->exit_code == MANAGER_OK) { usec_t wait_usec; - if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) + if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m)) watchdog_ping(); if (!ratelimit_test(&rl)) { @@ -2042,7 +2035,7 @@ int manager_loop(Manager *m) { continue; /* Sleep for half the watchdog time */ - if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) { + if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m)) { wait_usec = m->runtime_watchdog / 2; if (wait_usec <= 0) wait_usec = 1; @@ -2113,7 +2106,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { const char *msg; int audit_fd, r; - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return; audit_fd = get_audit_fd(); @@ -2159,7 +2152,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { if (m->n_reloading > 0) return; - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return; if (detect_container() > 0) @@ -2203,7 +2196,7 @@ int manager_open_serialization(Manager *m, FILE **_f) { assert(_f); - path = m->running_as == MANAGER_SYSTEM ? "/run/systemd" : "/tmp"; + path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp"; fd = open_tmpfile(path, O_RDWR|O_CLOEXEC); if (fd < 0) return -errno; @@ -2537,7 +2530,7 @@ int manager_reload(Manager *m) { manager_undo_generators(m); lookup_paths_free(&m->lookup_paths); - q = lookup_paths_init(&m->lookup_paths, m->running_as, true, NULL); + q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, NULL); if (q < 0 && r >= 0) r = q; @@ -2616,7 +2609,7 @@ static void manager_notify_finished(Manager *m) { if (m->test_run) return; - if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0) { + if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) { /* Note that m->kernel_usec.monotonic is always at 0, * and m->firmware_usec.monotonic and @@ -2733,7 +2726,7 @@ static int manager_run_generators(Manager *m) { if (m->test_run) return 0; - paths = generator_paths(m->running_as); + paths = generator_paths(m->unit_file_scope); if (!paths) return log_oom(); @@ -2851,7 +2844,7 @@ void manager_recheck_journal(Manager *m) { assert(m); - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return; u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET); @@ -2875,7 +2868,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 != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return; if (m->show_status != mode) @@ -2892,7 +2885,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 != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return false; if (m->no_console_output) @@ -2914,7 +2907,7 @@ static bool manager_get_show_status(Manager *m, StatusType type) { void manager_set_first_boot(Manager *m, bool b) { assert(m); - if (m->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(m)) return; if (m->first_boot != (int) b) { @@ -2960,7 +2953,7 @@ 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 == MANAGER_SYSTEM ? + return MANAGER_IS_SYSTEM(m) ? "/run" : getenv("XDG_RUNTIME_DIR"); } diff --git a/src/core/manager.h b/src/core/manager.h index 5471bd7a0d..19eab958ea 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -140,6 +140,7 @@ struct Manager { sd_event_source *jobs_in_progress_event_source; + UnitFileScope unit_file_scope; LookupPaths lookup_paths; Set *unit_path_cache; @@ -224,7 +225,6 @@ struct Manager { unsigned n_in_gc_queue; /* Flags */ - ManagerRunningAs running_as; ManagerExitCode exit_code:5; bool dispatching_load_queue:1; @@ -300,10 +300,13 @@ struct Manager { const char *unit_log_field; const char *unit_log_format_string; - int first_boot; + int first_boot; /* tri-state */ }; -int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m); +#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM) +#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM) + +int manager_new(UnitFileScope scope, bool test_run, Manager **m); Manager* manager_free(Manager *m); void manager_enumerate(Manager *m); diff --git a/src/core/mount.c b/src/core/mount.c index 0fd880df5d..74ab54bfd0 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -336,8 +336,7 @@ static int mount_add_device_links(Mount *m) { if (path_equal(m->where, "/")) return 0; - if (mount_is_auto(p) && !mount_is_automount(p) && - UNIT(m)->manager->running_as == MANAGER_SYSTEM) + if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager)) device_wants_mount = true; r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES); @@ -353,7 +352,7 @@ static int mount_add_quota_links(Mount *m) { assert(m); - if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(UNIT(m)->manager)) return 0; p = get_mount_parameters_fragment(m); @@ -400,7 +399,7 @@ static int mount_add_default_dependencies(Mount *m) { if (!UNIT(m)->default_dependencies) return 0; - if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(UNIT(m)->manager)) return 0; /* We do not add any default dependencies to /, /usr or @@ -1396,7 +1395,7 @@ static int mount_setup_unit( goto fail; } - if (m->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(m)) { const char* target; target = mount_needs_network(options, fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET; @@ -1424,7 +1423,7 @@ static int mount_setup_unit( } } - if (m->running_as == MANAGER_SYSTEM && + if (MANAGER_IS_SYSTEM(m) && mount_needs_network(options, fstype)) { /* _netdev option may have shown up late, or on a * remount. Add remote-fs dependencies, even though diff --git a/src/core/path.c b/src/core/path.c index 426c4ad299..5e7b3eb234 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -318,7 +318,7 @@ static int path_add_default_dependencies(Path *p) { if (r < 0) return r; - if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) { r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); if (r < 0) return r; diff --git a/src/core/service.c b/src/core/service.c index c5cbf0f152..7aea6f7ff4 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -523,7 +523,7 @@ static int service_add_default_dependencies(Service *s) { /* Add a number of automatic dependencies useful for the * majority of services. */ - if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) { /* First, pull in the really early boot stuff, and * require it, so that we fail if we can't acquire * it. */ @@ -1211,7 +1211,7 @@ static int service_spawn( if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) return -ENOMEM; - if (UNIT(s)->manager->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(UNIT(s)->manager)) if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) return -ENOMEM; diff --git a/src/core/socket.c b/src/core/socket.c index dd515a17a5..65da0e3c5e 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -301,7 +301,7 @@ static int socket_add_default_dependencies(Socket *s) { if (r < 0) return r; - if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) { r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); if (r < 0) return r; diff --git a/src/core/swap.c b/src/core/swap.c index 11506d9ecb..c6502eb821 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -198,7 +198,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 == MANAGER_SYSTEM, UNIT_BINDS_TO); + return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO); else /* File based swap devices need to be ordered after * systemd-remount-fs.service, since they might need a @@ -214,7 +214,7 @@ static int swap_add_default_dependencies(Swap *s) { if (!UNIT(s)->default_dependencies) return 0; - if (UNIT(s)->manager->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(UNIT(s)->manager)) return 0; if (detect_container() > 0) diff --git a/src/core/timer.c b/src/core/timer.c index 3d0bae16e5..a51a67ea11 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -109,7 +109,7 @@ static int timer_add_default_dependencies(Timer *t) { if (r < 0) return r; - if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) { r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); if (r < 0) return r; @@ -135,7 +135,7 @@ static int timer_setup_persistent(Timer *t) { if (!t->persistent) return 0; - if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) { + if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) { r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers"); if (r < 0) diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index fc057d965c..40da52fcac 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -140,7 +140,7 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char ** assert(u); - if (u->manager->running_as == MANAGER_SYSTEM) + if (MANAGER_IS_SYSTEM(u->manager)) e = "/run"; else { e = getenv("XDG_RUNTIME_DIR"); diff --git a/src/core/unit.c b/src/core/unit.c index 70175557f7..fbc2b0d74d 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -814,7 +814,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { return r; } - if (u->manager->running_as != MANAGER_SYSTEM) + if (!MANAGER_IS_SYSTEM(u->manager)) return 0; if (c->private_tmp) { @@ -2413,7 +2413,7 @@ int unit_set_default_slice(Unit *u) { if (!escaped) return -ENOMEM; - if (u->manager->running_as == MANAGER_SYSTEM) + if (MANAGER_IS_SYSTEM(u->manager)) b = strjoin("system-", escaped, ".slice", NULL); else b = strappend(escaped, ".slice"); @@ -2423,7 +2423,7 @@ int unit_set_default_slice(Unit *u) { slice_name = b; } else slice_name = - u->manager->running_as == MANAGER_SYSTEM && !unit_has_name(u, SPECIAL_INIT_SCOPE) + MANAGER_IS_SYSTEM(u->manager) && !unit_has_name(u, SPECIAL_INIT_SCOPE) ? SPECIAL_SYSTEM_SLICE : SPECIAL_ROOT_SLICE; @@ -2884,7 +2884,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep return r; r = unit_add_two_dependencies(u, UNIT_AFTER, - u->manager->running_as == MANAGER_SYSTEM ? dep : UNIT_WANTS, + MANAGER_IS_SYSTEM(u->manager) ? dep : UNIT_WANTS, device, true); if (r < 0) return r; @@ -3158,7 +3158,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) { if (u->unit_file_state < 0 && u->fragment_path) { r = unit_file_get_state( - u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, + u->manager->unit_file_scope, NULL, basename(u->fragment_path), &u->unit_file_state); @@ -3174,7 +3174,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 == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, + u->manager->unit_file_scope, NULL, basename(u->fragment_path)); @@ -3225,7 +3225,7 @@ int unit_patch_contexts(Unit *u) { return -ENOMEM; } - if (u->manager->running_as == MANAGER_USER && + if (MANAGER_IS_USER(u->manager) && !ec->working_directory) { r = get_home_dir(&ec->working_directory); @@ -3237,7 +3237,7 @@ int unit_patch_contexts(Unit *u) { ec->working_directory_missing_ok = true; } - if (u->manager->running_as == MANAGER_USER && + if (MANAGER_IS_USER(u->manager) && (ec->syscall_whitelist || !set_isempty(ec->syscall_filter) || !set_isempty(ec->syscall_archs) || @@ -3318,7 +3318,7 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) { static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) { assert(u); - if (u->manager->running_as == MANAGER_USER) { + if (MANAGER_IS_USER(u->manager)) { int r; if (mode == UNIT_PERSISTENT && !transient) diff --git a/src/shared/install.c b/src/shared/install.c index 2cec6ba76f..f802343399 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1442,7 +1442,7 @@ int unit_file_mask( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1493,7 +1493,7 @@ int unit_file_unmask( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1575,7 +1575,7 @@ int unit_file_link( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1668,7 +1668,7 @@ int unit_file_add_dependency( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1738,7 +1738,7 @@ int unit_file_enable( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1786,7 +1786,7 @@ int unit_file_disable( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1863,7 +1863,7 @@ int unit_file_set_default( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1899,7 +1899,7 @@ int unit_file_get_default( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -2001,7 +2001,7 @@ int unit_file_get_state( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -2203,7 +2203,7 @@ int unit_file_preset( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -2244,7 +2244,7 @@ int unit_file_preset_all( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -2322,7 +2322,7 @@ int unit_file_get_list( if (r < 0) return r; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 5766053cef..cfe62c6438 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -102,7 +102,7 @@ static int user_data_home_dir(char **dir, const char *suffix) { return -ENOMEM; *dir = res; - return 0; + return 1; } static char** user_dirs( @@ -223,23 +223,32 @@ static char** user_dirs( return tmp; } -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", - USER_GENERATOR_PATH, - NULL); - else +char **generator_paths(UnitFileScope scope) { + + switch (scope) { + + case UNIT_FILE_SYSTEM: return strv_new("/run/systemd/system-generators", "/etc/systemd/system-generators", "/usr/local/lib/systemd/system-generators", SYSTEM_GENERATOR_PATH, NULL); + + case UNIT_FILE_GLOBAL: + case UNIT_FILE_USER: + return strv_new("/run/systemd/user-generators", + "/etc/systemd/user-generators", + "/usr/local/lib/systemd/user-generators", + USER_GENERATOR_PATH, + NULL); + + default: + assert_not_reached("Hmm, unexpected scope."); + } } static int acquire_generator_dirs( - ManagerRunningAs running_as, + UnitFileScope scope, char **generator, char **generator_early, char **generator_late) { @@ -251,18 +260,28 @@ static int acquire_generator_dirs( assert(generator_early); assert(generator_late); - if (running_as == MANAGER_SYSTEM) + switch (scope) { + + case UNIT_FILE_SYSTEM: prefix = "/run/systemd/"; - else { - const char *e; + break; - assert(running_as == MANAGER_USER); + case UNIT_FILE_USER: { + const char *e; e = getenv("XDG_RUNTIME_DIR"); if (!e) - return -EINVAL; + return -ENXIO; prefix = strjoina(e, "/systemd/", NULL); + break; + } + + case UNIT_FILE_GLOBAL: + return -EOPNOTSUPP; + + default: + assert_not_reached("Hmm, unexpected scope value."); } x = strappend(prefix, "generator"); @@ -285,19 +304,26 @@ static int acquire_generator_dirs( return 0; } -static int acquire_config_dirs(ManagerRunningAs running_as, bool personal, char **persistent, char **runtime) { +static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) { _cleanup_free_ char *a = NULL, *b = NULL; int r; assert(persistent); assert(runtime); - if (running_as == MANAGER_SYSTEM) { + switch (scope) { + + case UNIT_FILE_SYSTEM: a = strdup(SYSTEM_CONFIG_UNIT_PATH); b = strdup("/run/systemd/system"); - } else if (personal) { - assert(running_as == MANAGER_USER); + break; + + case UNIT_FILE_GLOBAL: + a = strdup(USER_CONFIG_UNIT_PATH); + b = strdup("/run/systemd/user"); + break; + case UNIT_FILE_USER: r = user_config_home(&a); if (r < 0) return r; @@ -310,11 +336,9 @@ static int acquire_config_dirs(ManagerRunningAs running_as, bool personal, char a = NULL; return 0; - } else { - assert(running_as == MANAGER_USER); - a = strdup(USER_CONFIG_UNIT_PATH); - b = strdup("/run/systemd/user"); + default: + assert_not_reached("Hmm, unexpected scope value."); } if (!a || !b) @@ -350,8 +374,7 @@ static int patch_root_prefix(char **p, const char *root_dir) { int lookup_paths_init( LookupPaths *p, - ManagerRunningAs running_as, - bool personal, + UnitFileScope scope, const char *root_dir) { _cleanup_free_ char *generator = NULL, *generator_early = NULL, *generator_late = NULL, @@ -362,15 +385,15 @@ int lookup_paths_init( int r; assert(p); - assert(running_as >= 0); - assert(running_as < _MANAGER_RUNNING_AS_MAX); + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); - r = acquire_config_dirs(running_as, personal, &persistent_config, &runtime_config); + r = acquire_config_dirs(scope, &persistent_config, &runtime_config); if (r < 0) return r; - r = acquire_generator_dirs(running_as, &generator, &generator_early, &generator_late); - if (r < 0) + r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late); + if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) return r; /* First priority is whatever has been passed to us via env @@ -405,46 +428,56 @@ int lookup_paths_init( * we include /lib in the search path for the system * stuff but avoid it for user stuff. */ - if (running_as == MANAGER_USER) { - if (personal) - add = user_dirs(persistent_config, runtime_config, - generator, generator_early, generator_late); - else - add = strv_new( + switch (scope) { + + case UNIT_FILE_SYSTEM: + add = strv_new( + /* If you modify this you also want to modify + * systemdsystemunitpath= in systemd.pc.in! */ + STRV_IFNOTNULL(generator_early), + persistent_config, + "/etc/systemd/system", + runtime_config, + "/run/systemd/system", + STRV_IFNOTNULL(generator), + "/usr/local/lib/systemd/system", + SYSTEM_DATA_UNIT_PATH, + "/usr/lib/systemd/system", +#ifdef HAVE_SPLIT_USR + "/lib/systemd/system", +#endif + STRV_IFNOTNULL(generator_late), + NULL); + break; + + case UNIT_FILE_GLOBAL: + add = strv_new( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and * the arrays in user_dirs() above! */ - generator_early, + STRV_IFNOTNULL(generator_early), persistent_config, "/etc/systemd/user", runtime_config, "/run/systemd/user", - generator, + STRV_IFNOTNULL(generator), "/usr/local/lib/systemd/user", "/usr/local/share/systemd/user", USER_DATA_UNIT_PATH, "/usr/lib/systemd/user", "/usr/share/systemd/user", - generator_late, + STRV_IFNOTNULL(generator_late), NULL); - } else - add = strv_new( - /* If you modify this you also want to modify - * systemdsystemunitpath= in systemd.pc.in! */ - generator_early, - persistent_config, - "/etc/systemd/system", - runtime_config, - "/run/systemd/system", - generator, - "/usr/local/lib/systemd/system", - SYSTEM_DATA_UNIT_PATH, - "/usr/lib/systemd/system", -#ifdef HAVE_SPLIT_USR - "/lib/systemd/system", -#endif - generator_late, - NULL); + break; + + case UNIT_FILE_USER: + add = user_dirs(persistent_config, runtime_config, + generator, generator_early, generator_late); + break; + + default: + assert_not_reached("Hmm, unexpected scope?"); + } if (!add) return -ENOMEM; @@ -520,19 +553,3 @@ void lookup_paths_free(LookupPaths *p) { p->generator_early = mfree(p->generator_early); p->generator_late = mfree(p->generator_late); } - -int lookup_paths_init_from_scope( - LookupPaths *p, - UnitFileScope scope, - const char *root_dir) { - - assert(p); - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - return lookup_paths_init( - p, - scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER, - scope == UNIT_FILE_USER, - root_dir); -} diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 64c8035c2b..974db79509 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -22,7 +22,6 @@ #include typedef struct LookupPaths LookupPaths; -typedef enum ManagerRunningAs ManagerRunningAs; #include "install.h" #include "macro.h" @@ -40,20 +39,12 @@ struct LookupPaths { char *generator_late; }; -enum ManagerRunningAs { - MANAGER_SYSTEM, - MANAGER_USER, - _MANAGER_RUNNING_AS_MAX, - _MANAGER_RUNNING_AS_INVALID = -1 -}; - int user_config_home(char **config_home); int user_runtime_dir(char **runtime_dir); -char **generator_paths(ManagerRunningAs running_as); +char **generator_paths(UnitFileScope scope); -int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal, const char *root_dir); -int lookup_paths_init_from_scope(LookupPaths *p, UnitFileScope scope, const char *root_dir); +int lookup_paths_init(LookupPaths *p, 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/systemctl/systemctl.c b/src/systemctl/systemctl.c index bab34986e3..3fd44a01d4 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4810,7 +4810,7 @@ static int cat(int argc, char *argv[], void *userdata) { return -EINVAL; } - r = lookup_paths_init_from_scope(&lp, arg_scope, arg_root); + r = lookup_paths_init(&lp, arg_scope, arg_root); if (r < 0) return log_error_errno(r, "Failed to determine unit paths: %m"); @@ -5241,7 +5241,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, MANAGER_SYSTEM, false, arg_root); + r = lookup_paths_init(&paths, arg_scope, arg_root); if (r < 0) return r; @@ -6074,7 +6074,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { assert(names); assert(paths); - r = lookup_paths_init_from_scope(&lp, arg_scope, arg_root); + r = lookup_paths_init(&lp, arg_scope, arg_root); if (r < 0) return r; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index b82c877dc7..3f5f24b4b9 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -1004,7 +1004,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL); + r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, NULL); if (r < 0) { log_error_errno(r, "Failed to find lookup paths: %m"); goto finish; diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index ad15075a5b..332755cf41 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -33,7 +33,7 @@ static int test_cgroup_mask(void) { /* Prepare the manager. */ assert_se(set_unit_path(TEST_DIR) >= 0); - r = manager_new(MANAGER_USER, true, &m); + r = manager_new(UNIT_FILE_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-engine.c b/src/test/test-engine.c index ca66f5b684..52b34c03df 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) { /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); - r = manager_new(MANAGER_USER, true, &m); + r = manager_new(UNIT_FILE_USER, true, &m); if (MANAGER_SKIP_TEST(r)) { printf("Skipping test: manager_new: %s\n", strerror(-r)); return EXIT_TEST_SKIP; diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 901cc44af6..77ef4e8b2a 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -291,14 +291,14 @@ static void test_exec_spec_interpolation(Manager *m) { test(m, "exec-spec-interpolation.service", 0, CLD_EXITED); } -static int run_tests(ManagerRunningAs running_as, test_function_t *tests) { +static int run_tests(UnitFileScope scope, test_function_t *tests) { test_function_t *test = NULL; Manager *m = NULL; int r; assert_se(tests); - r = manager_new(running_as, true, &m); + r = manager_new(scope, true, &m); if (MANAGER_SKIP_TEST(r)) { printf("Skipping test: manager_new: %s\n", strerror(-r)); return EXIT_TEST_SKIP; @@ -366,9 +366,9 @@ int main(int argc, char *argv[]) { assert_se(unsetenv("VAR2") == 0); assert_se(unsetenv("VAR3") == 0); - r = run_tests(MANAGER_USER, user_tests); + r = run_tests(UNIT_FILE_USER, user_tests); if (r != 0) return r; - return run_tests(MANAGER_SYSTEM, system_tests); + return run_tests(UNIT_FILE_SYSTEM, system_tests); } diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index ebb11dcb6d..5575a364f2 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -26,7 +26,7 @@ #include "string-util.h" #include "strv.h" -static void test_paths(ManagerRunningAs running_as, bool personal) { +static void test_paths(UnitFileScope scope) { char template[] = "/tmp/test-path-lookup.XXXXXXX"; _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {}; @@ -36,26 +36,26 @@ static void test_paths(ManagerRunningAs running_as, bool personal) { assert_se(mkdtemp(template)); assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); - assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL) == 0); + assert_se(lookup_paths_init(&lp_without_env, scope, NULL) == 0); assert_se(!strv_isempty(lp_without_env.search_path)); systemd_unit_path = strjoina(template, "/systemd-unit-path"); assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); - assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL) == 0); + assert_se(lookup_paths_init(&lp_with_env, scope, NULL) == 0); assert_se(strv_length(lp_with_env.search_path) == 1); assert_se(streq(lp_with_env.search_path[0], systemd_unit_path)); assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -static void print_generator_paths(ManagerRunningAs running_as) { +static void print_generator_paths(UnitFileScope scope) { _cleanup_strv_free_ char **paths; char **dir; - log_info("Generators dirs (%s):", running_as == MANAGER_SYSTEM ? "system" : "user"); + log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); - paths = generator_paths(running_as); + paths = generator_paths(scope); STRV_FOREACH(dir, paths) log_info(" %s", *dir); } @@ -65,13 +65,12 @@ int main(int argc, char **argv) { log_parse_environment(); log_open(); - test_paths(MANAGER_SYSTEM, false); - test_paths(MANAGER_SYSTEM, true); - test_paths(MANAGER_USER, false); - test_paths(MANAGER_USER, true); + test_paths(UNIT_FILE_SYSTEM); + test_paths(UNIT_FILE_USER); + test_paths(UNIT_FILE_GLOBAL); - print_generator_paths(MANAGER_SYSTEM); - print_generator_paths(MANAGER_USER); + print_generator_paths(UNIT_FILE_SYSTEM); + print_generator_paths(UNIT_FILE_USER); return EXIT_SUCCESS; } diff --git a/src/test/test-path.c b/src/test/test-path.c index 1e704a03dc..e0c8db50ae 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -44,7 +44,7 @@ static int setup_test(Manager **m) { assert_se(m); - r = manager_new(MANAGER_USER, true, &tmp); + r = manager_new(UNIT_FILE_USER, true, &tmp); if (MANAGER_SKIP_TEST(r)) { printf("Skipping test: manager_new: %s\n", strerror(-r)); return -EXIT_TEST_SKIP; diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index 7f515b53d8..5083cd53c2 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) { /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); - r = manager_new(MANAGER_USER, true, &m); + r = manager_new(UNIT_FILE_USER, true, &m); if (MANAGER_SKIP_TEST(r)) { printf("Skipping test: manager_new: %s\n", strerror(-r)); return EXIT_TEST_SKIP; diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index cc6c61ba63..7f2fee772b 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -113,7 +113,7 @@ static void test_config_parse_exec(void) { Manager *m = NULL; Unit *u = NULL; - r = manager_new(MANAGER_USER, true, &m); + r = manager_new(UNIT_FILE_USER, true, &m); if (MANAGER_SKIP_TEST(r)) { printf("Skipping test: manager_new: %s\n", strerror(-r)); return; diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 3de94ef425..2fd83f321c 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -209,7 +209,7 @@ static int test_unit_printf(void) { assert_se(get_home_dir(&home) >= 0); assert_se(get_shell(&shell) >= 0); - r = manager_new(MANAGER_USER, true, &m); + r = manager_new(UNIT_FILE_USER, true, &m); if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) { puts("manager_new: Permission denied. Skipping test."); return EXIT_TEST_SKIP; -- cgit v1.2.3-54-g00ecf From 2c289ea8332a2c0777d8940058ff7a6293f59b6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 21:36:09 +0100 Subject: core: introduce MANAGER_IS_RELOADING() macro This replaces the old function call manager_is_reloading_or_reexecuting() which was used only at very few places. Use the new macro wherever we check whether we are reloading. This should hopefully make things a bit more readable, given the nature of Manager:n_reloading being a counter. --- src/core/job.c | 2 +- src/core/manager.c | 12 +++--------- src/core/manager.h | 4 ++-- src/core/scope.c | 6 +++--- src/core/service.c | 2 +- src/core/transaction.c | 2 +- src/core/unit.c | 12 ++++++------ 7 files changed, 17 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/core/job.c b/src/core/job.c index 2e30431163..d9c5669c9f 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -137,7 +137,7 @@ void job_uninstall(Job *j) { /* Detach from next 'bigger' objects */ /* daemon-reload should be transparent to job observers */ - if (j->manager->n_reloading <= 0) + if (!MANAGER_IS_RELOADING(j->manager)) bus_job_send_removed_signal(j); *pj = NULL; diff --git a/src/core/manager.c b/src/core/manager.c index 1412d6718a..b3c3445f2c 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2115,7 +2115,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { /* Don't generate audit events if the service was already * started and we're just deserializing */ - if (m->n_reloading > 0) + if (MANAGER_IS_RELOADING(m)) return; if (u->type != UNIT_SERVICE) @@ -2149,7 +2149,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { /* Don't generate plymouth events if the service was already * started and we're just deserializing */ - if (m->n_reloading > 0) + if (MANAGER_IS_RELOADING(m)) return; if (!MANAGER_IS_SYSTEM(m)) @@ -2572,12 +2572,6 @@ int manager_reload(Manager *m) { return r; } -bool manager_is_reloading_or_reexecuting(Manager *m) { - assert(m); - - return m->n_reloading != 0; -} - void manager_reset_failed(Manager *m) { Unit *u; Iterator i; @@ -2674,7 +2668,7 @@ static void manager_notify_finished(Manager *m) { void manager_check_finished(Manager *m) { assert(m); - if (m->n_reloading > 0) + if (MANAGER_IS_RELOADING(m)) return; /* Verify that we are actually running currently. Initially diff --git a/src/core/manager.h b/src/core/manager.h index 19eab958ea..17f84e6963 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -306,6 +306,8 @@ struct Manager { #define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM) #define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM) +#define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0) + int manager_new(UnitFileScope scope, bool test_run, Manager **m); Manager* manager_free(Manager *m); @@ -344,8 +346,6 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds); int manager_reload(Manager *m); -bool manager_is_reloading_or_reexecuting(Manager *m) _pure_; - void manager_reset_failed(Manager *m); void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success); diff --git a/src/core/scope.c b/src/core/scope.c index 361695c3f9..92a3aed331 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -138,7 +138,7 @@ static int scope_verify(Scope *s) { return 0; if (set_isempty(UNIT(s)->pids) && - !manager_is_reloading_or_reexecuting(UNIT(s)->manager) && + !MANAGER_IS_RELOADING(UNIT(s)->manager) && !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) { log_unit_error(UNIT(s), "Scope has no PIDs. Refusing."); return -EINVAL; @@ -154,7 +154,7 @@ static int scope_load(Unit *u) { assert(s); assert(u->load_state == UNIT_STUB); - if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager)) + if (!u->transient && !MANAGER_IS_RELOADING(u->manager)) return -ENOENT; u->load_state = UNIT_LOADED; @@ -292,7 +292,7 @@ static int scope_start(Unit *u) { assert(s->state == SCOPE_DEAD); - if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager)) + if (!u->transient && !MANAGER_IS_RELOADING(u->manager)) return -ENOENT; (void) unit_realize_cgroup(u); diff --git a/src/core/service.c b/src/core/service.c index 7aea6f7ff4..58084e2f82 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -920,7 +920,7 @@ static void service_set_state(Service *s, ServiceState state) { /* For the inactive states unit_notify() will trim the cgroup, * but for exit we have to do that ourselves... */ - if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0) + if (state == SERVICE_EXITED && !MANAGER_IS_RELOADING(UNIT(s)->manager)) unit_prune_cgroup(UNIT(s)); /* For remain_after_exit services, let's see if we can "release" the diff --git a/src/core/transaction.c b/src/core/transaction.c index c894001cf9..dad387749c 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -855,7 +855,7 @@ int transaction_add_job_and_dependencies( * 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) + if (MANAGER_IS_RELOADING(unit->manager)) unit_coldplug(unit); /* log_debug("Pulling in %s/%s from %s/%s", */ diff --git a/src/core/unit.c b/src/core/unit.c index fbc2b0d74d..565704851b 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -483,7 +483,7 @@ void unit_free(Unit *u) { assert(u); - if (u->manager->n_reloading <= 0) + if (!MANAGER_IS_RELOADING(u->manager)) unit_remove_transient(u); bus_unit_send_removed_signal(u); @@ -1834,7 +1834,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su m = u->manager; /* Update timestamps for state changes */ - if (m->n_reloading <= 0) { + if (!MANAGER_IS_RELOADING(m)) { dual_timestamp_get(&u->state_change_timestamp); if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns)) @@ -1941,7 +1941,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su } else unexpected = true; - if (m->n_reloading <= 0) { + if (!MANAGER_IS_RELOADING(m)) { /* If this state change happened without being * requested by a job, then let's retroactively start @@ -1978,7 +1978,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (u->type == UNIT_SERVICE && !UNIT_IS_ACTIVE_OR_RELOADING(os) && - m->n_reloading <= 0) { + !MANAGER_IS_RELOADING(m)) { /* Write audit record if we have just finished starting up */ manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true); u->in_audit = true; @@ -1995,7 +1995,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (u->type == UNIT_SERVICE && UNIT_IS_INACTIVE_OR_FAILED(ns) && !UNIT_IS_INACTIVE_OR_FAILED(os) && - m->n_reloading <= 0) { + !MANAGER_IS_RELOADING(m)) { /* Hmm, if there was no start record written * write it now, so that we always have a nice @@ -2016,7 +2016,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su manager_recheck_journal(m); unit_trigger_notify(u); - if (u->manager->n_reloading <= 0) { + if (!MANAGER_IS_RELOADING(u->manager)) { /* Maybe we finished startup and are now ready for * being stopped because unneeded? */ unit_check_unneeded(u); -- cgit v1.2.3-54-g00ecf From 21b3926840b22c738a5e575f089485732e1cbd28 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 21:37:42 +0100 Subject: network: hashmap_put() can fail Let's properly handle hashmap_put() failing. --- src/network/networkd-route.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index e065a5a5a9..ab9b777d9a 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -52,8 +52,7 @@ int route_new_static(Network *network, unsigned section, Route **ret) { int r; if (section) { - route = hashmap_get(network->routes_by_section, - UINT_TO_PTR(section)); + route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section)); if (route) { *ret = route; route = NULL; @@ -67,16 +66,18 @@ int route_new_static(Network *network, unsigned section, Route **ret) { return r; route->protocol = RTPROT_STATIC; - route->network = network; - - LIST_PREPEND(routes, network->static_routes, route); if (section) { + r = hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route); + if (r < 0) + return r; + route->section = section; - hashmap_put(network->routes_by_section, - UINT_TO_PTR(route->section), route); } + LIST_PREPEND(routes, network->static_routes, route); + route->network = network; + *ret = route; route = NULL; -- cgit v1.2.3-54-g00ecf From 385eb996344f3b2a9223b66e83b853c844c02947 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 21:43:09 +0100 Subject: install: be more accurate when checking whether something is runtime configuration Let's actually check the runtime config dir, instead of just /run. --- src/shared/install.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index f802343399..59582e573d 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -118,6 +118,22 @@ static int path_is_config(const LookupPaths *p, const char *path) { path_equal(parent, p->runtime_config); } +static int path_is_runtime(const LookupPaths *p, const char *path) { + _cleanup_free_ char *parent = NULL; + + assert(p); + assert(path); + + if (path_startswith(path, "/run")) + return true; + + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; + + return path_equal(parent, p->runtime_config); +} + static int verify_root_dir(UnitFileScope scope, const char **root_dir) { int r; @@ -1950,7 +1966,11 @@ int unit_file_lookup_state( switch (i->type) { case UNIT_FILE_TYPE_MASKED: - state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; + r = path_is_runtime(paths, i->path); + if (r < 0) + return r; + + state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; break; case UNIT_FILE_TYPE_REGULAR: -- cgit v1.2.3-54-g00ecf From f4dc1e65e39336453e842f79ecd5cf7e5af34458 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 21:45:19 +0100 Subject: install: rename unit_file_is_generated() → path_is_generator() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way the funciton name matches nicely our other calls path_is_config() and path_is_runtime(). --- src/shared/install.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 59582e573d..e0846c9fbf 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -82,7 +82,7 @@ static int in_search_path(const char *path, char **search) { return false; } -static int unit_file_is_generated(const LookupPaths *p, const char *path) { +static int path_is_generator(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; assert(p); @@ -1695,7 +1695,7 @@ int unit_file_add_dependency( return r; if (target_info->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; - if (unit_file_is_generated(&paths, target_info->path)) + if (path_is_generator(&paths, target_info->path)) return -EADDRNOTAVAIL; assert(target_info->type == UNIT_FILE_TYPE_REGULAR); @@ -1708,7 +1708,7 @@ int unit_file_add_dependency( return r; if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; - if (unit_file_is_generated(&paths, i->path)) + if (path_is_generator(&paths, i->path)) return -EADDRNOTAVAIL; assert(i->type == UNIT_FILE_TYPE_REGULAR); @@ -1766,7 +1766,7 @@ int unit_file_enable( return r; if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; - if (unit_file_is_generated(&paths, i->path)) + if (path_is_generator(&paths, i->path)) return -EADDRNOTAVAIL; assert(i->type == UNIT_FILE_TYPE_REGULAR); @@ -1888,7 +1888,7 @@ int unit_file_set_default( return r; if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; - if (unit_file_is_generated(&paths, i->path)) + if (path_is_generator(&paths, i->path)) return -EADDRNOTAVAIL; path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); @@ -1974,7 +1974,7 @@ int unit_file_lookup_state( break; case UNIT_FILE_TYPE_REGULAR: - r = unit_file_is_generated(paths, i->path); + r = path_is_generator(paths, i->path); if (r < 0) return r; if (r > 0) { @@ -2191,7 +2191,7 @@ static int preset_prepare_one( if (i->type == UNIT_FILE_TYPE_MASKED) return -ESHUTDOWN; - if (unit_file_is_generated(paths, i->path)) + if (path_is_generator(paths, i->path)) return -EADDRNOTAVAIL; } else r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); -- cgit v1.2.3-54-g00ecf From 32c0ed7bbb94037a50c267f25071522dc8eb3e68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 24 Feb 2016 21:47:54 +0100 Subject: install: change in_search_path() to take a LookupPaths structure Similar to the other calls that operate on the collected path data. --- src/shared/install.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index e0846c9fbf..464b0d3a40 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -65,7 +65,7 @@ typedef struct { OrderedHashmap *have_processed; } InstallContext; -static int in_search_path(const char *path, char **search) { +static int in_search_path(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; char **i; @@ -75,7 +75,7 @@ static int in_search_path(const char *path, char **search) { if (!parent) return -ENOMEM; - STRV_FOREACH(i, search) + STRV_FOREACH(i, p->search_path) if (path_equal(parent, *i)) return true; @@ -1294,7 +1294,7 @@ static int install_info_symlink_link( assert(config_path); assert(i->path); - r = in_search_path(i->path, paths->search_path); + r = in_search_path(paths, i->path); if (r != 0) return r; @@ -1622,7 +1622,7 @@ int unit_file_link( if (!S_ISREG(st.st_mode)) return -ENOTTY; - q = in_search_path(*i, paths.search_path); + q = in_search_path(&paths, *i); if (q < 0) return q; if (q > 0) -- cgit v1.2.3-54-g00ecf From e4bb56c7a946190c348a3c686af6cb35661fa5fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2016 00:16:51 +0100 Subject: install: add root directory to LookupPaths structure We use the root directory parameter while putting together the LookupPaths structure, hence let's also store it in the structure as-is. That way we can drop a parameter from half of the functions in install.c Also, let's move the validation of the root paths into lookup_paths_init() so that we can drop even more code from install.c --- src/shared/install.c | 169 ++++++++---------------------------- src/shared/install.h | 2 +- src/shared/path-lookup.c | 40 ++++++--- src/shared/path-lookup.h | 3 + src/sysv-generator/sysv-generator.c | 2 +- 5 files changed, 73 insertions(+), 143 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 464b0d3a40..b588457c13 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -134,32 +134,6 @@ static int path_is_runtime(const LookupPaths *p, const char *path) { return path_equal(parent, p->runtime_config); } -static int verify_root_dir(UnitFileScope scope, const char **root_dir) { - int r; - - assert(root_dir); - - /* Verifies that the specified root directory to operate on - * makes sense. Reset it to NULL if it is the root directory - * or set to empty */ - - if (isempty(*root_dir) || path_equal(*root_dir, "/")) { - *root_dir = NULL; - return 0; - } - - if (scope != UNIT_FILE_SYSTEM) - return -EINVAL; - - r = is_dir(*root_dir, true); - if (r < 0) - return r; - if (r == 0) - return -ENOTDIR; - - return 0; -} - int unit_file_changes_add( UnitFileChange **changes, unsigned *n_changes, @@ -594,7 +568,6 @@ static int find_symlinks( static int find_symlinks_in_scope( UnitFileScope scope, const LookupPaths *paths, - const char *root_dir, const char *name, UnitFileState *state) { @@ -607,7 +580,7 @@ static int find_symlinks_in_scope( assert(name); /* First look in the persistent config path */ - r = find_symlinks(root_dir, name, paths->persistent_config, &same_name_link); + r = find_symlinks(paths->root_dir, name, paths->persistent_config, &same_name_link); if (r < 0) return r; if (r > 0) { @@ -616,7 +589,7 @@ static int find_symlinks_in_scope( } /* Then look in runtime config path */ - r = find_symlinks(root_dir, name, paths->runtime_config, &same_name_link_runtime); + r = find_symlinks(paths->root_dir, name, paths->runtime_config, &same_name_link_runtime); if (r < 0) return r; if (r > 0) { @@ -982,7 +955,6 @@ static int unit_file_search( InstallContext *c, UnitFileInstallInfo *info, const LookupPaths *paths, - const char *root_dir, SearchFlags flags) { char **p; @@ -997,7 +969,7 @@ static int unit_file_search( return 0; if (info->path) - return unit_file_load_or_readlink(c, info, info->path, root_dir, flags); + return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags); assert(info->name); @@ -1008,7 +980,7 @@ static int unit_file_search( if (!path) return -ENOMEM; - r = unit_file_load_or_readlink(c, info, path, root_dir, flags); + r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags); if (r < 0) { if (r != -ENOENT) return r; @@ -1038,7 +1010,7 @@ static int unit_file_search( if (!path) return -ENOMEM; - r = unit_file_load_or_readlink(c, info, path, root_dir, flags); + r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags); if (r < 0) { if (r != -ENOENT) return r; @@ -1084,7 +1056,6 @@ static int install_info_follow( static int install_info_traverse( UnitFileScope scope, InstallContext *c, - const char *root_dir, const LookupPaths *paths, UnitFileInstallInfo *start, SearchFlags flags, @@ -1098,7 +1069,7 @@ static int install_info_traverse( assert(start); assert(c); - r = unit_file_search(c, start, paths, root_dir, flags); + r = unit_file_search(c, start, paths, flags); if (r < 0) return r; @@ -1117,7 +1088,7 @@ static int install_info_traverse( return -ELOOP; } - r = install_info_follow(c, i, root_dir, flags); + r = install_info_follow(c, i, paths->root_dir, flags); if (r < 0) { _cleanup_free_ char *buffer = NULL; const char *bn; @@ -1151,7 +1122,7 @@ static int install_info_traverse( if (r < 0) return r; - r = unit_file_search(c, i, paths, root_dir, flags); + r = unit_file_search(c, i, paths, flags); if (r < 0) return r; } @@ -1168,7 +1139,6 @@ static int install_info_traverse( static int install_info_discover( UnitFileScope scope, InstallContext *c, - const char *root_dir, const LookupPaths *paths, const char *name, SearchFlags flags, @@ -1185,7 +1155,7 @@ static int install_info_discover( if (r < 0) return r; - return install_info_traverse(scope, c, root_dir, paths, i, flags, ret); + return install_info_traverse(scope, c, paths, i, flags, ret); } static int install_info_symlink_alias( @@ -1281,7 +1251,6 @@ static int install_info_symlink_link( UnitFileInstallInfo *i, const LookupPaths *paths, const char *config_path, - const char *root_dir, bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1309,7 +1278,6 @@ static int install_info_apply( UnitFileInstallInfo *i, const LookupPaths *paths, const char *config_path, - const char *root_dir, bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1333,7 +1301,7 @@ static int install_info_apply( if (r == 0) r = q; - q = install_info_symlink_link(i, paths, config_path, root_dir, force, changes, n_changes); + q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes); if (r == 0) r = q; @@ -1345,7 +1313,6 @@ static int install_context_apply( InstallContext *c, const LookupPaths *paths, const char *config_path, - const char *root_dir, bool force, SearchFlags flags, UnitFileChange **changes, @@ -1373,14 +1340,14 @@ static int install_context_apply( if (q < 0) return q; - r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL); + r = install_info_traverse(scope, c, paths, i, flags, NULL); if (r < 0) return r; if (i->type != UNIT_FILE_TYPE_REGULAR) continue; - q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes); + q = install_info_apply(i, paths, config_path, force, changes, n_changes); if (r >= 0) { if (q < 0) r = q; @@ -1397,8 +1364,7 @@ static int install_context_mark_for_removal( InstallContext *c, const LookupPaths *paths, Set **remove_symlinks_to, - const char *config_path, - const char *root_dir) { + const char *config_path) { UnitFileInstallInfo *i; int r; @@ -1422,7 +1388,7 @@ static int install_context_mark_for_removal( if (r < 0) return r; - r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); + r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); if (r < 0) return r; @@ -1454,10 +1420,6 @@ int unit_file_mask( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1505,10 +1467,6 @@ int unit_file_unmask( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1587,10 +1545,6 @@ int unit_file_link( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1609,7 +1563,7 @@ int unit_file_link( if (!unit_name_is_valid(fn, UNIT_NAME_ANY)) return -EINVAL; - full = prefix_root(root_dir, *i); + full = prefix_root(paths.root_dir, *i); if (!full) return -ENOMEM; @@ -1680,17 +1634,13 @@ int unit_file_add_dependency( if (!unit_name_is_valid(target, UNIT_NAME_ANY)) return -EINVAL; - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; config_path = runtime ? paths.runtime_config : paths.persistent_config; - r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); + r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); if (r < 0) return r; if (target_info->type == UNIT_FILE_TYPE_MASKED) @@ -1703,7 +1653,7 @@ int unit_file_add_dependency( STRV_FOREACH(f, files) { char ***l; - r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; if (i->type == UNIT_FILE_TYPE_MASKED) @@ -1728,7 +1678,7 @@ int unit_file_add_dependency( return -ENOMEM; } - return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); } int unit_file_enable( @@ -1750,10 +1700,6 @@ int unit_file_enable( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1761,7 +1707,7 @@ int unit_file_enable( config_path = runtime ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(f, files) { - r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i); + r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i); if (r < 0) return r; if (i->type == UNIT_FILE_TYPE_MASKED) @@ -1777,7 +1723,7 @@ int unit_file_enable( is useful to determine whether the passed files had any installation data at all. */ - return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); + return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes); } int unit_file_disable( @@ -1798,10 +1744,6 @@ int unit_file_disable( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -1817,7 +1759,7 @@ int unit_file_disable( return r; } - r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir); + r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path); if (r < 0) return r; @@ -1875,15 +1817,11 @@ int unit_file_set_default( if (streq(name, SPECIAL_DEFAULT_TARGET)) return -EINVAL; - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; - r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i); + r = install_info_discover(scope, &c, &paths, name, 0, &i); if (r < 0) return r; if (i->type == UNIT_FILE_TYPE_MASKED) @@ -1911,15 +1849,11 @@ int unit_file_get_default( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; - r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; if (i->type == UNIT_FILE_TYPE_MASKED) @@ -1935,7 +1869,6 @@ int unit_file_get_default( int unit_file_lookup_state( UnitFileScope scope, - const char *root_dir, const LookupPaths *paths, const char *name, UnitFileState *ret) { @@ -1951,11 +1884,7 @@ int unit_file_lookup_state( if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - - r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; @@ -1982,7 +1911,7 @@ int unit_file_lookup_state( break; } - r = find_symlinks_in_scope(scope, paths, root_dir, i->name, &state); + r = find_symlinks_in_scope(scope, paths, i->name, &state); if (r < 0) return r; if (r == 0) { @@ -2017,15 +1946,11 @@ int unit_file_get_state( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; - return unit_file_lookup_state(scope, root_dir, &paths, name, ret); + return unit_file_lookup_state(scope, &paths, name, ret); } int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { @@ -2037,10 +1962,6 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; @@ -2123,7 +2044,6 @@ static int execute_preset( InstallContext *minus, const LookupPaths *paths, const char *config_path, - const char *root_dir, char **files, UnitFilePresetMode mode, bool force, @@ -2140,7 +2060,7 @@ static int execute_preset( if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, root_dir); + r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path); if (r < 0) return r; @@ -2152,7 +2072,7 @@ static int execute_preset( int q; /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(scope, plus, paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); + q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes); if (r >= 0) { if (q < 0) r = q; @@ -2169,7 +2089,6 @@ static int preset_prepare_one( InstallContext *plus, InstallContext *minus, LookupPaths *paths, - const char *root_dir, UnitFilePresetMode mode, const char *name) { @@ -2180,12 +2099,12 @@ static int preset_prepare_one( install_info_find(minus, name)) return 0; - r = unit_file_query_preset(scope, root_dir, name); + r = unit_file_query_preset(scope, paths->root_dir, name); if (r < 0) return r; if (r > 0) { - r = install_info_discover(scope, plus, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; @@ -2194,7 +2113,7 @@ static int preset_prepare_one( if (path_is_generator(paths, i->path)) return -EADDRNOTAVAIL; } else - r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); return r; } @@ -2219,10 +2138,6 @@ int unit_file_preset( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -2233,12 +2148,12 @@ int unit_file_preset( if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) return -EINVAL; - r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i); + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i); if (r < 0) return r; } - return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes); } int unit_file_preset_all( @@ -2260,10 +2175,6 @@ int unit_file_preset_all( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -2275,7 +2186,7 @@ int unit_file_preset_all( _cleanup_free_ char *units_dir; struct dirent *de; - units_dir = path_join(root_dir, *i, NULL); + units_dir = path_join(paths.root_dir, *i, NULL); if (!units_dir) return -ENOMEM; @@ -2297,13 +2208,13 @@ int unit_file_preset_all( if (!IN_SET(de->d_type, DT_LNK, DT_REG)) continue; - r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name); + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name); if (r < 0) return r; } } - return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes); } static void unit_file_list_free_one(UnitFileList *f) { @@ -2338,10 +2249,6 @@ int unit_file_get_list( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(h); - r = verify_root_dir(scope, &root_dir); - if (r < 0) - return r; - r = lookup_paths_init(&paths, scope, root_dir); if (r < 0) return r; @@ -2351,7 +2258,7 @@ int unit_file_get_list( _cleanup_free_ char *units_dir; struct dirent *de; - units_dir = path_join(root_dir, *i, NULL); + units_dir = path_join(paths.root_dir, *i, NULL); if (!units_dir) return -ENOMEM; @@ -2385,7 +2292,7 @@ int unit_file_get_list( if (!f->path) return -ENOMEM; - r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state); + r = unit_file_lookup_state(scope, &paths, basename(f->path), &f->state); if (r < 0) f->state = UNIT_FILE_BAD; diff --git a/src/shared/install.h b/src/shared/install.h index 18aad65d50..9c33110e44 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -136,7 +136,7 @@ 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, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_lookup_state(UnitFileScope scope, const char *root_dir, const LookupPaths *paths, const char *name, UnitFileState *ret); +int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index cfe62c6438..93dd83652f 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -28,6 +28,7 @@ #include "macro.h" #include "path-lookup.h" #include "path-util.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -359,9 +360,6 @@ static int patch_root_prefix(char **p, const char *root_dir) { if (!*p) return 0; - if (isempty(root_dir) || path_equal(root_dir, "/")) - return 0; - c = prefix_root(root_dir, *p); if (!c) return -ENOMEM; @@ -377,7 +375,9 @@ int lookup_paths_init( UnitFileScope scope, const char *root_dir) { - _cleanup_free_ char *generator = NULL, *generator_early = NULL, *generator_late = NULL, + _cleanup_free_ char + *root = NULL, + *generator = NULL, *generator_early = NULL, *generator_late = NULL, *persistent_config = NULL, *runtime_config = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ char **l = NULL; @@ -388,6 +388,21 @@ int lookup_paths_init( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); + if (!isempty(root_dir) && !path_equal(root_dir, "/")) { + if (scope == UNIT_FILE_USER) + return -EINVAL; + + r = is_dir(root_dir, true); + if (r < 0) + return r; + if (r == 0) + return -ENOTDIR; + + root = strdup(root_dir); + if (!root) + return -ENOMEM; + } + r = acquire_config_dirs(scope, &persistent_config, &runtime_config); if (r < 0) return r; @@ -492,24 +507,24 @@ int lookup_paths_init( } } - r = patch_root_prefix(&persistent_config, root_dir); + r = patch_root_prefix(&persistent_config, root); if (r < 0) return r; - r = patch_root_prefix(&runtime_config, root_dir); + r = patch_root_prefix(&runtime_config, root); if (r < 0) return r; - r = patch_root_prefix(&generator, root_dir); + r = patch_root_prefix(&generator, root); if (r < 0) return r; - r = patch_root_prefix(&generator_early, root_dir); + r = patch_root_prefix(&generator_early, root); if (r < 0) return r; - r = patch_root_prefix(&generator_late, root_dir); + r = patch_root_prefix(&generator_late, root); if (r < 0) return r; - if (!path_strv_resolve_uniq(l, root_dir)) + if (!path_strv_resolve_uniq(l, root)) return -ENOMEM; if (strv_isempty(l)) { @@ -537,6 +552,9 @@ int lookup_paths_init( p->generator_late = generator_late; generator = generator_early = generator_late = NULL; + p->root_dir = root; + root = NULL; + return 0; } @@ -552,4 +570,6 @@ void lookup_paths_free(LookupPaths *p) { p->generator = mfree(p->generator); p->generator_early = mfree(p->generator_early); p->generator_late = mfree(p->generator_late); + + p->root_dir = mfree(p->root_dir); } diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 974db79509..078c3484f5 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -37,6 +37,9 @@ struct LookupPaths { char *generator; char *generator_early; char *generator_late; + + /* The root directory prepended to all items above, or NULL */ + char *root_dir; }; int user_config_home(char **config_home); diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 3f5f24b4b9..fb7c47e1c8 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -806,7 +806,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { if (hashmap_contains(all_services, name)) continue; - r = unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name, NULL); + r = unit_file_lookup_state(UNIT_FILE_SYSTEM, lp, name, NULL); if (r < 0 && r != -ENOENT) { log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); continue; -- cgit v1.2.3-54-g00ecf From 92dd7c49659a0bb4c8e081199e4ff4351f37397a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2016 00:30:32 +0100 Subject: core: reuse manager_get_runtime_prefix() at more places --- src/core/manager.c | 19 +++++++------------ src/core/unit-printf.c | 11 +++-------- 2 files changed, 10 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index b3c3445f2c..c72b46be30 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -676,6 +676,7 @@ static int manager_setup_notify(Manager *m) { .sa.sa_family = AF_UNIX, }; static const int one = 1; + const char *e; /* First free all secondary fields */ m->notify_socket = mfree(m->notify_socket); @@ -687,19 +688,13 @@ static int manager_setup_notify(Manager *m) { fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE); - if (MANAGER_IS_SYSTEM(m)) - m->notify_socket = strdup("/run/systemd/notify"); - else { - const char *e; - - e = getenv("XDG_RUNTIME_DIR"); - if (!e) { - log_error_errno(errno, "XDG_RUNTIME_DIR is not set: %m"); - return -EINVAL; - } - - m->notify_socket = strappend(e, "/systemd/notify"); + e = manager_get_runtime_prefix(m); + if (!e) { + log_error("Failed to determine runtime prefix."); + return -EINVAL; } + + m->notify_socket = strappend(e, "/systemd/notify"); if (!m->notify_socket) return log_oom(); diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 40da52fcac..f11df42af3 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -140,14 +140,9 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char ** assert(u); - if (MANAGER_IS_SYSTEM(u->manager)) - e = "/run"; - else { - e = getenv("XDG_RUNTIME_DIR"); - if (!e) - return -EOPNOTSUPP; - } - + e = manager_get_runtime_prefix(u->manager); + if (!e) + return -EOPNOTSUPP; n = strdup(e); if (!n) return -ENOMEM; -- cgit v1.2.3-54-g00ecf From 5f0a41dade626da20000890807bc61f5d4359fb5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2016 00:54:31 +0100 Subject: path-lookup: add configured unit paths back into search path After all, for test builds they might differ from /etc/systemd/{user|system}, hence they should be included. --- src/shared/path-lookup.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 93dd83652f..11b9bb6107 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -451,6 +451,7 @@ int lookup_paths_init( * systemdsystemunitpath= in systemd.pc.in! */ STRV_IFNOTNULL(generator_early), persistent_config, + SYSTEM_CONFIG_UNIT_PATH, "/etc/systemd/system", runtime_config, "/run/systemd/system", @@ -472,6 +473,7 @@ int lookup_paths_init( * the arrays in user_dirs() above! */ STRV_IFNOTNULL(generator_early), persistent_config, + USER_CONFIG_UNIT_PATH, "/etc/systemd/user", runtime_config, "/run/systemd/user", -- cgit v1.2.3-54-g00ecf From 39591351391de3ef2fd23cc5aea5bdd6ab712db6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2016 01:13:57 +0100 Subject: core: add a separate unit directory for transient units Previously, transient units were created below the normal runtime directory /run/systemd/system. With this change they are created in a special transient directory /run/systemd/transient, which only contains data for transient units. This clarifies the life-cycle of transient units, and makes clear they are distinct from user-provided runtime units. In particular, users may now extend transient units via /run/systemd/system, without systemd interfering with the life-cycle of these files. This change also adds code so that when a transient unit exits only the drop-ins in this new directory are removed, but nothing else. Fixes: #2139 --- src/core/manager.c | 6 +++++ src/core/unit.c | 62 ++++++++++++++++++++++------------------------ src/shared/path-lookup.c | 64 +++++++++++++++++++++++++++++++++++++++++++++--- src/shared/path-lookup.h | 3 +++ 4 files changed, 99 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index c72b46be30..1bc7921abe 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -63,6 +63,7 @@ #include "manager.h" #include "missing.h" #include "mkdir.h" +#include "mkdir.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" @@ -1108,6 +1109,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { if (r < 0) return r; + /* Make sure the transient directory always exists, so that it remains in the search path */ + r = mkdir_p_label(m->lookup_paths.transient, 0755); + if (r < 0) + return r; + dual_timestamp_get(&m->generators_start_timestamp); r = manager_run_generators(m); dual_timestamp_get(&m->generators_finish_timestamp); diff --git a/src/core/unit.c b/src/core/unit.c index 565704851b..f6c9891aad 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -418,13 +418,22 @@ static void unit_remove_transient(Unit *u) { (void) unlink(u->fragment_path); STRV_FOREACH(i, u->dropin_paths) { - _cleanup_free_ char *p = NULL; + _cleanup_free_ char *p = NULL, *pp = NULL; - (void) unlink(*i); + p = dirname_malloc(*i); /* Get the drop-in directory from the drop-in file */ + if (!p) + continue; + + pp = dirname_malloc(p); /* Get the config directory from the drop-in directory */ + if (!pp) + continue; + + /* Only drop transient drop-ins */ + if (!path_equal(u->manager->lookup_paths.transient, pp)) + continue; - p = dirname_malloc(*i); - if (p) - (void) rmdir(p); + (void) unlink(*i); + (void) rmdir(p); } } @@ -3315,35 +3324,24 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) { return *(ExecRuntime**) ((uint8_t*) u + offset); } -static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) { +static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) { assert(u); - if (MANAGER_IS_USER(u->manager)) { - int r; + if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */ + return u->manager->lookup_paths.transient; - if (mode == UNIT_PERSISTENT && !transient) - r = user_config_home(dir); - else - r = user_runtime_dir(dir); - if (r == 0) - return -ENOENT; + if (mode == UNIT_RUNTIME) + return u->manager->lookup_paths.runtime_config; - return r; - } + if (mode == UNIT_PERSISTENT) + return u->manager->lookup_paths.persistent_config; - if (mode == UNIT_PERSISTENT && !transient) - *dir = strdup("/etc/systemd/system"); - else - *dir = strdup("/run/systemd/system"); - if (!*dir) - return -ENOMEM; - - return 0; + return NULL; } int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { - - _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL; + _cleanup_free_ char *p = NULL, *q = NULL; + const char *dir; int r; assert(u); @@ -3351,9 +3349,9 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) return 0; - r = unit_drop_in_dir(u, mode, u->transient, &dir); - if (r < 0) - return r; + dir = unit_drop_in_dir(u, mode); + if (!dir) + return -EINVAL; r = write_drop_in(dir, u->id, 50, name, data); if (r < 0) @@ -3398,7 +3396,7 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n } int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { - _cleanup_free_ char *ndata = NULL; + const char *ndata; assert(u); assert(name); @@ -3410,9 +3408,7 @@ int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char * if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) return 0; - ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL); - if (!ndata) - return -ENOMEM; + ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL); return unit_write_drop_in(u, mode, name, ndata); } diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 11b9bb6107..f437de370c 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -111,7 +111,8 @@ static char** user_dirs( const char *runtime_config, const char *generator, const char *generator_early, - const char *generator_late) { + const char *generator_late, + const char *transient) { const char * const config_unit_paths[] = { USER_CONFIG_UNIT_PATH, @@ -172,6 +173,10 @@ static char** user_dirs( return NULL; /* Now merge everything we found. */ + if (transient) + if (strv_extend(&res, transient) < 0) + return NULL; + if (generator_early) if (strv_extend(&res, generator_early) < 0) return NULL; @@ -305,6 +310,42 @@ static int acquire_generator_dirs( return 0; } +static int acquire_transient_dir(UnitFileScope scope, char **ret) { + char *transient; + + assert(ret); + + switch (scope) { + + case UNIT_FILE_SYSTEM: + transient = strdup("/run/systemd/transient"); + break; + + case UNIT_FILE_USER: { + const char *e; + + e = getenv("XDG_RUNTIME_DIR"); + if (!e) + return -ENXIO; + + transient = strjoin(e, "/systemd/transient", NULL); + break; + } + + case UNIT_FILE_GLOBAL: + return -EOPNOTSUPP; + + default: + assert_not_reached("Hmm, unexpected scope value."); + } + + if (!transient) + return -ENOMEM; + + *ret = transient; + return 0; +} + static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) { _cleanup_free_ char *a = NULL, *b = NULL; int r; @@ -377,8 +418,9 @@ int lookup_paths_init( _cleanup_free_ char *root = NULL, + *persistent_config = NULL, *runtime_config = NULL, *generator = NULL, *generator_early = NULL, *generator_late = NULL, - *persistent_config = NULL, *runtime_config = NULL; + *transient = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ char **l = NULL; const char *e; @@ -411,6 +453,10 @@ int lookup_paths_init( if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) return r; + r = acquire_transient_dir(scope, &transient); + if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) + return r; + /* First priority is whatever has been passed to us via env * vars */ e = getenv("SYSTEMD_UNIT_PATH"); @@ -449,6 +495,7 @@ int lookup_paths_init( add = strv_new( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ + STRV_IFNOTNULL(transient), STRV_IFNOTNULL(generator_early), persistent_config, SYSTEM_CONFIG_UNIT_PATH, @@ -471,6 +518,7 @@ int lookup_paths_init( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and * the arrays in user_dirs() above! */ + STRV_IFNOTNULL(transient), STRV_IFNOTNULL(generator_early), persistent_config, USER_CONFIG_UNIT_PATH, @@ -489,7 +537,8 @@ int lookup_paths_init( case UNIT_FILE_USER: add = user_dirs(persistent_config, runtime_config, - generator, generator_early, generator_late); + generator, generator_early, generator_late, + transient); break; default: @@ -526,6 +575,10 @@ int lookup_paths_init( if (r < 0) return r; + r = patch_root_prefix(&transient, root); + if (r < 0) + return r; + if (!path_strv_resolve_uniq(l, root)) return -ENOMEM; @@ -554,6 +607,9 @@ int lookup_paths_init( p->generator_late = generator_late; generator = generator_early = generator_late = NULL; + p->transient = transient; + transient = NULL; + p->root_dir = root; root = NULL; @@ -573,5 +629,7 @@ void lookup_paths_free(LookupPaths *p) { p->generator_early = mfree(p->generator_early); p->generator_late = mfree(p->generator_late); + p->transient = mfree(p->transient); + p->root_dir = mfree(p->root_dir); } diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 078c3484f5..b0603c0c99 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -38,6 +38,9 @@ struct LookupPaths { char *generator_early; char *generator_late; + /* Where to place transient unit files */ + char *transient; + /* The root directory prepended to all items above, or NULL */ char *root_dir; }; -- cgit v1.2.3-54-g00ecf From cd64fd56134ef00cce0651e741d4ebda3791d97b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2016 01:44:30 +0100 Subject: path-lookup: split out logic for mkdir/rmdir of generator dirs in their own functions --- src/core/manager.c | 15 ++------------- src/shared/path-lookup.c | 37 +++++++++++++++++++++++++++++++++++-- src/shared/path-lookup.h | 3 +++ 3 files changed, 40 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 1bc7921abe..d48b41d88f 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2737,15 +2737,7 @@ static int manager_run_generators(Manager *m) { return 0; found: - r = mkdir_p_label(m->lookup_paths.generator, 0755); - if (r < 0) - goto finish; - - r = mkdir_p_label(m->lookup_paths.generator_early, 0755); - if (r < 0) - goto finish; - - r = mkdir_p_label(m->lookup_paths.generator_late, 0755); + r = lookup_paths_mkdir_generator(&m->lookup_paths); if (r < 0) goto finish; @@ -2759,10 +2751,7 @@ static int manager_run_generators(Manager *m) { execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv); finish: - /* Trim empty dirs */ - (void) rmdir(m->lookup_paths.generator); - (void) rmdir(m->lookup_paths.generator_early); - (void) rmdir(m->lookup_paths.generator_late); + lookup_paths_trim_generator(&m->lookup_paths); return r; } diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index f437de370c..083e467475 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -26,6 +26,7 @@ #include "install.h" #include "log.h" #include "macro.h" +#include "mkdir.h" #include "path-lookup.h" #include "path-util.h" #include "stat-util.h" @@ -457,8 +458,7 @@ int lookup_paths_init( if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) return r; - /* First priority is whatever has been passed to us via env - * vars */ + /* First priority is whatever has been passed to us via env vars */ e = getenv("SYSTEMD_UNIT_PATH"); if (e) { const char *k; @@ -633,3 +633,36 @@ void lookup_paths_free(LookupPaths *p) { p->root_dir = mfree(p->root_dir); } + +int lookup_paths_mkdir_generator(LookupPaths *p) { + int r, q; + + assert(p); + + r = mkdir_p_label(p->generator, 0755); + + q = mkdir_p_label(p->generator_early, 0755); + if (q < 0 && r >= 0) + r = q; + + q = mkdir_p_label(p->generator_late, 0755); + if (q < 0 && r >= 0) + r = q; + + return r; +} + +void lookup_paths_trim_generator(LookupPaths *p) { + assert(p); + + /* Trim empty dirs */ + + if (p->generator) + (void) rmdir(p->generator); + + if (p->generator_early) + (void) rmdir(p->generator_early); + + if (p->generator_late) + (void) rmdir(p->generator_late); +} diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index b0603c0c99..27be1d8be8 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -52,5 +52,8 @@ char **generator_paths(UnitFileScope scope); int lookup_paths_init(LookupPaths *p, UnitFileScope scope, const char *root_dir); +int lookup_paths_mkdir_generator(LookupPaths *p); +void lookup_paths_trim_generator(LookupPaths *p); + void lookup_paths_free(LookupPaths *p); #define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free) -- cgit v1.2.3-54-g00ecf From a14533430498bfaa91ba19b7fd0268bd2ef7d797 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 Feb 2016 02:32:19 +0100 Subject: core: rework logic to drop duplicate and non-existing items from search path Move this into a function of its own, so that we can run it after we ran the generators, so that it takes into account removed generator dirs. --- src/core/manager.c | 2 + src/shared/path-lookup.c | 107 +++++++++++++++++++++++++++++++++++++------- src/shared/path-lookup.h | 2 + src/test/test-path-lookup.c | 6 ++- 4 files changed, 100 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index d48b41d88f..55f2f49a06 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1120,6 +1120,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { if (r < 0) return r; + lookup_paths_reduce(&m->lookup_paths); manager_build_unit_path_cache(m); /* If we will deserialize make sure that during enumeration @@ -2540,6 +2541,7 @@ int manager_reload(Manager *m) { if (q < 0 && r >= 0) r = q; + lookup_paths_reduce(&m->lookup_paths); manager_build_unit_path_cache(m); /* First, enumerate what we can from all config files */ diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 083e467475..eeabdd1ecd 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -412,6 +412,22 @@ static int patch_root_prefix(char **p, const char *root_dir) { return 0; } +static int patch_root_prefix_strv(char **l, const char *root_dir) { + char **i; + int r; + + if (!root_dir) + return 0; + + STRV_FOREACH(i, l) { + r = patch_root_prefix(i, root_dir); + if (r < 0) + return r; + } + + return 0; +} + int lookup_paths_init( LookupPaths *p, UnitFileScope scope, @@ -579,23 +595,11 @@ int lookup_paths_init( if (r < 0) return r; - if (!path_strv_resolve_uniq(l, root)) + r = patch_root_prefix_strv(l, root); + if (r < 0) return -ENOMEM; - if (strv_isempty(l)) { - log_debug("Ignoring unit files."); - l = strv_free(l); - } else { - _cleanup_free_ char *t; - - t = strv_join(l, "\n\t"); - if (!t) - return -ENOMEM; - - log_debug("Looking for unit files in (higher priority first):\n\t%s", t); - } - - p->search_path = l; + p->search_path = strv_uniq(l); l = NULL; p->persistent_config = persistent_config; @@ -634,6 +638,79 @@ void lookup_paths_free(LookupPaths *p) { p->root_dir = mfree(p->root_dir); } +int lookup_paths_reduce(LookupPaths *p) { + _cleanup_free_ struct stat *stats = NULL; + size_t n_stats = 0, allocated = 0; + unsigned c = 0; + int r; + + assert(p); + + /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are + * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set, + * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into + * account when following symlinks. When we have no root path set this restriction does not apply however. */ + + if (!p->search_path) + return 0; + + while (p->search_path[c]) { + struct stat st; + unsigned k; + + if (p->root_dir) + r = lstat(p->search_path[c], &st); + else + r = stat(p->search_path[c], &st); + if (r < 0) { + if (errno == ENOENT) + goto remove_item; + + /* If something we don't grok happened, let's better leave it in. */ + log_debug_errno(errno, "Failed to stat %s: %m", p->search_path[c]); + c++; + continue; + } + + for (k = 0; k < n_stats; k++) { + if (stats[k].st_dev == st.st_dev && + stats[k].st_ino == st.st_ino) + break; + } + + if (k < n_stats) /* Is there already an entry with the same device/inode? */ + goto remove_item; + + if (!GREEDY_REALLOC(stats, allocated, n_stats+1)) + return -ENOMEM; + + stats[n_stats++] = st; + c++; + continue; + + remove_item: + free(p->search_path[c]); + memmove(p->search_path + c, + p->search_path + c + 1, + (strv_length(p->search_path + c + 1) + 1) * sizeof(char*)); + } + + if (strv_isempty(p->search_path)) { + log_debug("Ignoring unit files."); + p->search_path = strv_free(p->search_path); + } else { + _cleanup_free_ char *t; + + t = strv_join(p->search_path, "\n\t"); + if (!t) + return -ENOMEM; + + log_debug("Looking for unit files in (higher priority first):\n\t%s", t); + } + + return 0; +} + int lookup_paths_mkdir_generator(LookupPaths *p) { int r, q; diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 27be1d8be8..5a5d734deb 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -52,6 +52,8 @@ char **generator_paths(UnitFileScope scope); int lookup_paths_init(LookupPaths *p, UnitFileScope scope, const char *root_dir); +int lookup_paths_reduce(LookupPaths *p); + int lookup_paths_mkdir_generator(LookupPaths *p); void lookup_paths_trim_generator(LookupPaths *p); diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index 5575a364f2..5ee6f4ebb2 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -36,8 +36,8 @@ static void test_paths(UnitFileScope scope) { assert_se(mkdtemp(template)); assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); - assert_se(lookup_paths_init(&lp_without_env, scope, NULL) == 0); - + assert_se(lookup_paths_init(&lp_without_env, scope, NULL) >= 0); + assert_se(lookup_paths_reduce(&lp_without_env) >= 0); assert_se(!strv_isempty(lp_without_env.search_path)); systemd_unit_path = strjoina(template, "/systemd-unit-path"); @@ -45,6 +45,8 @@ static void test_paths(UnitFileScope scope) { assert_se(lookup_paths_init(&lp_with_env, scope, NULL) == 0); assert_se(strv_length(lp_with_env.search_path) == 1); assert_se(streq(lp_with_env.search_path[0], systemd_unit_path)); + assert_se(lookup_paths_reduce(&lp_with_env) >= 0); + assert_se(strv_length(lp_with_env.search_path) == 0); assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -- cgit v1.2.3-54-g00ecf From d7e0da1db2ac9e747893ef5f565c554eb246e3f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 26 Feb 2016 17:05:33 +0100 Subject: core: don't drop transient drop-ins when loading the rest Previously, when creating a transient unit, we'd first add the transient drop-ins to the unit, and then normally load any other drop-ins later on top of this, replacing the already loaded drop-ins. Let's not do this, after all the transient drop-ins area already in effect, let's just add what we find on disk, but not replace it. --- src/core/load-dropin.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index 1c65055a3f..f83fa09301 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -44,6 +44,7 @@ static int add_dependency_consumer( } int unit_load_dropin(Unit *u) { + _cleanup_strv_free_ char **l = NULL; Iterator i; char *t, **f; int r; @@ -63,11 +64,19 @@ int unit_load_dropin(Unit *u) { } } - u->dropin_paths = strv_free(u->dropin_paths); - r = unit_find_dropin_paths(u, &u->dropin_paths); + r = unit_find_dropin_paths(u, &l); if (r <= 0) return 0; + if (!u->dropin_paths) { + u->dropin_paths = l; + l = NULL; + } else { + r = strv_extend_strv(&u->dropin_paths, l, true); + if (r < 0) + return log_oom(); + } + STRV_FOREACH(f, u->dropin_paths) { config_parse(u->id, *f, NULL, UNIT_VTABLE(u)->sections, -- cgit v1.2.3-54-g00ecf From 193dc81ee336ad07b92e7e945b458eb24f615f55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 26 Feb 2016 17:58:37 +0100 Subject: core: don't reorder drop-ins when changing properties The drop-in order we present should actually show what we is in effect, hence let's not reorder it when writing changes. After all, just sorting alphabetically is going to break things, as it doesn't respect that /etc breaks /run breaks /usr... --- src/core/unit.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index f6c9891aad..ac29353299 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3365,7 +3365,6 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co if (r < 0) return r; - strv_sort(u->dropin_paths); strv_uniq(u->dropin_paths); u->dropin_mtime = now(CLOCK_REALTIME); -- cgit v1.2.3-54-g00ecf From d063a527411ac9aa715bee59a9dcc59c877d2362 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 26 Feb 2016 18:28:45 +0100 Subject: core: modernize manager_build_unit_patch_cache() a bit --- src/core/manager.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 55f2f49a06..b1f79e014e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -49,6 +49,7 @@ #include "dbus-manager.h" #include "dbus-unit.h" #include "dbus.h" +#include "dirent-util.h" #include "env-util.h" #include "escape.h" #include "exit-status.h" @@ -1026,7 +1027,6 @@ static void manager_coldplug(Manager *m) { static void manager_build_unit_path_cache(Manager *m) { char **i; - _cleanup_closedir_ DIR *d = NULL; int r; assert(m); @@ -1035,29 +1035,27 @@ static void manager_build_unit_path_cache(Manager *m) { m->unit_path_cache = set_new(&string_hash_ops); if (!m->unit_path_cache) { - log_error("Failed to allocate unit path cache."); - return; + r = -ENOMEM; + goto fail; } /* This simply builds a list of files we know exist, so that * we don't always have to go to disk */ STRV_FOREACH(i, m->lookup_paths.search_path) { + _cleanup_closedir_ DIR *d = NULL; struct dirent *de; d = opendir(*i); if (!d) { if (errno != ENOENT) - log_error_errno(errno, "Failed to open directory %s: %m", *i); + log_warning_errno(errno, "Failed to open directory %s, ignoring: %m", *i); continue; } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, r = -errno; goto fail) { char *p; - if (hidden_file(de->d_name)) - continue; - p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL); if (!p) { r = -ENOMEM; @@ -1068,20 +1066,15 @@ static void manager_build_unit_path_cache(Manager *m) { if (r < 0) goto fail; } - - d = safe_closedir(d); } return; fail: - log_error_errno(r, "Failed to build unit path cache: %m"); - - set_free_free(m->unit_path_cache); - m->unit_path_cache = NULL; + log_warning_errno(r, "Failed to build unit path cache, proceeding without: %m"); + m->unit_path_cache = set_free_free(m->unit_path_cache); } - static void manager_distribute_fds(Manager *m, FDSet *fds) { Iterator i; Unit *u; -- cgit v1.2.3-54-g00ecf From 5b5ad18dd9c22957092a651300a2e48bc34959d5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 26 Feb 2016 18:35:46 +0100 Subject: path-lookup: stop exporting two functions user_runtime_dir() and user_config_home() are not used externally anymore, hence let's not export them anymore. --- src/shared/path-lookup.c | 4 ++-- src/shared/path-lookup.h | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index eeabdd1ecd..22357e6392 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -34,7 +34,7 @@ #include "strv.h" #include "util.h" -int user_config_home(char **config_home) { +static int user_config_home(char **config_home) { const char *e; char *r; @@ -63,7 +63,7 @@ int user_config_home(char **config_home) { return 0; } -int user_runtime_dir(char **runtime_dir) { +static int user_runtime_dir(char **runtime_dir) { const char *e; char *r; diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 5a5d734deb..03f103dcc0 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -45,9 +45,6 @@ struct LookupPaths { char *root_dir; }; -int user_config_home(char **config_home); -int user_runtime_dir(char **runtime_dir); - char **generator_paths(UnitFileScope scope); int lookup_paths_init(LookupPaths *p, UnitFileScope scope, const char *root_dir); -- cgit v1.2.3-54-g00ecf From 205dd21eccf6332fdb57f2d2ad9df70ab2c30cb1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Feb 2016 20:41:54 +0100 Subject: path-lookup: clean up user_config_home() and user_runtime_dir() Let's modernize these calls a bit. Also, don't call them from user_dirs() anymore, as we already have both dirs in the list a second time via the persistent_config and runtime_config function parameters. --- src/shared/path-lookup.c | 85 +++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 22357e6392..17a9ca2aac 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -34,55 +34,57 @@ #include "strv.h" #include "util.h" -static int user_config_home(char **config_home) { +static int user_config_home(char **ret) { const char *e; - char *r; + char *j; + + assert(ret); e = getenv("XDG_CONFIG_HOME"); if (e) { - r = strappend(e, "/systemd/user"); - if (!r) + j = strappend(e, "/systemd/user"); + if (!j) return -ENOMEM; - *config_home = r; - return 1; } else { const char *home; home = getenv("HOME"); - if (home) { - r = strappend(home, "/.config/systemd/user"); - if (!r) - return -ENOMEM; + if (!home) + return -ENXIO; - *config_home = r; - return 1; - } + j = strappend(home, "/.config/systemd/user"); + if (!j) + return -ENOMEM; } + *ret = j; return 0; } -static int user_runtime_dir(char **runtime_dir) { +static int user_runtime_dir(char **ret) { const char *e; - char *r; + char *j; + + assert(ret); e = getenv("XDG_RUNTIME_DIR"); - if (e) { - r = strappend(e, "/systemd/user"); - if (!r) - return -ENOMEM; + if (!e) + return -ENXIO; - *runtime_dir = r; - return 1; - } + j = strappend(e, "/systemd/user"); + if (!j) + return -ENOMEM; + *ret = j; return 0; } -static int user_data_home_dir(char **dir, const char *suffix) { +static int user_data_home_dir(char **ret, const char *suffix) { const char *e; - char *res; + char *j; + + assert(ret); /* We don't treat /etc/xdg/systemd here as the spec * suggests because we assume that that is a link to @@ -90,20 +92,21 @@ static int user_data_home_dir(char **dir, const char *suffix) { e = getenv("XDG_DATA_HOME"); if (e) - res = strappend(e, suffix); + j = strappend(e, suffix); else { const char *home; home = getenv("HOME"); - if (home) - res = strjoin(home, "/.local/share", suffix, NULL); - else - return 0; + if (!home) + return -ENXIO; + + + j = strjoin(home, "/.local/share", suffix, NULL); } - if (!res) + if (!j) return -ENOMEM; - *dir = res; + *ret = j; return 1; } @@ -131,8 +134,8 @@ static char** user_dirs( }; const char *e; - _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL; _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL; + _cleanup_free_ char *data_home = NULL; _cleanup_free_ char **res = NULL; char **tmp; int r; @@ -146,12 +149,6 @@ static char** user_dirs( * as data, and allow overriding as configuration. */ - if (user_config_home(&config_home) < 0) - return NULL; - - if (user_runtime_dir(&runtime_dir) < 0) - return NULL; - e = getenv("XDG_CONFIG_DIRS"); if (e) { config_dirs = strv_split(e, ":"); @@ -160,7 +157,7 @@ static char** user_dirs( } r = user_data_home_dir(&data_home, "/systemd/user"); - if (r < 0) + if (r < 0 && r != -ENXIO) return NULL; e = getenv("XDG_DATA_DIRS"); @@ -182,10 +179,6 @@ static char** user_dirs( if (strv_extend(&res, generator_early) < 0) return NULL; - if (config_home) - if (strv_extend(&res, config_home) < 0) - return NULL; - if (!strv_isempty(config_dirs)) if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0) return NULL; @@ -196,10 +189,6 @@ static char** user_dirs( if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0) return NULL; - if (runtime_dir) - if (strv_extend(&res, runtime_dir) < 0) - return NULL; - if (strv_extend(&res, runtime_config) < 0) return NULL; @@ -463,7 +452,7 @@ int lookup_paths_init( } r = acquire_config_dirs(scope, &persistent_config, &runtime_config); - if (r < 0) + if (r < 0 && r != -ENXIO) return r; r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late); -- cgit v1.2.3-54-g00ecf From a7527131bbae88b44469a44f9d97325d70762981 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Feb 2016 20:56:47 +0100 Subject: path-lookup: make user_runtime_dir() more generic Let's make the suffix it appends configurable. This way we can reuse it at a second place. --- src/shared/path-lookup.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 17a9ca2aac..0735e3b4f5 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -62,17 +62,18 @@ static int user_config_home(char **ret) { return 0; } -static int user_runtime_dir(char **ret) { +static int user_runtime_dir(char **ret, const char *suffix) { const char *e; char *j; assert(ret); + assert(suffix); e = getenv("XDG_RUNTIME_DIR"); if (!e) return -ENXIO; - j = strappend(e, "/systemd/user"); + j = strappend(e, suffix); if (!j) return -ENOMEM; @@ -85,6 +86,7 @@ static int user_data_home_dir(char **ret, const char *suffix) { char *j; assert(ret); + assert(suffix); /* We don't treat /etc/xdg/systemd here as the spec * suggests because we assume that that is a link to @@ -301,27 +303,24 @@ static int acquire_generator_dirs( } static int acquire_transient_dir(UnitFileScope scope, char **ret) { - char *transient; - assert(ret); switch (scope) { - case UNIT_FILE_SYSTEM: - transient = strdup("/run/systemd/transient"); - break; - - case UNIT_FILE_USER: { - const char *e; + case UNIT_FILE_SYSTEM: { + char *transient; - e = getenv("XDG_RUNTIME_DIR"); - if (!e) - return -ENXIO; + transient = strdup("/run/systemd/transient"); + if (!transient) + return -ENOMEM; - transient = strjoin(e, "/systemd/transient", NULL); - break; + *ret = transient; + return 0; } + case UNIT_FILE_USER: + return user_runtime_dir(ret, "/systemd/transient"); + case UNIT_FILE_GLOBAL: return -EOPNOTSUPP; @@ -329,11 +328,6 @@ static int acquire_transient_dir(UnitFileScope scope, char **ret) { assert_not_reached("Hmm, unexpected scope value."); } - if (!transient) - return -ENOMEM; - - *ret = transient; - return 0; } static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) { @@ -360,7 +354,7 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru if (r < 0) return r; - r = user_runtime_dir(runtime); + r = user_runtime_dir(runtime, "/systemd/user"); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 401017e04d3d1ac41fabb939278984acc8298ddb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Mar 2016 17:40:07 +0100 Subject: install: fix root prefix handling Previously, we'd execute some operations with the root prefix applied, while others without (which was a bug). Clean this up: all paths are now prefixed properly with the root path, and we strip it off when necessary. (Of course, an alternative option would be to strictly pass around paths without the prefix prepended and only prepend it right before hitting the disk, however, I am came to the conclusion this would result in more code.) --- src/shared/install.c | 210 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 132 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index b588457c13..6c5d3ce7d1 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -82,6 +82,28 @@ static int in_search_path(const LookupPaths *p, const char *path) { return false; } +static const char* skip_root(const LookupPaths *p, const char *path) { + if (p->root_dir) { + char *e; + + e = path_startswith(path, p->root_dir); + if (!e) + return NULL; + + /* Make sure the returned path starts with a slash */ + if (e[0] != '/') { + if (e == path || e[-1] != '/') + return NULL; + + e--; + } + + return e; + } + + return path; +} + static int path_is_generator(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; @@ -99,6 +121,7 @@ static int path_is_generator(const LookupPaths *p, const char *path) { static int path_is_config(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; + const char *rpath; assert(p); assert(path); @@ -107,7 +130,8 @@ static int path_is_config(const LookupPaths *p, const char *path) { * top-level directory and the one actually configured. The latter is particularly relevant for cases where we * operate on a root directory. */ - if (path_startswith(path, "/etc") || path_startswith(path, "/run")) + rpath = skip_root(p, path); + if (rpath && (path_startswith(rpath, "/etc") || path_startswith(rpath, "/run"))) return true; parent = dirname_malloc(path); @@ -120,11 +144,13 @@ static int path_is_config(const LookupPaths *p, const char *path) { static int path_is_runtime(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; + const char *rpath; assert(p); assert(path); - if (path_startswith(path, "/run")) + rpath = skip_root(p, path); + if (rpath && path_startswith(rpath, "/run")) return true; parent = dirname_malloc(path); @@ -275,6 +301,7 @@ static int remove_marked_symlinks_fd( int fd, const char *path, const char *config_path, + const LookupPaths *lp, bool *restart, UnitFileChange **changes, unsigned *n_changes) { @@ -287,6 +314,7 @@ static int remove_marked_symlinks_fd( assert(fd >= 0); assert(path); assert(config_path); + assert(lp); assert(restart); d = fdopendir(fd); @@ -322,12 +350,13 @@ static int remove_marked_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes); if (q < 0 && r == 0) r = q; } else if (de->d_type == DT_LNK) { _cleanup_free_ char *p = NULL, *dest = NULL; + const char *rp; bool found; int q; @@ -339,19 +368,16 @@ static int remove_marked_symlinks_fd( return -ENOMEM; q = readlink_malloc(p, &dest); + if (q == -ENOENT) + continue; if (q < 0) { - if (q == -ENOENT) - continue; - if (r == 0) r = q; continue; } - /* We remove all links pointing to a file or - * path that is marked, as well as all files - * sharing the same name as a file that is - * marked. */ + /* We remove all links pointing to a file or path that is marked, as well as all files sharing + * the same name as a file that is marked. */ found = set_contains(remove_symlinks_to, dest) || @@ -361,7 +387,7 @@ static int remove_marked_symlinks_fd( if (!found) continue; - if (unlink(p) < 0 && errno != ENOENT) { + if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) { if (r == 0) r = -errno; continue; @@ -372,7 +398,11 @@ static int remove_marked_symlinks_fd( unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); - q = mark_symlink_for_removal(&remove_symlinks_to, p); + /* Now, remember the full path (but with the root prefix removed) of the symlink we just + * removed, and remove any symlinks to it, too */ + + rp = skip_root(lp, p); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p); if (q < 0) return q; if (q > 0) @@ -386,6 +416,7 @@ static int remove_marked_symlinks_fd( static int remove_marked_symlinks( Set *remove_symlinks_to, const char *config_path, + const LookupPaths *lp, UnitFileChange **changes, unsigned *n_changes) { @@ -394,6 +425,7 @@ static int remove_marked_symlinks( int r = 0; assert(config_path); + assert(lp); if (set_size(remove_symlinks_to) <= 0) return 0; @@ -411,7 +443,7 @@ static int remove_marked_symlinks( return -errno; /* This takes possession of cfd and closes it */ - q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes); if (r == 0) r = q; } while (restart); @@ -425,6 +457,7 @@ static int find_symlinks_fd( int fd, const char *path, const char *config_path, + const LookupPaths *lp, bool *same_name_link) { _cleanup_closedir_ DIR *d = NULL; @@ -435,6 +468,7 @@ static int find_symlinks_fd( assert(fd >= 0); assert(path); assert(config_path); + assert(lp); assert(same_name_link); d = fdopendir(fd); @@ -468,7 +502,7 @@ static int find_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link); + q = find_symlinks_fd(root_dir, name, nfd, p, config_path, lp, same_name_link); if (q > 0) return 1; if (r == 0) @@ -546,6 +580,7 @@ static int find_symlinks( const char *root_dir, const char *name, const char *config_path, + const LookupPaths *lp, bool *same_name_link) { int fd; @@ -562,7 +597,7 @@ static int find_symlinks( } /* This takes possession of fd and closes it */ - return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link); + return find_symlinks_fd(root_dir, name, fd, config_path, config_path, lp, same_name_link); } static int find_symlinks_in_scope( @@ -580,7 +615,7 @@ static int find_symlinks_in_scope( assert(name); /* First look in the persistent config path */ - r = find_symlinks(paths->root_dir, name, paths->persistent_config, &same_name_link); + r = find_symlinks(paths->root_dir, name, paths->persistent_config, paths, &same_name_link); if (r < 0) return r; if (r > 0) { @@ -589,7 +624,7 @@ static int find_symlinks_in_scope( } /* Then look in runtime config path */ - r = find_symlinks(paths->root_dir, name, paths->runtime_config, &same_name_link_runtime); + r = find_symlinks(paths->root_dir, name, paths->runtime_config, paths, &same_name_link_runtime); if (r < 0) return r; if (r > 0) { @@ -718,20 +753,6 @@ fail: return r; } -static int install_info_add_auto( - InstallContext *c, - const char *name_or_path, - UnitFileInstallInfo **ret) { - - assert(c); - assert(name_or_path); - - if (path_is_absolute(name_or_path)) - return install_info_add(c, NULL, name_or_path, ret); - else - return install_info_add(c, name_or_path, NULL, ret); -} - static int config_parse_also( const char *unit, const char *filename, @@ -814,7 +835,6 @@ static int unit_file_load( InstallContext *c, UnitFileInstallInfo *info, const char *path, - const char *root_dir, SearchFlags flags) { const ConfigTableItem items[] = { @@ -835,8 +855,6 @@ static int unit_file_load( assert(info); assert(path); - path = prefix_roota(root_dir, path); - if (!(flags & SEARCH_LOAD)) { r = lstat(path, &st); if (r < 0) @@ -897,26 +915,26 @@ static int unit_file_load_or_readlink( const char *root_dir, SearchFlags flags) { - _cleanup_free_ char *np = NULL; + _cleanup_free_ char *target = NULL; int r; - r = unit_file_load(c, info, path, root_dir, flags); + r = unit_file_load(c, info, path, flags); if (r != -ELOOP) return r; /* This is a symlink, let's read it. */ - r = readlink_and_make_absolute_root(root_dir, path, &np); + r = readlink_malloc(path, &target); if (r < 0) return r; - if (path_equal(np, "/dev/null")) + if (path_equal(target, "/dev/null")) info->type = UNIT_FILE_TYPE_MASKED; else { const char *bn; UnitType a, b; - bn = basename(np); + bn = basename(target); if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) { @@ -943,9 +961,16 @@ static int unit_file_load_or_readlink( if (a < 0 || b < 0 || a != b) return -EINVAL; + if (path_is_absolute(target)) + /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */ + info->symlink_target = prefix_root(root_dir, target); + else + /* This is a relative path, take it relative to the dir the symlink is located in. */ + info->symlink_target = file_in_same_dir(path, target); + if (!info->symlink_target) + return -ENOMEM; + info->type = UNIT_FILE_TYPE_SYMLINK; - info->symlink_target = np; - np = NULL; } return 0; @@ -1136,6 +1161,25 @@ static int install_info_traverse( return 0; } +static int install_info_add_auto( + InstallContext *c, + const LookupPaths *paths, + const char *name_or_path, + UnitFileInstallInfo **ret) { + + assert(c); + assert(name_or_path); + + if (path_is_absolute(name_or_path)) { + const char *pp; + + pp = prefix_roota(paths->root_dir, name_or_path); + + return install_info_add(c, NULL, pp, ret); + } else + return install_info_add(c, name_or_path, NULL, ret); +} + static int install_info_discover( UnitFileScope scope, InstallContext *c, @@ -1151,7 +1195,7 @@ static int install_info_discover( assert(paths); assert(name); - r = install_info_add_auto(c, name, &i); + r = install_info_add_auto(c, paths, name, &i); if (r < 0) return r; @@ -1160,6 +1204,7 @@ static int install_info_discover( static int install_info_symlink_alias( UnitFileInstallInfo *i, + const LookupPaths *paths, const char *config_path, bool force, UnitFileChange **changes, @@ -1169,10 +1214,12 @@ static int install_info_symlink_alias( int r = 0, q; assert(i); + assert(paths); assert(config_path); STRV_FOREACH(s, i->aliases) { _cleanup_free_ char *alias_path = NULL, *dst = NULL; + const char *rp; q = install_full_printf(i, *s, &dst); if (q < 0) @@ -1182,7 +1229,9 @@ static int install_info_symlink_alias( if (!alias_path) return -ENOMEM; - q = create_symlink(i->path, alias_path, force, changes, n_changes); + rp = skip_root(paths, i->path); + + q = create_symlink(rp ?: i->path, alias_path, force, changes, n_changes); if (r == 0) r = q; } @@ -1192,6 +1241,7 @@ static int install_info_symlink_alias( static int install_info_symlink_wants( UnitFileInstallInfo *i, + const LookupPaths *paths, const char *config_path, char **list, const char *suffix, @@ -1205,6 +1255,7 @@ static int install_info_symlink_wants( int r = 0, q; assert(i); + assert(paths); assert(config_path); if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) { @@ -1225,6 +1276,7 @@ static int install_info_symlink_wants( STRV_FOREACH(s, list) { _cleanup_free_ char *path = NULL, *dst = NULL; + const char *rp; q = install_full_printf(i, *s, &dst); if (q < 0) @@ -1239,7 +1291,9 @@ static int install_info_symlink_wants( if (!path) return -ENOMEM; - q = create_symlink(i->path, path, force, changes, n_changes); + rp = skip_root(paths, i->path); + + q = create_symlink(rp ?: i->path, path, force, changes, n_changes); if (r == 0) r = q; } @@ -1256,6 +1310,7 @@ static int install_info_symlink_link( unsigned *n_changes) { _cleanup_free_ char *path = NULL; + const char *rp; int r; assert(i); @@ -1271,7 +1326,9 @@ static int install_info_symlink_link( if (!path) return -ENOMEM; - return create_symlink(i->path, path, force, changes, n_changes); + rp = skip_root(paths, i->path); + + return create_symlink(rp ?: i->path, path, force, changes, n_changes); } static int install_info_apply( @@ -1291,13 +1348,13 @@ static int install_info_apply( if (i->type != UNIT_FILE_TYPE_REGULAR) return 0; - r = install_info_symlink_alias(i, config_path, force, changes, n_changes); + r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes); - q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes); + q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", force, changes, n_changes); if (r == 0) r = q; - q = install_info_symlink_wants(i, config_path, i->required_by, ".requires/", force, changes, n_changes); + q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", force, changes, n_changes); if (r == 0) r = q; @@ -1502,6 +1559,7 @@ int unit_file_unmask( r = 0; STRV_FOREACH(i, todo) { _cleanup_free_ char *path = NULL; + const char *rp; path = path_make_absolute(*i, config_path); if (!path) @@ -1510,16 +1568,19 @@ int unit_file_unmask( if (unlink(path) < 0) { if (errno != -ENOENT && r >= 0) r = -errno; - } else { - q = mark_symlink_for_removal(&remove_symlinks_to, path); - if (q < 0) - return q; - unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + continue; } + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + + rp = skip_root(&paths, path); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path); + if (q < 0) + return q; } - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes); if (r >= 0) r = q; @@ -1592,13 +1653,15 @@ int unit_file_link( r = 0; STRV_FOREACH(i, todo) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *new_path = NULL; + const char *old_path; - path = path_make_absolute(basename(*i), config_path); - if (!path) + old_path = skip_root(&paths, *i); + new_path = path_make_absolute(basename(*i), config_path); + if (!new_path) return -ENOMEM; - q = create_symlink(*i, path, force, changes, n_changes); + q = create_symlink(old_path ?: *i, new_path, force, changes, n_changes); if (q < 0 && r >= 0) r = q; } @@ -1763,7 +1826,7 @@ int unit_file_disable( if (r < 0) return r; - return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes); } int unit_file_reenable( @@ -1805,14 +1868,14 @@ int unit_file_set_default( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; UnitFileInstallInfo *i; - const char *path; + const char *new_path, *old_path; int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - if (unit_name_to_type(name) != UNIT_TARGET) + if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */ return -EINVAL; if (streq(name, SPECIAL_DEFAULT_TARGET)) return -EINVAL; @@ -1829,9 +1892,10 @@ int unit_file_set_default( if (path_is_generator(&paths, i->path)) return -EADDRNOTAVAIL; - path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); + old_path = skip_root(&paths, i->path); + new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); - return create_symlink(i->path, path, force, changes, n_changes); + return create_symlink(old_path ?: i->path, new_path, force, changes, n_changes); } int unit_file_get_default( @@ -2064,7 +2128,7 @@ static int execute_preset( if (r < 0) return r; - r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes); } else r = 0; @@ -2183,14 +2247,9 @@ int unit_file_preset_all( STRV_FOREACH(i, paths.search_path) { _cleanup_closedir_ DIR *d = NULL; - _cleanup_free_ char *units_dir; struct dirent *de; - units_dir = path_join(paths.root_dir, *i, NULL); - if (!units_dir) - return -ENOMEM; - - d = opendir(units_dir); + d = opendir(*i); if (!d) { if (errno == ENOENT) continue; @@ -2255,14 +2314,9 @@ int unit_file_get_list( STRV_FOREACH(i, paths.search_path) { _cleanup_closedir_ DIR *d = NULL; - _cleanup_free_ char *units_dir; struct dirent *de; - units_dir = path_join(paths.root_dir, *i, NULL); - if (!units_dir) - return -ENOMEM; - - d = opendir(units_dir); + d = opendir(*i); if (!d) { if (errno == ENOENT) continue; @@ -2288,11 +2342,11 @@ int unit_file_get_list( if (!f) return -ENOMEM; - f->path = path_make_absolute(de->d_name, units_dir); + f->path = path_make_absolute(de->d_name, *i); if (!f->path) return -ENOMEM; - r = unit_file_lookup_state(scope, &paths, basename(f->path), &f->state); + r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state); if (r < 0) f->state = UNIT_FILE_BAD; -- cgit v1.2.3-54-g00ecf From e4fca67ff02c44216780c5a61b1ab66cb6c09752 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Mar 2016 19:07:30 +0100 Subject: install: introduce a new unit file state "transient" Now, that the search path logic knows the unit path for transient units we also can introduce an explicit unit file state "transient" that clarifies to the user what kind of unit file he is encountering. --- man/systemctl.xml | 5 +++++ src/core/dbus-manager.c | 4 ++-- src/shared/install.c | 32 ++++++++++++++++++++++++++++++++ src/shared/install.h | 1 + src/systemctl/systemctl.c | 4 ++-- 5 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/man/systemctl.xml b/man/systemctl.xml index 0febdfd4de..064777810f 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1186,6 +1186,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service The unit file was generated dynamically via a generator tool. See systemd.generator7. Generated unit files may not be enabled, they are enabled implicitly by their generator. 0 + + transient + The unit file has been created dynamically with the runtime API. Transient units may not be enabled. + 0 + bad The unit file is invalid or another error occurred. Note that is-enabled will not actually return this state, but print an error message instead. However the unit file listing printed by list-unit-files might show it. diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 5fc3526751..f0ee2fcb36 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1641,7 +1641,7 @@ static int method_enable_unit_files_generic( if (r == -ESHUTDOWN) return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); if (r == -EADDRNOTAVAIL) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is generated."); + return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated."); if (r < 0) return r; @@ -1866,7 +1866,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd if (r == -ESHUTDOWN) return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); if (r == -EADDRNOTAVAIL) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is generated."); + return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated."); if (r < 0) return r; diff --git a/src/shared/install.c b/src/shared/install.c index 6c5d3ce7d1..c19c85a3b5 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -119,6 +119,19 @@ static int path_is_generator(const LookupPaths *p, const char *path) { path_equal(p->generator_late, parent); } +static int path_is_transient(const LookupPaths *p, const char *path) { + _cleanup_free_ char *parent = NULL; + + assert(p); + assert(path); + + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; + + return path_equal(p->transient, parent); +} + static int path_is_config(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; const char *rpath; @@ -1710,6 +1723,8 @@ int unit_file_add_dependency( return -ESHUTDOWN; if (path_is_generator(&paths, target_info->path)) return -EADDRNOTAVAIL; + if (path_is_transient(&paths, target_info->path)) + return -EADDRNOTAVAIL; assert(target_info->type == UNIT_FILE_TYPE_REGULAR); @@ -1723,6 +1738,8 @@ int unit_file_add_dependency( return -ESHUTDOWN; if (path_is_generator(&paths, i->path)) return -EADDRNOTAVAIL; + if (path_is_transient(&paths, i->path)) + return -EADDRNOTAVAIL; assert(i->type == UNIT_FILE_TYPE_REGULAR); @@ -1777,6 +1794,8 @@ int unit_file_enable( return -ESHUTDOWN; if (path_is_generator(&paths, i->path)) return -EADDRNOTAVAIL; + if (path_is_transient(&paths, i->path)) + return -EADDRNOTAVAIL; assert(i->type == UNIT_FILE_TYPE_REGULAR); } @@ -1891,6 +1910,8 @@ int unit_file_set_default( return -ESHUTDOWN; if (path_is_generator(&paths, i->path)) return -EADDRNOTAVAIL; + if (path_is_transient(&paths, i->path)) + return -EADDRNOTAVAIL; old_path = skip_root(&paths, i->path); new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); @@ -1975,6 +1996,14 @@ int unit_file_lookup_state( break; } + r = path_is_transient(paths, i->path); + if (r < 0) + return r; + if (r > 0) { + state = UNIT_FILE_TRANSIENT; + break; + } + r = find_symlinks_in_scope(scope, paths, i->name, &state); if (r < 0) return r; @@ -2176,6 +2205,8 @@ static int preset_prepare_one( return -ESHUTDOWN; if (path_is_generator(paths, i->path)) return -EADDRNOTAVAIL; + if (path_is_transient(paths, i->path)) + return -EADDRNOTAVAIL; } else r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); @@ -2372,6 +2403,7 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { [UNIT_FILE_DISABLED] = "disabled", [UNIT_FILE_INDIRECT] = "indirect", [UNIT_FILE_GENERATED] = "generated", + [UNIT_FILE_TRANSIENT] = "transient", [UNIT_FILE_BAD] = "bad", }; diff --git a/src/shared/install.h b/src/shared/install.h index 9c33110e44..578664dd48 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -55,6 +55,7 @@ enum UnitFileState { UNIT_FILE_DISABLED, UNIT_FILE_INDIRECT, UNIT_FILE_GENERATED, + UNIT_FILE_TRANSIENT, UNIT_FILE_BAD, _UNIT_FILE_STATE_MAX, _UNIT_FILE_STATE_INVALID = -1 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 3fd44a01d4..b64a97375e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5444,7 +5444,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { if (r == -ESHUTDOWN) return log_error_errno(r, "Unit file is masked."); if (r == -EADDRNOTAVAIL) - return log_error_errno(r, "Unit file is generated."); + return log_error_errno(r, "Unit file is transient or generated."); if (r < 0) return log_error_errno(r, "Operation failed: %m"); @@ -5612,7 +5612,7 @@ static int add_dependency(int argc, char *argv[], void *userdata) { if (r == -ESHUTDOWN) return log_error_errno(r, "Unit file is masked."); if (r == -EADDRNOTAVAIL) - return log_error_errno(r, "Unit file is generated."); + return log_error_errno(r, "Unit file is transient or generated."); if (r < 0) return log_error_errno(r, "Can't add dependency: %m"); -- cgit v1.2.3-54-g00ecf From 76adb5b8b57ce40947fd00f7b33ea7b1d1e1e738 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Mar 2016 19:15:51 +0100 Subject: install: unify checking whether operations may be applied to a unit file in a new function Let's replace repeated code by a single implementation in a single function. --- src/shared/install.c | 67 +++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index c19c85a3b5..f78cc814e5 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -704,6 +704,23 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam return ordered_hashmap_get(c->will_process, name); } +static int install_info_may_process(UnitFileInstallInfo *i, const LookupPaths *paths) { + assert(i); + assert(paths); + + /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus + * not subject to enable/disable operations. */ + + if (i->type == UNIT_FILE_TYPE_MASKED) + return -ESHUTDOWN; + if (path_is_generator(paths, i->path)) + return -EADDRNOTAVAIL; + if (path_is_transient(paths, i->path)) + return -EADDRNOTAVAIL; + + return 0; +} + static int install_info_add( InstallContext *c, const char *name, @@ -1719,12 +1736,9 @@ int unit_file_add_dependency( r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); if (r < 0) return r; - if (target_info->type == UNIT_FILE_TYPE_MASKED) - return -ESHUTDOWN; - if (path_is_generator(&paths, target_info->path)) - return -EADDRNOTAVAIL; - if (path_is_transient(&paths, target_info->path)) - return -EADDRNOTAVAIL; + r = install_info_may_process(target_info, &paths); + if (r < 0) + return r; assert(target_info->type == UNIT_FILE_TYPE_REGULAR); @@ -1734,12 +1748,9 @@ int unit_file_add_dependency( r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; - if (i->type == UNIT_FILE_TYPE_MASKED) - return -ESHUTDOWN; - if (path_is_generator(&paths, i->path)) - return -EADDRNOTAVAIL; - if (path_is_transient(&paths, i->path)) - return -EADDRNOTAVAIL; + r = install_info_may_process(i, &paths); + if (r < 0) + return r; assert(i->type == UNIT_FILE_TYPE_REGULAR); @@ -1790,12 +1801,9 @@ int unit_file_enable( r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i); if (r < 0) return r; - if (i->type == UNIT_FILE_TYPE_MASKED) - return -ESHUTDOWN; - if (path_is_generator(&paths, i->path)) - return -EADDRNOTAVAIL; - if (path_is_transient(&paths, i->path)) - return -EADDRNOTAVAIL; + r = install_info_may_process(i, &paths); + if (r < 0) + return r; assert(i->type == UNIT_FILE_TYPE_REGULAR); } @@ -1906,12 +1914,9 @@ int unit_file_set_default( r = install_info_discover(scope, &c, &paths, name, 0, &i); if (r < 0) return r; - if (i->type == UNIT_FILE_TYPE_MASKED) - return -ESHUTDOWN; - if (path_is_generator(&paths, i->path)) - return -EADDRNOTAVAIL; - if (path_is_transient(&paths, i->path)) - return -EADDRNOTAVAIL; + r = install_info_may_process(i, &paths); + if (r < 0) + return r; old_path = skip_root(&paths, i->path); new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); @@ -1941,8 +1946,9 @@ int unit_file_get_default( r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; - if (i->type == UNIT_FILE_TYPE_MASKED) - return -ESHUTDOWN; + r = install_info_may_process(i, &paths); + if (r < 0) + return r; n = strdup(i->name); if (!n) @@ -2201,12 +2207,9 @@ static int preset_prepare_one( if (r < 0) return r; - if (i->type == UNIT_FILE_TYPE_MASKED) - return -ESHUTDOWN; - if (path_is_generator(paths, i->path)) - return -EADDRNOTAVAIL; - if (path_is_transient(paths, i->path)) - return -EADDRNOTAVAIL; + r = install_info_may_process(i, paths); + if (r < 0) + return r; } else r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); -- cgit v1.2.3-54-g00ecf From 08ce521fb2546921f2642bef067d2cc02158b121 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 5 Apr 2016 19:30:31 +0200 Subject: shared: add a temporary work-around for kernel header inclusion fuck-up See: #2864 --- src/shared/firewall-util.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index 0d3da2e6d2..ade2de7727 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -17,14 +17,24 @@ along with systemd; If not, see . ***/ +#warning "Temporary work-around for broken glibc vs. linux kernel header definitions" +#warning "This really should be removed sooner rather than later, when this is fixed upstream" +#define _NET_IF_H 1 + #include #include #include #include -#include #include #include #include +#include +#include +#ifndef IFNAMSIZ +#undef _NET_IF_H +/* Let's make sure to include this one, too, if IFNAMSIZ isn't defined yet, as it is for kernels <= 4.2 */ +#include +#endif #include #include #include -- cgit v1.2.3-54-g00ecf From 198402d3c9d9b92d6a5e9bca70693011108914e0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 17:49:27 +0200 Subject: test: bump up log level for install root test --- src/test/test-install-root.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index cd250ca7b8..bc4206a1b0 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -30,6 +30,8 @@ static void test_basic_mask_and_enable(const char *root) { UnitFileChange *changes = NULL; unsigned n_changes = 0; + log_set_max_level(LOG_DEBUG); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); -- cgit v1.2.3-54-g00ecf From 5de344704df64d8f31448f1222432bc87ddcfbef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 18:23:37 +0200 Subject: localed: downgrade libxkbcommon to an optional runtime dependency Previously, libxkbcommon was a compile-time option. When enabled the localed binary would strictly depend on it, thus pulling in libxkbcommon and its dependencies, which are non-trivial in size. With this change we dlopen() libxkbcommon when it is available instead. If the library is available behaviour is as before. However, if it isn't the system is considered "headless", i.e. without local hardware and all attempts to set the local keyboard configuration will be refused. This is useful for general-purpose distributions which want to support "headless" (such as container systems) and "full" systems with the same build. --- Makefile.am | 3 +-- src/locale/localed.c | 76 +++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 67 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 5c25178aec..0c2de6f2d3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4729,8 +4729,7 @@ systemd_localed_SOURCES = \ src/locale/localed.c systemd_localed_LDADD = \ - libshared.la \ - $(XKBCOMMON_LIBS) + libshared.la systemd_localed_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/src/locale/localed.c b/src/locale/localed.c index 46405ca68a..3b22a582ac 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -24,6 +24,7 @@ #ifdef HAVE_XKBCOMMON #include +#include #endif #include "sd-bus.h" @@ -1101,6 +1102,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro } #ifdef HAVE_XKBCOMMON + _printf_(3, 0) static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) { const char *fmt; @@ -1109,7 +1111,24 @@ static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args); } +#define LOAD_SYMBOL(symbol, dl, name) \ + ({ \ + (symbol) = (typeof(symbol)) dlvsym((dl), (name), "V_0.5.0"); \ + (symbol) ? 0 : -EOPNOTSUPP; \ + }) + static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) { + + /* We dlopen() the library in order to make the dependency soft. The library (and what it pulls in) is huge + * after all, hence let's support XKB maps when the library is around, and refuse otherwise. The function + * pointers to the shared library are below: */ + + struct xkb_context* (*symbol_xkb_context_new)(enum xkb_context_flags flags) = NULL; + void (*symbol_xkb_context_unref)(struct xkb_context *context) = NULL; + void (*symbol_xkb_context_set_log_fn)(struct xkb_context *context, void (*log_fn)(struct xkb_context *context, enum xkb_log_level level, const char *format, va_list args)) = NULL; + struct xkb_keymap* (*symbol_xkb_keymap_new_from_names)(struct xkb_context *context, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags) = NULL; + void (*symbol_xkb_keymap_unref)(struct xkb_keymap *keymap) = NULL; + const struct xkb_rule_names rmlvo = { .model = model, .layout = layout, @@ -1118,35 +1137,68 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v }; struct xkb_context *ctx = NULL; struct xkb_keymap *km = NULL; + void *dl; int r; - /* compile keymap from RMLVO information to check out its validity */ + /* Compile keymap from RMLVO information to check out its validity */ + + dl = dlopen("libxkbcommon.so.0", RTLD_LAZY); + if (!dl) + return -EOPNOTSUPP; + + r = LOAD_SYMBOL(symbol_xkb_context_new, dl, "xkb_context_new"); + if (r < 0) + goto finish; + + r = LOAD_SYMBOL(symbol_xkb_context_unref, dl, "xkb_context_unref"); + if (r < 0) + goto finish; + + r = LOAD_SYMBOL(symbol_xkb_context_set_log_fn, dl, "xkb_context_set_log_fn"); + if (r < 0) + goto finish; - ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES); + r = LOAD_SYMBOL(symbol_xkb_keymap_new_from_names, dl, "xkb_keymap_new_from_names"); + if (r < 0) + goto finish; + + r = LOAD_SYMBOL(symbol_xkb_keymap_unref, dl, "xkb_keymap_unref"); + if (r < 0) + goto finish; + + ctx = symbol_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES); if (!ctx) { r = -ENOMEM; - goto exit; + goto finish; } - xkb_context_set_log_fn(ctx, log_xkb); + symbol_xkb_context_set_log_fn(ctx, log_xkb); - km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS); + km = symbol_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!km) { r = -EINVAL; - goto exit; + goto finish; } r = 0; -exit: - xkb_keymap_unref(km); - xkb_context_unref(ctx); +finish: + if (symbol_xkb_keymap_unref && km) + symbol_xkb_keymap_unref(km); + + if (symbol_xkb_context_unref && ctx) + symbol_xkb_context_unref(ctx); + + (void) dlclose(dl); return r; } + #else + static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) { return 0; } + #endif static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) { @@ -1203,7 +1255,11 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err if (r < 0) { log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m", strempty(model), strempty(layout), strempty(variant), strempty(options)); - return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing"); + + if (r == -EOPNOTSUPP) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system."); + + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified keymap cannot be compiled, refusing as invalid."); } if (free_and_strdup(&c->x11_layout, layout) < 0 || -- cgit v1.2.3-54-g00ecf From e46e442243d45fa2a0214baabe478a6f21ad0858 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 19:15:12 +0200 Subject: tests: make sure test-path-lookup can run even when no units are installed on test system --- src/test/test-path-lookup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index 5ee6f4ebb2..6ef0535ecb 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -37,8 +37,8 @@ static void test_paths(UnitFileScope scope) { assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); assert_se(lookup_paths_init(&lp_without_env, scope, NULL) >= 0); - assert_se(lookup_paths_reduce(&lp_without_env) >= 0); assert_se(!strv_isempty(lp_without_env.search_path)); + assert_se(lookup_paths_reduce(&lp_without_env) >= 0); systemd_unit_path = strjoina(template, "/systemd-unit-path"); assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); -- cgit v1.2.3-54-g00ecf From d8d410f4455238e30daa1775b469e31f34371f87 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 20:46:52 +0200 Subject: core: minor coding style fix --- src/core/dbus-execute.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 973a60187d..9dfca14914 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -837,9 +837,9 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { - if (isempty(uu)) { + if (isempty(uu)) c->user = mfree(c->user); - } else { + else { char *t; t = strdup(uu); @@ -864,9 +864,9 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { - if (isempty(gg)) { + if (isempty(gg)) c->group = mfree(c->group); - } else { + else { char *t; t = strdup(gg); -- cgit v1.2.3-54-g00ecf From 07a7864324e146662cb06f49fc3cd666788e2e2f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 20:47:44 +0200 Subject: core: move flushing of generated unit files to path-lookup.c It's very similar to the mkdir and trim operations for the generator dirs, hence let's unify this at a single place. --- src/core/manager.c | 16 ++-------------- src/shared/path-lookup.c | 11 +++++++++++ src/shared/path-lookup.h | 1 + 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index b1f79e014e..6ce3e404c9 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -100,7 +100,6 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32 static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata); 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 void manager_watch_jobs_in_progress(Manager *m) { usec_t next; @@ -930,7 +929,7 @@ Manager* manager_free(Manager *m) { * around */ manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE); - manager_undo_generators(m); + lookup_paths_flush_generator(&m->lookup_paths); bus_done(m); @@ -2522,7 +2521,7 @@ int manager_reload(Manager *m) { /* From here on there is no way back. */ manager_clear_jobs_and_units(m); - manager_undo_generators(m); + lookup_paths_flush_generator(&m->lookup_paths); lookup_paths_free(&m->lookup_paths); q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, NULL); @@ -2750,17 +2749,6 @@ finish: return r; } -static void manager_undo_generators(Manager *m) { - assert(m); - - if (m->lookup_paths.generator) - (void) rm_rf(m->lookup_paths.generator, REMOVE_ROOT); - if (m->lookup_paths.generator_early) - (void) rm_rf(m->lookup_paths.generator_early, REMOVE_ROOT); - if (m->lookup_paths.generator_late) - (void) rm_rf(m->lookup_paths.generator_late, REMOVE_ROOT); -} - int manager_environment_add(Manager *m, char **minus, char **plus) { char **a = NULL, **b = NULL, **l; assert(m); diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 0735e3b4f5..685ae895d2 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -726,3 +726,14 @@ void lookup_paths_trim_generator(LookupPaths *p) { if (p->generator_late) (void) rmdir(p->generator_late); } + +void lookup_paths_flush_generator(LookupPaths *p) { + assert(p); + + if (p->generator) + (void) rm_rf(p->generator, REMOVE_ROOT); + if (p->generator_early) + (void) rm_rf(p->generator_early, REMOVE_ROOT); + if (p->generator_late) + (void) rm_rf(p->generator_late, REMOVE_ROOT); +} diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 03f103dcc0..d151347a1b 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -53,6 +53,7 @@ int lookup_paths_reduce(LookupPaths *p); int lookup_paths_mkdir_generator(LookupPaths *p); void lookup_paths_trim_generator(LookupPaths *p); +void lookup_paths_flush_generator(LookupPaths *p); void lookup_paths_free(LookupPaths *p); #define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free) -- cgit v1.2.3-54-g00ecf From 9183df707bde9e83d838e7b5a05db0c5f4b55e6d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 20:48:58 +0200 Subject: install: rename generator_paths() → generator_binary_paths() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is too confusing, as this funciton returns the paths to the generator binaries, while usually when we refer to the just the "generator path" we mean the generated unit files. Let's clean this up. --- src/core/manager.c | 2 +- src/shared/path-lookup.c | 2 +- src/shared/path-lookup.h | 2 +- src/test/test-path-lookup.c | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 6ce3e404c9..91fe9c2d5b 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2715,7 +2715,7 @@ static int manager_run_generators(Manager *m) { if (m->test_run) return 0; - paths = generator_paths(m->unit_file_scope); + paths = generator_binary_paths(m->unit_file_scope); if (!paths) return log_oom(); diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 685ae895d2..d3d4243ad4 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -221,7 +221,7 @@ static char** user_dirs( return tmp; } -char **generator_paths(UnitFileScope scope) { +char **generator_binary_paths(UnitFileScope scope) { switch (scope) { diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index d151347a1b..29f74cf211 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -45,7 +45,7 @@ struct LookupPaths { char *root_dir; }; -char **generator_paths(UnitFileScope scope); +char **generator_binary_paths(UnitFileScope scope); int lookup_paths_init(LookupPaths *p, UnitFileScope scope, const char *root_dir); diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index 6ef0535ecb..ba60482867 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -51,13 +51,13 @@ static void test_paths(UnitFileScope scope) { assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -static void print_generator_paths(UnitFileScope scope) { +static void print_generator_binary_paths(UnitFileScope scope) { _cleanup_strv_free_ char **paths; char **dir; log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); - paths = generator_paths(scope); + paths = generator_binary_paths(scope); STRV_FOREACH(dir, paths) log_info(" %s", *dir); } @@ -71,8 +71,8 @@ int main(int argc, char **argv) { test_paths(UNIT_FILE_USER); test_paths(UNIT_FILE_GLOBAL); - print_generator_paths(UNIT_FILE_SYSTEM); - print_generator_paths(UNIT_FILE_USER); + print_generator_binary_paths(UNIT_FILE_SYSTEM); + print_generator_binary_paths(UNIT_FILE_USER); return EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf From 80b1ae32e1cab924086bb5224cde675df623df07 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 6 Apr 2016 21:02:36 +0200 Subject: core: introduce a "control" unit file directory This patch adds a concept of a "control" unit file directory, which is supposed to be used as place for unit file drop-ins created by "systemctl set-property" (note that this directory is not actually hooked up to "systemctl set-property" yet, that's coming in a later patch). The rationale for this: previously changes made by the user and by "systemctl set-property" were done in the same directory, which made semantics very unclear: the changes made by "systemctl set-property" were applied instantly, and their drop-ins only written to not lose settings on a later "systemctl daemon-reload", while drop-ins made by the user would only be in effect after "systemctl daemon-reload". This is particular problematic as the changes made by "systemctl set-property" would really apply immediately without any respect for the unit search path. This meant that using "set-property" could have an effect that is lsot as soon as "daemon-reload" is issued, in case there was a "later" drop-in already in place. With this change the directories are seperated, and the "control" directory always takes the highest priority of all, to avoid any confusion. --- src/shared/path-lookup.c | 168 ++++++++++++++++++++++++++++++++++------------- src/shared/path-lookup.h | 19 +++++- 2 files changed, 139 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index d3d4243ad4..68b432216e 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -29,51 +29,50 @@ #include "mkdir.h" #include "path-lookup.h" #include "path-util.h" +#include "rm-rf.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" #include "util.h" -static int user_config_home(char **ret) { +static int user_runtime_dir(char **ret, const char *suffix) { const char *e; char *j; assert(ret); + assert(suffix); - e = getenv("XDG_CONFIG_HOME"); - if (e) { - j = strappend(e, "/systemd/user"); - if (!j) - return -ENOMEM; - - } else { - const char *home; - - home = getenv("HOME"); - if (!home) - return -ENXIO; + e = getenv("XDG_RUNTIME_DIR"); + if (!e) + return -ENXIO; - j = strappend(home, "/.config/systemd/user"); - if (!j) - return -ENOMEM; - } + j = strappend(e, suffix); + if (!j) + return -ENOMEM; *ret = j; return 0; } -static int user_runtime_dir(char **ret, const char *suffix) { +static int user_config_dir(char **ret, const char *suffix) { const char *e; char *j; assert(ret); - assert(suffix); - e = getenv("XDG_RUNTIME_DIR"); - if (!e) - return -ENXIO; + e = getenv("XDG_CONFIG_HOME"); + if (e) + j = strappend(e, suffix); + else { + const char *home; + + home = getenv("HOME"); + if (!home) + return -ENXIO; + + j = strjoin(home, "/.config", suffix, NULL); + } - j = strappend(e, suffix); if (!j) return -ENOMEM; @@ -81,7 +80,7 @@ static int user_runtime_dir(char **ret, const char *suffix) { return 0; } -static int user_data_home_dir(char **ret, const char *suffix) { +static int user_data_dir(char **ret, const char *suffix) { const char *e; char *j; @@ -118,7 +117,9 @@ static char** user_dirs( const char *generator, const char *generator_early, const char *generator_late, - const char *transient) { + const char *transient, + const char *persistent_control, + const char *runtime_control) { const char * const config_unit_paths[] = { USER_CONFIG_UNIT_PATH, @@ -158,7 +159,7 @@ static char** user_dirs( return NULL; } - r = user_data_home_dir(&data_home, "/systemd/user"); + r = user_data_dir(&data_home, "/systemd/user"); if (r < 0 && r != -ENXIO) return NULL; @@ -173,13 +174,17 @@ static char** user_dirs( return NULL; /* Now merge everything we found. */ - if (transient) - if (strv_extend(&res, transient) < 0) - return NULL; + if (strv_extend(&res, persistent_control) < 0) + return NULL; - if (generator_early) - if (strv_extend(&res, generator_early) < 0) - return NULL; + if (strv_extend(&res, runtime_control) < 0) + return NULL; + + if (strv_extend(&res, transient) < 0) + return NULL; + + if (strv_extend(&res, generator_early) < 0) + return NULL; if (!strv_isempty(config_dirs)) if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0) @@ -194,13 +199,11 @@ static char** user_dirs( if (strv_extend(&res, runtime_config) < 0) return NULL; - if (generator) - if (strv_extend(&res, generator) < 0) - return NULL; + if (strv_extend(&res, generator) < 0) + return NULL; - if (data_home) - if (strv_extend(&res, data_home) < 0) - return NULL; + if (strv_extend(&res, data_home) < 0) + return NULL; if (!strv_isempty(data_dirs)) if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0) @@ -209,9 +212,8 @@ static char** user_dirs( if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0) return NULL; - if (generator_late) - if (strv_extend(&res, generator_late) < 0) - return NULL; + if (strv_extend(&res, generator_late) < 0) + return NULL; if (path_strv_make_absolute_cwd(res) < 0) return NULL; @@ -327,7 +329,6 @@ static int acquire_transient_dir(UnitFileScope scope, char **ret) { default: assert_not_reached("Hmm, unexpected scope value."); } - } static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) { @@ -350,7 +351,7 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru break; case UNIT_FILE_USER: - r = user_config_home(&a); + r = user_config_dir(&a, "/systemd/user"); if (r < 0) return r; @@ -377,6 +378,56 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru return 0; } +static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) { + _cleanup_free_ char *a = NULL; + int r; + + assert(persistent); + assert(runtime); + + switch (scope) { + + case UNIT_FILE_SYSTEM: { + _cleanup_free_ char *b = NULL; + + a = strdup("/etc/systemd/system.control"); + if (!a) + return -ENOMEM; + + b = strdup("/run/systemd/system.control"); + if (!b) + return -ENOMEM; + + *runtime = b; + b = NULL; + + break; + } + + case UNIT_FILE_USER: + r = user_config_dir(&a, "/systemd/system.control"); + if (r < 0) + return r; + + r = user_runtime_dir(runtime, "/systemd/system.control"); + if (r < 0) + return r; + + break; + + case UNIT_FILE_GLOBAL: + return -EOPNOTSUPP; + + default: + assert_not_reached("Hmm, unexpected scope value."); + } + + *persistent = a; + a = NULL; + + return 0; +} + static int patch_root_prefix(char **p, const char *root_dir) { char *c; @@ -420,7 +471,8 @@ int lookup_paths_init( *root = NULL, *persistent_config = NULL, *runtime_config = NULL, *generator = NULL, *generator_early = NULL, *generator_late = NULL, - *transient = NULL; + *transient = NULL, + *persistent_control = NULL, *runtime_control = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ char **l = NULL; const char *e; @@ -457,6 +509,10 @@ int lookup_paths_init( if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) return r; + r = acquire_control_dirs(scope, &persistent_control, &runtime_control); + if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) + return r; + /* First priority is whatever has been passed to us via env vars */ e = getenv("SYSTEMD_UNIT_PATH"); if (e) { @@ -494,6 +550,8 @@ int lookup_paths_init( add = strv_new( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ + STRV_IFNOTNULL(persistent_control), + STRV_IFNOTNULL(runtime_control), STRV_IFNOTNULL(transient), STRV_IFNOTNULL(generator_early), persistent_config, @@ -517,6 +575,8 @@ int lookup_paths_init( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and * the arrays in user_dirs() above! */ + STRV_IFNOTNULL(persistent_control), + STRV_IFNOTNULL(runtime_control), STRV_IFNOTNULL(transient), STRV_IFNOTNULL(generator_early), persistent_config, @@ -537,7 +597,8 @@ int lookup_paths_init( case UNIT_FILE_USER: add = user_dirs(persistent_config, runtime_config, generator, generator_early, generator_late, - transient); + transient, + persistent_config, runtime_control); break; default: @@ -578,6 +639,14 @@ int lookup_paths_init( if (r < 0) return r; + r = patch_root_prefix(&persistent_control, root); + if (r < 0) + return r; + + r = patch_root_prefix(&runtime_control, root); + if (r < 0) + return r; + r = patch_root_prefix_strv(l, root); if (r < 0) return -ENOMEM; @@ -597,6 +666,10 @@ int lookup_paths_init( p->transient = transient; transient = NULL; + p->persistent_control = persistent_control; + p->runtime_control = runtime_control; + persistent_control = runtime_control = NULL; + p->root_dir = root; root = NULL; @@ -618,6 +691,9 @@ void lookup_paths_free(LookupPaths *p) { p->transient = mfree(p->transient); + p->persistent_control = mfree(p->persistent_control); + p->runtime_control = mfree(p->runtime_control); + p->root_dir = mfree(p->root_dir); } @@ -730,6 +806,8 @@ void lookup_paths_trim_generator(LookupPaths *p) { void lookup_paths_flush_generator(LookupPaths *p) { assert(p); + /* Flush the generated unit files in full */ + if (p->generator) (void) rm_rf(p->generator, REMOVE_ROOT); if (p->generator_early) diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 29f74cf211..89254cbac5 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -27,20 +27,33 @@ typedef struct LookupPaths LookupPaths; #include "macro.h" struct LookupPaths { + /* Where we look for unit files. This includes the individual special paths below, but also any vendor + * supplied, static unit file paths. */ char **search_path; - /* Where we shall create or remove our installation symlinks, aka "configuration". */ + /* Where we shall create or remove our installation symlinks, aka "configuration", and where the user/admin + * shall place his own unit files. */ char *persistent_config; char *runtime_config; - /* Where to place generated unit files */ + /* Where to place generated unit files (i.e. those a "generator" tool generated). Note the special semantics of + * this directory: the generators are flushed each time a "systemctl daemon-reload" is issued. The user should + * not alter these directories directly. */ char *generator; char *generator_early; char *generator_late; - /* Where to place transient unit files */ + /* Where to place transient unit files (i.e. those created dynamically via the bus API). Note the special + * semantics of this directory: all units created transiently have their unit files removed as the transient + * unit is unloaded. The user should not alter this directory directly. */ char *transient; + /* Where the snippets created by "systemctl set-property" are placed. Note that for transient units, the + * snippets are placed in the transient directory though (see above). The user should not alter this directory + * directly. */ + char *persistent_control; + char *runtime_control; + /* The root directory prepended to all items above, or NULL */ char *root_dir; }; -- cgit v1.2.3-54-g00ecf From 4f4afc88ecd8ab9cfe9e1eeea7e3aeb937811937 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 15:43:59 +0200 Subject: core: rework how transient unit files and property drop-ins work With this change the logic for placing transient unit files and drop-ins generated via "systemctl set-property" is reworked. The latter are now placed in the newly introduced "control" unit file directory. The fomer are now placed in the "transient" unit file directory. Note that the properties originally set when a transient unit was created will be written to and stay in the transient unit file directory, while later changes are done via drop-ins. This is preparation for a later "systemctl revert" addition, where existing drop-ins are flushed out, but the original transient definition is restored. --- src/basic/strv.c | 36 +++++++++++++++++++++++++++++++++ src/basic/strv.h | 1 + src/core/scope.c | 25 ++++++++++++----------- src/core/slice.c | 1 + src/core/unit.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++------ src/core/unit.h | 3 +++ 6 files changed, 109 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/basic/strv.c b/src/basic/strv.c index 8282298dca..97a96e5762 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -558,6 +558,42 @@ int strv_extend(char ***l, const char *value) { return strv_consume(l, v); } +int strv_extend_front(char ***l, const char *value) { + size_t n, m; + char *v, **c; + + assert(l); + + /* Like strv_extend(), but prepends rather than appends the new entry */ + + if (!value) + return 0; + + n = strv_length(*l); + + /* Increase and overflow check. */ + m = n + 2; + if (m < n) + return -ENOMEM; + + v = strdup(value); + if (!v) + return -ENOMEM; + + c = realloc_multiply(*l, sizeof(char*), m); + if (!c) { + free(v); + return -ENOMEM; + } + + memmove(c+1, c, n * sizeof(char*)); + c[0] = v; + c[n+1] = NULL; + + *l = c; + return 0; +} + char **strv_uniq(char **l) { char **i; diff --git a/src/basic/strv.h b/src/basic/strv.h index 7bfa54408d..f61bbb5386 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -50,6 +50,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char **b, const char *suffix); int strv_extend(char ***l, const char *value); int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); +int strv_extend_front(char ***l, const char *value); int strv_push(char ***l, char *value); int strv_push_pair(char ***l, char *a, char *b); int strv_push_prepend(char ***l, char *value); diff --git a/src/core/scope.c b/src/core/scope.c index 92a3aed331..7078d1f7e9 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -155,25 +155,26 @@ static int scope_load(Unit *u) { assert(u->load_state == UNIT_STUB); if (!u->transient && !MANAGER_IS_RELOADING(u->manager)) + /* Refuse to load non-transient scope units, but allow them while reloading. */ return -ENOENT; - u->load_state = UNIT_LOADED; - - r = unit_load_dropin(u); + r = unit_load_fragment_and_dropin_optional(u); if (r < 0) return r; - r = unit_patch_contexts(u); - if (r < 0) - return r; + if (u->load_state == UNIT_LOADED) { + r = unit_patch_contexts(u); + if (r < 0) + return r; - r = unit_set_default_slice(u); - if (r < 0) - return r; + r = unit_set_default_slice(u); + if (r < 0) + return r; - r = scope_add_default_dependencies(s); - if (r < 0) - return r; + r = scope_add_default_dependencies(s); + if (r < 0) + return r; + } return scope_verify(s); } diff --git a/src/core/slice.c b/src/core/slice.c index 667f61bde5..63a77c9bca 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -135,6 +135,7 @@ static int slice_load(Unit *u) { int r; assert(s); + assert(u->load_state == UNIT_STUB); r = unit_load_fragment_and_dropin_optional(u); if (r < 0) diff --git a/src/core/unit.c b/src/core/unit.c index ac29353299..c028f57f13 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -52,6 +52,7 @@ #include "stdio-util.h" #include "string-util.h" #include "strv.h" +#include "umask-util.h" #include "unit-name.h" #include "unit.h" #include "user-util.h" @@ -492,6 +493,9 @@ void unit_free(Unit *u) { assert(u); + if (u->transient_file) + fclose(u->transient_file); + if (!MANAGER_IS_RELOADING(u->manager)) unit_remove_transient(u); @@ -1231,6 +1235,15 @@ int unit_load(Unit *u) { if (u->load_state != UNIT_STUB) return 0; + if (u->transient_file) { + r = fflush_and_check(u->transient_file); + if (r < 0) + goto fail; + + fclose(u->transient_file); + u->transient_file = NULL; + } + if (UNIT_VTABLE(u)->load) { r = UNIT_VTABLE(u)->load(u); if (r < 0) @@ -3327,14 +3340,17 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) { static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) { assert(u); + if (!IN_SET(mode, UNIT_RUNTIME, UNIT_PERSISTENT)) + return NULL; + if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */ return u->manager->lookup_paths.transient; if (mode == UNIT_RUNTIME) - return u->manager->lookup_paths.runtime_config; + return u->manager->lookup_paths.runtime_control; if (mode == UNIT_PERSISTENT) - return u->manager->lookup_paths.persistent_config; + return u->manager->lookup_paths.persistent_control; return NULL; } @@ -3346,6 +3362,13 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co assert(u); + if (u->transient_file) { + /* When this is a transient unit file in creation, then let's not create a new drop-in but instead + * write to the transient unit file. */ + fputs(data, u->transient_file); + return 0; + } + if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) return 0; @@ -3435,24 +3458,50 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const } int unit_make_transient(Unit *u) { + FILE *f; + char *path; + assert(u); if (!UNIT_VTABLE(u)->can_transient) return -EOPNOTSUPP; - u->load_state = UNIT_STUB; - u->load_error = 0; - u->transient = true; + path = strjoin(u->manager->lookup_paths.transient, "/", u->id, NULL); + if (!path) + return -ENOMEM; + + /* Let's open the file we'll write the transient settings into. This file is kept open as long as we are + * creating the transient, and is closed in unit_load(), as soon as we start loading the file. */ + + RUN_WITH_UMASK(0022) + f = fopen(path, "we"); + if (!f) { + free(path); + return -errno; + } + + if (u->transient_file) + fclose(u->transient_file); + u->transient_file = f; + + free(u->fragment_path); + u->fragment_path = path; - u->fragment_path = mfree(u->fragment_path); u->source_path = mfree(u->source_path); u->dropin_paths = strv_free(u->dropin_paths); u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0; + u->load_state = UNIT_STUB; + u->load_error = 0; + u->transient = true; + unit_add_to_dbus_queue(u); unit_add_to_gc_queue(u); unit_add_to_load_queue(u); + fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n", + u->transient_file); + return 0; } diff --git a/src/core/unit.h b/src/core/unit.h index 601e763ce2..cfdac852a5 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -95,6 +95,9 @@ struct Unit { usec_t source_mtime; usec_t dropin_mtime; + /* If this is a transient unit we are currently writing, this is where we are writing it to */ + FILE *transient_file; + /* If there is something to do with this unit, then this is the installed job for it */ Job *job; -- cgit v1.2.3-54-g00ecf From 8612da973d30c5a9530fa1b6b3d449147b5a3324 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 16:15:26 +0200 Subject: core: be more paranoid when mixing umask and fopen() Let's be extra careful with the umask when we use simple fopen(), as this creates files with 0777 by default. --- src/basic/util.c | 4 +++- src/core/machine-id-setup.c | 3 +-- src/core/main.c | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/basic/util.c b/src/basic/util.c index f1e3bd5b48..6996527ec4 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -55,6 +55,7 @@ #include "string-util.h" #include "strv.h" #include "time-util.h" +#include "umask-util.h" #include "user-util.h" #include "util.h" @@ -781,7 +782,8 @@ int update_reboot_param_file(const char *param) { int r = 0; if (param) { - r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); + RUN_WITH_UMASK(0022) + r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); if (r < 0) return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m"); } else diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 7b25349c07..86da16c31e 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -259,9 +259,8 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) { /* Hmm, we couldn't write it? So let's write it to * /run/machine-id as a replacement */ - RUN_WITH_UMASK(0022) { + RUN_WITH_UMASK(0022) r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE); - } if (r < 0) { (void) unlink(run_machine_id); return log_error_errno(r, "Cannot write %s: %m", run_machine_id); diff --git a/src/core/main.c b/src/core/main.c index a428e345e0..2912608435 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -81,6 +81,7 @@ #include "strv.h" #include "switch-root.h" #include "terminal-util.h" +#include "umask-util.h" #include "user-util.h" #include "virt.h" #include "watchdog.h" @@ -1237,7 +1238,8 @@ static int write_container_id(void) { if (isempty(c)) return 0; - r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE); + RUN_WITH_UMASK(0022) + r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE); if (r < 0) return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m"); -- cgit v1.2.3-54-g00ecf From 27c06cb516c3b87c34f2a1c2c227152997d05c8c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 16:53:37 +0200 Subject: core: rework reboot parameter logic a bit Always warn if something fails, and clarify that the involved utility functions do so in their name. Drop the REBOOT_PARAM_FILE macro. We don't do this for other flag file paths like this, so don't do this for this one either. The path isn't configurable anyway, hence let's make this easier to read by avoiding this one indirection. --- src/basic/def.h | 2 -- src/basic/util.c | 26 +++++++++++++++++--------- src/basic/util.h | 2 +- src/core/failure-action.c | 14 +++++++------- src/core/shutdown.c | 7 ++++++- src/systemctl/systemctl.c | 12 +++++++++--- 6 files changed, 40 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/basic/def.h b/src/basic/def.h index 963343eb7d..1a7a0f4928 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -41,8 +41,6 @@ #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT #define SIGNALS_IGNORE SIGPIPE -#define REBOOT_PARAM_FILE "/run/systemd/reboot-param" - #ifdef HAVE_SPLIT_USR #define KBD_KEYMAP_DIRS \ "/usr/share/keymaps/\0" \ diff --git a/src/basic/util.c b/src/basic/util.c index 6996527ec4..957b0e1ff1 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -778,16 +778,24 @@ uint64_t physical_memory(void) { return (uint64_t) mem * (uint64_t) page_size(); } -int update_reboot_param_file(const char *param) { - int r = 0; +int update_reboot_parameter_and_warn(const char *param) { + int r; - if (param) { - RUN_WITH_UMASK(0022) - r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); - if (r < 0) - return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m"); - } else - (void) unlink(REBOOT_PARAM_FILE); + if (isempty(param)) { + if (unlink("/run/systemd/reboot-param") < 0) { + if (errno == ENOENT) + return 0; + + return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m"); + } + + return 0; + } + + RUN_WITH_UMASK(0022) + r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE); + if (r < 0) + return log_warning_errno(r, "Failed to write reboot parameter file: %m"); return 0; } diff --git a/src/basic/util.h b/src/basic/util.h index 286db05159..1c032c15c9 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -184,6 +184,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int uint64_t physical_memory(void); -int update_reboot_param_file(const char *param); +int update_reboot_parameter_and_warn(const char *param); int version(void); diff --git a/src/core/failure-action.c b/src/core/failure-action.c index d4aae4b6e7..ddae46190f 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -61,17 +61,17 @@ int failure_action( case FAILURE_ACTION_REBOOT: log_and_status(m, "Rebooting as result of failure."); - update_reboot_param_file(reboot_arg); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, - JOB_REPLACE_IRREVERSIBLY, NULL); + (void) update_reboot_parameter_and_warn(reboot_arg); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL); break; case FAILURE_ACTION_REBOOT_FORCE: log_and_status(m, "Forcibly rebooting as result of failure."); - update_reboot_param_file(reboot_arg); + (void) update_reboot_parameter_and_warn(reboot_arg); m->exit_code = MANAGER_REBOOT; + break; case FAILURE_ACTION_REBOOT_IMMEDIATE: @@ -79,9 +79,10 @@ int failure_action( sync(); - if (reboot_arg) { + if (!isempty(reboot_arg)) { log_info("Rebooting with argument '%s'.", reboot_arg); syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reboot_arg); + log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); } log_info("Rebooting."); @@ -90,8 +91,7 @@ int failure_action( case FAILURE_ACTION_POWEROFF: log_and_status(m, "Powering off as result of failure."); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, - JOB_REPLACE_IRREVERSIBLY, NULL); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL); break; case FAILURE_ACTION_POWEROFF_FORCE: diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 96679c920f..e14755d84e 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -397,9 +397,14 @@ int main(int argc, char *argv[]) { if (!in_container) { _cleanup_free_ char *param = NULL; - if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { + r = read_one_line_file("/run/systemd/reboot-param", ¶m); + if (r < 0) + log_warning_errno(r, "Failed to read reboot parameter file: %m"); + + if (!isempty(param)) { log_info("Rebooting with argument '%s'.", param); syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); + log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); } } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b64a97375e..b1c4a84eff 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3136,7 +3136,7 @@ static int start_special(int argc, char *argv[], void *userdata) { return r; if (a == ACTION_REBOOT && argc > 1) { - r = update_reboot_param_file(argv[1]); + r = update_reboot_parameter_and_warn(argv[1]); if (r < 0) return r; @@ -6949,7 +6949,7 @@ static int halt_parse_argv(int argc, char *argv[]) { } if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) { - r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL); + r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL); if (r < 0) return r; } else if (optind < argc) { @@ -7450,6 +7450,7 @@ static int start_with_fallback(void) { } static int halt_now(enum action a) { + int r; /* The kernel will automaticall flush ATA disks and suchlike * on reboot(), but the file systems need to be synce'd @@ -7476,9 +7477,14 @@ static int halt_now(enum action a) { case ACTION_REBOOT: { _cleanup_free_ char *param = NULL; - if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { + r = read_one_line_file("/run/systemd/reboot-param", ¶m); + if (r < 0) + log_warning_errno(r, "Failed to read reboot parameter file: %m"); + + if (!isempty(param)) { log_info("Rebooting with argument '%s'.", param); (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); + log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); } log_info("Rebooting."); -- cgit v1.2.3-54-g00ecf From e735decc38fd60921c8d8c0345d01fd4ed874677 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 17:40:11 +0200 Subject: systemctl: move check whether a service exists as native unit file to install.c Move the search path check from the SysV service compat support into install.c so that we can reuse the usual algorithm instead of rolling a private loop for this. --- src/shared/install.c | 19 ++++++++++++++++++ src/shared/install.h | 1 + src/systemctl/systemctl.c | 50 +++++++++++++++++++++++------------------------ 3 files changed, 44 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index f78cc814e5..b5453adeee 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2052,6 +2052,25 @@ int unit_file_get_state( return unit_file_lookup_state(scope, &paths, name, ret); } +int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) { + _cleanup_(install_context_done) InstallContext c = {}; + int r; + + assert(paths); + assert(name); + + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + + r = install_info_discover(scope, &c, paths, name, 0, NULL); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; + + return 1; +} + int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { _cleanup_strv_free_ char **files = NULL; char **p; diff --git a/src/shared/install.h b/src/shared/install.h index 578664dd48..c57c23934b 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -139,6 +139,7 @@ int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); +int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name); int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); Hashmap* unit_file_list_free(Hashmap *h); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b1c4a84eff..da2715810e 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5223,8 +5223,10 @@ static int enable_sysv_units(const char *verb, char **args) { int r = 0; #if defined(HAVE_SYSV_COMPAT) - unsigned f = 0; _cleanup_lookup_paths_free_ LookupPaths paths = {}; + unsigned f = 0; + + /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */ if (arg_scope != UNIT_FILE_SYSTEM) return 0; @@ -5238,24 +5240,28 @@ static int enable_sysv_units(const char *verb, char **args) { "is-enabled")) return 0; - /* Processes all SysV units, and reshuffles the array so that - * afterwards only the native units remain */ - r = lookup_paths_init(&paths, arg_scope, arg_root); if (r < 0) return r; r = 0; while (args[f]) { - const char *name; + + const char *argv[] = { + ROOTLIBEXECDIR "/systemd-sysv-install", + NULL, + NULL, + NULL, + NULL, + }; + _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL; bool found_native = false, found_sysv; + siginfo_t status; + const char *name; unsigned c = 1; - const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL }; - char **k; - int j; pid_t pid; - siginfo_t status; + int j; name = args[f++]; @@ -5265,21 +5271,13 @@ static int enable_sysv_units(const char *verb, char **args) { if (path_is_absolute(name)) continue; - STRV_FOREACH(k, paths.search_path) { - _cleanup_free_ char *path = NULL; - - path = path_join(arg_root, *k, name); - if (!path) - return log_oom(); - - found_native = access(path, F_OK) >= 0; - if (found_native) - break; - } + j = unit_file_exists(arg_scope, &paths, name); + if (j < 0) + return log_error_errno(j, "Failed to lookup unit file state: %m"); + found_native = j > 0; - /* If we have both a native unit and a SysV script, - * enable/disable them both (below); for is-enabled, prefer the - * native unit */ + /* 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; @@ -5293,9 +5291,9 @@ static int enable_sysv_units(const char *verb, char **args) { continue; if (found_native) - log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]); + log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]); else - log_info("%s is not a native service, redirecting to systemd-sysv-install", name); + 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); @@ -5308,7 +5306,7 @@ static int enable_sysv_units(const char *verb, char **args) { if (!l) return log_oom(); - log_info("Executing %s", l); + log_info("Executing: %s", l); pid = fork(); if (pid < 0) -- cgit v1.2.3-54-g00ecf From cc7cb0ca905157606d8f2827a813ca028d474125 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 17:41:35 +0200 Subject: systemctl: fix incorrect errno for error message --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index da2715810e..d3e9ccfbd5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5318,7 +5318,7 @@ static int enable_sysv_units(const char *verb, char **args) { (void) reset_signal_mask(); execv(argv[0], (char**) argv); - log_error_errno(r, "Failed to execute %s: %m", argv[0]); + log_error_errno(errno, "Failed to execute %s: %m", argv[0]); _exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From c61b443d32ceea2d0a8c46c1d61a9314f1affa89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 17:41:48 +0200 Subject: systemctl: add error message when we get unexpected event from waitid() We should log about everything we don't expect. Also, add a comment for one case were we do not log, on purpose, and make it use a separate error code. --- src/systemctl/systemctl.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d3e9ccfbd5..7c259ba06f 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5340,9 +5340,11 @@ static int enable_sysv_units(const char *verb, char **args) { } } else if (status.si_status != 0) - return -EINVAL; - } else + return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */ + } else { + log_error("Unexpected waitid() result."); return -EPROTO; + } if (found_native) continue; @@ -5413,8 +5415,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { if (r < 0) return r; - /* If the operation was fully executed by the SysV compat, - * let's finish early */ + /* If the operation was fully executed by the SysV compat, let's finish early */ if (strv_isempty(names)) return 0; -- cgit v1.2.3-54-g00ecf From a69b4fb0f80689b96f492a557368ed880365edee Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 17:51:26 +0200 Subject: path-lookup: move generator_binary_paths() to end of file Let's keep the code that manipulates LookupPaths together, and move generator_binary_paths() to the end of the .h and .c files, since it is not strictly related to that. --- src/shared/path-lookup.c | 48 ++++++++++++++++++++++++------------------------ src/shared/path-lookup.h | 4 ++-- 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 68b432216e..1c8e22eee7 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -223,30 +223,6 @@ static char** user_dirs( return tmp; } -char **generator_binary_paths(UnitFileScope scope) { - - switch (scope) { - - case UNIT_FILE_SYSTEM: - return strv_new("/run/systemd/system-generators", - "/etc/systemd/system-generators", - "/usr/local/lib/systemd/system-generators", - SYSTEM_GENERATOR_PATH, - NULL); - - case UNIT_FILE_GLOBAL: - case UNIT_FILE_USER: - return strv_new("/run/systemd/user-generators", - "/etc/systemd/user-generators", - "/usr/local/lib/systemd/user-generators", - USER_GENERATOR_PATH, - NULL); - - default: - assert_not_reached("Hmm, unexpected scope."); - } -} - static int acquire_generator_dirs( UnitFileScope scope, char **generator, @@ -815,3 +791,27 @@ void lookup_paths_flush_generator(LookupPaths *p) { if (p->generator_late) (void) rm_rf(p->generator_late, REMOVE_ROOT); } + +char **generator_binary_paths(UnitFileScope scope) { + + switch (scope) { + + case UNIT_FILE_SYSTEM: + return strv_new("/run/systemd/system-generators", + "/etc/systemd/system-generators", + "/usr/local/lib/systemd/system-generators", + SYSTEM_GENERATOR_PATH, + NULL); + + case UNIT_FILE_GLOBAL: + case UNIT_FILE_USER: + return strv_new("/run/systemd/user-generators", + "/etc/systemd/user-generators", + "/usr/local/lib/systemd/user-generators", + USER_GENERATOR_PATH, + NULL); + + default: + assert_not_reached("Hmm, unexpected scope."); + } +} diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index 89254cbac5..ad05c0c537 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -58,8 +58,6 @@ struct LookupPaths { char *root_dir; }; -char **generator_binary_paths(UnitFileScope scope); - int lookup_paths_init(LookupPaths *p, UnitFileScope scope, const char *root_dir); int lookup_paths_reduce(LookupPaths *p); @@ -70,3 +68,5 @@ void lookup_paths_flush_generator(LookupPaths *p); void lookup_paths_free(LookupPaths *p); #define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free) + +char **generator_binary_paths(UnitFileScope scope); -- cgit v1.2.3-54-g00ecf From 4943d14306c3e456525fdb793e7f48efea5b9236 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 18:48:01 +0200 Subject: systemctl: don't confuse sysv code with generated units The SysV compat code checks whether there's a native unit file before looking for a SysV init script. Since the newest rework generated units will show up in the unit path, and hence the checks ended up assuming that there always was a native unit file for each init script: the generated one. With this change the generated unit file directory is suppressed from the search path when this check is done, to avoid the confusion. --- src/core/manager.c | 4 ++-- src/shared/install.c | 24 ++++++++++++------------ src/shared/path-lookup.c | 14 +++++++++----- src/shared/path-lookup.h | 6 +++++- src/systemctl/systemctl.c | 6 +++--- src/sysv-generator/sysv-generator.c | 2 +- src/test/test-path-lookup.c | 4 ++-- 7 files changed, 34 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/core/manager.c b/src/core/manager.c index 91fe9c2d5b..5601770670 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1097,7 +1097,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { assert(m); - r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, NULL); + r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL); if (r < 0) return r; @@ -2524,7 +2524,7 @@ int manager_reload(Manager *m) { lookup_paths_flush_generator(&m->lookup_paths); lookup_paths_free(&m->lookup_paths); - q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, NULL); + q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL); if (q < 0 && r >= 0) r = q; diff --git a/src/shared/install.c b/src/shared/install.c index b5453adeee..7497a39219 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1507,7 +1507,7 @@ int unit_file_mask( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -1554,7 +1554,7 @@ int unit_file_unmask( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -1636,7 +1636,7 @@ int unit_file_link( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -1727,7 +1727,7 @@ int unit_file_add_dependency( if (!unit_name_is_valid(target, UNIT_NAME_ANY)) return -EINVAL; - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -1791,7 +1791,7 @@ int unit_file_enable( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -1834,7 +1834,7 @@ int unit_file_disable( assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -1907,7 +1907,7 @@ int unit_file_set_default( if (streq(name, SPECIAL_DEFAULT_TARGET)) return -EINVAL; - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -1939,7 +1939,7 @@ int unit_file_get_default( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -2045,7 +2045,7 @@ int unit_file_get_state( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -2255,7 +2255,7 @@ int unit_file_preset( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -2292,7 +2292,7 @@ int unit_file_preset_all( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; @@ -2361,7 +2361,7 @@ int unit_file_get_list( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(h); - r = lookup_paths_init(&paths, scope, root_dir); + r = lookup_paths_init(&paths, scope, 0, root_dir); if (r < 0) return r; diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 1c8e22eee7..ca69a0aef2 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -441,6 +441,7 @@ static int patch_root_prefix_strv(char **l, const char *root_dir) { int lookup_paths_init( LookupPaths *p, UnitFileScope scope, + LookupPathsFlags flags, const char *root_dir) { _cleanup_free_ char @@ -477,9 +478,11 @@ int lookup_paths_init( if (r < 0 && r != -ENXIO) return r; - r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late); - if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) - return r; + if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) { + r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late); + if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) + return r; + } r = acquire_transient_dir(scope, &transient); if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO) @@ -751,6 +754,9 @@ int lookup_paths_mkdir_generator(LookupPaths *p) { assert(p); + if (!p->generator || !p->generator_early || !p->generator_late) + return -EINVAL; + r = mkdir_p_label(p->generator, 0755); q = mkdir_p_label(p->generator_early, 0755); @@ -771,10 +777,8 @@ void lookup_paths_trim_generator(LookupPaths *p) { if (p->generator) (void) rmdir(p->generator); - if (p->generator_early) (void) rmdir(p->generator_early); - if (p->generator_late) (void) rmdir(p->generator_late); } diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index ad05c0c537..f9bb2fe237 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -26,6 +26,10 @@ typedef struct LookupPaths LookupPaths; #include "install.h" #include "macro.h" +typedef enum LookupPathsFlags { + LOOKUP_PATHS_EXCLUDE_GENERATED = 1, +} LookupPathsFlags; + struct LookupPaths { /* Where we look for unit files. This includes the individual special paths below, but also any vendor * supplied, static unit file paths. */ @@ -58,7 +62,7 @@ struct LookupPaths { char *root_dir; }; -int lookup_paths_init(LookupPaths *p, UnitFileScope scope, const char *root_dir); +int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir); int lookup_paths_reduce(LookupPaths *p); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 7c259ba06f..3344d25f77 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4810,7 +4810,7 @@ static int cat(int argc, char *argv[], void *userdata) { return -EINVAL; } - r = lookup_paths_init(&lp, arg_scope, arg_root); + r = lookup_paths_init(&lp, arg_scope, 0, arg_root); if (r < 0) return log_error_errno(r, "Failed to determine unit paths: %m"); @@ -5240,7 +5240,7 @@ static int enable_sysv_units(const char *verb, char **args) { "is-enabled")) return 0; - r = lookup_paths_init(&paths, arg_scope, arg_root); + r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root); if (r < 0) return r; @@ -6073,7 +6073,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { assert(names); assert(paths); - r = lookup_paths_init(&lp, arg_scope, arg_root); + r = lookup_paths_init(&lp, arg_scope, 0, arg_root); if (r < 0) return r; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index fb7c47e1c8..e44304c16a 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -1004,7 +1004,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, NULL); + r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL); if (r < 0) { log_error_errno(r, "Failed to find lookup paths: %m"); goto finish; diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index ba60482867..096326d176 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -36,13 +36,13 @@ static void test_paths(UnitFileScope scope) { assert_se(mkdtemp(template)); assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); - assert_se(lookup_paths_init(&lp_without_env, scope, NULL) >= 0); + assert_se(lookup_paths_init(&lp_without_env, scope, 0, NULL) >= 0); assert_se(!strv_isempty(lp_without_env.search_path)); assert_se(lookup_paths_reduce(&lp_without_env) >= 0); systemd_unit_path = strjoina(template, "/systemd-unit-path"); assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); - assert_se(lookup_paths_init(&lp_with_env, scope, NULL) == 0); + assert_se(lookup_paths_init(&lp_with_env, scope, 0, NULL) == 0); assert_se(strv_length(lp_with_env.search_path) == 1); assert_se(streq(lp_with_env.search_path[0], systemd_unit_path)); assert_se(lookup_paths_reduce(&lp_with_env) >= 0); -- cgit v1.2.3-54-g00ecf From 5ae87056e3dc1162c2088daf0cb5affb0480ae54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 19:18:59 +0200 Subject: sysv-generator: port to use new unit_file_exists() call The code previously queries the state of a unit file, but was only interested in the existance of it, hence let's use unit_file_exists() instead, the same way the SysV compat code in systemctl does it. --- src/sysv-generator/sysv-generator.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index e44304c16a..cae920eb3b 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -806,11 +806,11 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { if (hashmap_contains(all_services, name)) continue; - r = unit_file_lookup_state(UNIT_FILE_SYSTEM, lp, name, NULL); - if (r < 0 && r != -ENOENT) { + r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name); + if (r < 0) { log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); continue; - } else if (r >= 0) { + } else if (r > 0) { log_debug("Native unit for %s already exists, skipping.", name); continue; } -- cgit v1.2.3-54-g00ecf From 4c310c073aec5a31a7e626ea8ceb86d3a28291aa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 7 Apr 2016 19:22:24 +0200 Subject: basic: remove rbtree code, it's unused it's unused, and should we need it one day we can always resurrect it from git history. --- .gitignore | 1 - Makefile.am | 9 - src/basic/c-rbtree.c | 674 ------------------------------------------------- src/basic/c-rbtree.h | 297 ---------------------- src/test/test-rbtree.c | 362 -------------------------- 5 files changed, 1343 deletions(-) delete mode 100644 src/basic/c-rbtree.c delete mode 100644 src/basic/c-rbtree.h delete mode 100644 src/test/test-rbtree.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 403c16c339..02ba86ef6f 100644 --- a/.gitignore +++ b/.gitignore @@ -249,7 +249,6 @@ /test-pty /test-qcow2 /test-ratelimit -/test-rbtree /test-replace-var /test-resolve /test-resolve-tables diff --git a/Makefile.am b/Makefile.am index 0c2de6f2d3..ea6b0340b5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -747,8 +747,6 @@ libbasic_la_SOURCES = \ src/basic/missing_syscall.h \ src/basic/capability-util.c \ src/basic/capability-util.h \ - src/basic/c-rbtree.c \ - src/basic/c-rbtree.h \ src/basic/conf-files.c \ src/basic/conf-files.h \ src/basic/stdio-util.h \ @@ -1494,7 +1492,6 @@ tests += \ test-copy \ test-cap-list \ test-sigbus \ - test-rbtree \ test-verbs \ test-af-list \ test-arphrd-list \ @@ -1748,12 +1745,6 @@ test_sigbus_SOURCES = \ test_sigbus_LDADD = \ libshared.la -test_rbtree_SOURCES = \ - src/test/test-rbtree.c - -test_rbtree_LDADD = \ - libshared.la - test_condition_SOURCES = \ src/test/test-condition.c diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c deleted file mode 100644 index cf5a7242df..0000000000 --- a/src/basic/c-rbtree.c +++ /dev/null @@ -1,674 +0,0 @@ -/*** - This file is part of systemd. See COPYING for details. - - 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 . -***/ - -/* - * RB-Tree Implementation - * This implements the insertion/removal of elements in RB-Trees. You're highly - * recommended to have an RB-Tree documentation at hand when reading this. Both - * insertion and removal can be split into a handful of situations that can - * occur. Those situations are enumerated as "Case 1" to "Case n" here, and - * follow closely the cases described in most RB-Tree documentations. This file - * does not explain why it is enough to handle just those cases, nor does it - * provide a proof of correctness. Dig out your algorithm 101 handbook if - * you're interested. - * - * This implementation is *not* straightforward. Usually, a handful of - * rotation, reparent, swap and link helpers can be used to implement the - * rebalance operations. However, those often perform unnecessary writes. - * Therefore, this implementation hard-codes all the operations. You're highly - * recommended to look at the two basic helpers before reading the code: - * c_rbtree_swap_child() - * c_rbtree_set_parent_and_color() - * Those are the only helpers used, hence, you should really know what they do - * before digging into the code. - * - * For a highlevel documentation of the API, see the header file and docbook - * comments. - */ - -#include -#include -#include "c-rbtree.h" - -enum { - C_RBNODE_RED = 0, - C_RBNODE_BLACK = 1, -}; - -static inline unsigned long c_rbnode_color(CRBNode *n) { - return (unsigned long)n->__parent_and_color & 1UL; -} - -static inline _Bool c_rbnode_is_red(CRBNode *n) { - return c_rbnode_color(n) == C_RBNODE_RED; -} - -static inline _Bool c_rbnode_is_black(CRBNode *n) { - return c_rbnode_color(n) == C_RBNODE_BLACK; -} - -/** - * c_rbnode_leftmost() - return leftmost child - * @n: current node, or NULL - * - * This returns the leftmost child of @n. If @n is NULL, this will return NULL. - * In all other cases, this function returns a valid pointer. That is, if @n - * does not have any left children, this returns @n. - * - * Worst case runtime (n: number of elements in tree): O(log(n)) - * - * Return: Pointer to leftmost child, or NULL. - */ -CRBNode *c_rbnode_leftmost(CRBNode *n) { - if (n) - while (n->left) - n = n->left; - return n; -} - -/** - * c_rbnode_rightmost() - return rightmost child - * @n: current node, or NULL - * - * This returns the rightmost child of @n. If @n is NULL, this will return - * NULL. In all other cases, this function returns a valid pointer. That is, if - * @n does not have any right children, this returns @n. - * - * Worst case runtime (n: number of elements in tree): O(log(n)) - * - * Return: Pointer to rightmost child, or NULL. - */ -CRBNode *c_rbnode_rightmost(CRBNode *n) { - if (n) - while (n->right) - n = n->right; - return n; -} - -/** - * c_rbnode_next() - return next node - * @n: current node, or NULL - * - * An RB-Tree always defines a linear order of its elements. This function - * returns the logically next node to @n. If @n is NULL, the last node or - * unlinked, this returns NULL. - * - * Worst case runtime (n: number of elements in tree): O(log(n)) - * - * Return: Pointer to next node, or NULL. - */ -CRBNode *c_rbnode_next(CRBNode *n) { - CRBNode *p; - - if (!c_rbnode_is_linked(n)) - return NULL; - if (n->right) - return c_rbnode_leftmost(n->right); - - while ((p = c_rbnode_parent(n)) && n == p->right) - n = p; - - return p; -} - -/** - * c_rbnode_prev() - return previous node - * @n: current node, or NULL - * - * An RB-Tree always defines a linear order of its elements. This function - * returns the logically previous node to @n. If @n is NULL, the first node or - * unlinked, this returns NULL. - * - * Worst case runtime (n: number of elements in tree): O(log(n)) - * - * Return: Pointer to previous node, or NULL. - */ -CRBNode *c_rbnode_prev(CRBNode *n) { - CRBNode *p; - - if (!c_rbnode_is_linked(n)) - return NULL; - if (n->left) - return c_rbnode_rightmost(n->left); - - while ((p = c_rbnode_parent(n)) && n == p->left) - n = p; - - return p; -} - -/** - * c_rbtree_first() - return first node - * @t: tree to operate on - * - * An RB-Tree always defines a linear order of its elements. This function - * returns the logically first node in @t. If @t is empty, NULL is returned. - * - * Fixed runtime (n: number of elements in tree): O(log(n)) - * - * Return: Pointer to first node, or NULL. - */ -CRBNode *c_rbtree_first(CRBTree *t) { - assert(t); - return c_rbnode_leftmost(t->root); -} - -/** - * c_rbtree_last() - return last node - * @t: tree to operate on - * - * An RB-Tree always defines a linear order of its elements. This function - * returns the logically last node in @t. If @t is empty, NULL is returned. - * - * Fixed runtime (n: number of elements in tree): O(log(n)) - * - * Return: Pointer to last node, or NULL. - */ -CRBNode *c_rbtree_last(CRBTree *t) { - assert(t); - return c_rbnode_rightmost(t->root); -} - -/* - * Set the color and parent of a node. This should be treated as a simple - * assignment of the 'color' and 'parent' fields of the node. No other magic is - * applied. But since both fields share its backing memory, this helper - * function is provided. - */ -static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigned long c) { - assert(!((unsigned long)p & 1)); - assert(c < 2); - n->__parent_and_color = (CRBNode*)((unsigned long)p | c); -} - -/* same as c_rbnode_set_parent_and_color(), but keeps the current color */ -static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) { - c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n)); -} - -/* - * This function partially replaces an existing child pointer to a new one. The - * existing child must be given as @old, the new child as @new. @p must be the - * parent of @old (or NULL if it has no parent). - * This function ensures that the parent of @old now points to @new. However, - * it does *NOT* change the parent pointer of @new. The caller must ensure - * this. - * If @p is NULL, this function ensures that the root-pointer is adjusted - * instead (given as @t). - */ -static inline void c_rbtree_swap_child(CRBTree *t, CRBNode *p, CRBNode *old, CRBNode *new) { - if (p) { - if (p->left == old) - p->left = new; - else - p->right = new; - } else { - t->root = new; - } -} - -static inline CRBNode *c_rbtree_paint_one(CRBTree *t, CRBNode *n) { - CRBNode *p, *g, *gg, *u, *x; - - /* - * Paint a single node according to RB-Tree rules. The node must - * already be linked into the tree and painted red. - * We repaint the node or rotate the tree, if required. In case a - * recursive repaint is required, the next node to be re-painted - * is returned. - * p: parent - * g: grandparent - * gg: grandgrandparent - * u: uncle - * x: temporary - */ - - /* node is red, so we can access the parent directly */ - p = n->__parent_and_color; - - if (!p) { - /* Case 1: - * We reached the root. Mark it black and be done. As all - * leaf-paths share the root, the ratio of black nodes on each - * path stays the same. */ - c_rbnode_set_parent_and_color(n, p, C_RBNODE_BLACK); - n = NULL; - } else if (c_rbnode_is_black(p)) { - /* Case 2: - * The parent is already black. As our node is red, we did not - * change the number of black nodes on any path, nor do we have - * multiple consecutive red nodes. */ - n = NULL; - } else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */ - g = p->__parent_and_color; - gg = c_rbnode_parent(g); - u = g->right; - - if (u && c_rbnode_is_red(u)) { - /* Case 3: - * Parent and uncle are both red. We know the - * grandparent must be black then. Repaint parent and - * uncle black, the grandparent red and recurse into - * the grandparent. */ - c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); - n = g; - } else { - /* parent is red, uncle is black */ - - if (n == p->right) { - /* Case 4: - * We're the right child. Rotate on parent to - * become left child, so we can handle it the - * same as case 5. */ - x = n->left; - p->right = n->left; - n->left = p; - if (x) - c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); - p = n; - } - - /* 'n' is invalid from here on! */ - n = NULL; - - /* Case 5: - * We're the red left child or a red parent, black - * grandparent and uncle. Rotate on grandparent and - * switch color with parent. Number of black nodes on - * each path stays the same, but we got rid of the - * double red path. As the grandparent is still black, - * we're done. */ - x = p->right; - g->left = x; - p->right = g; - if (x) - c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); - c_rbtree_swap_child(t, gg, g, p); - } - } else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */ - g = p->__parent_and_color; - gg = c_rbnode_parent(g); - u = g->left; - - if (u && c_rbnode_is_red(u)) { - c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); - n = g; - } else { - if (n == p->left) { - x = n->right; - p->left = n->right; - n->right = p; - if (x) - c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); - p = n; - } - - n = NULL; - - x = p->left; - g->right = x; - p->left = g; - if (x) - c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); - c_rbtree_swap_child(t, gg, g, p); - } - } - - return n; -} - -static inline void c_rbtree_paint(CRBTree *t, CRBNode *n) { - assert(t); - assert(n); - - while (n) - n = c_rbtree_paint_one(t, n); -} - -/** - * c_rbtree_add() - add node to tree - * @t: tree to operate one - * @p: parent node to link under, or NULL - * @l: left/right slot of @p (or root) to link at - * @n: node to add - * - * This links @n into the tree given as @t. The caller must provide the exact - * spot where to link the node. That is, the caller must traverse the tree - * based on their search order. Once they hit a leaf where to insert the node, - * call this function to link it and rebalance the tree. - * - * A typical insertion would look like this (@t is your tree, @n is your node): - * - * CRBNode **i, *p; - * - * i = &t->root; - * p = NULL; - * while (*i) { - * p = *i; - * if (compare(n, *i) < 0) - * i = &(*i)->left; - * else - * i = &(*i)->right; - * } - * - * c_rbtree_add(t, p, i, n); - * - * Once the node is linked into the tree, a simple lookup on the same tree can - * be coded like this: - * - * CRBNode *i; - * - * i = t->root; - * while (i) { - * int v = compare(n, i); - * if (v < 0) - * i = (*i)->left; - * else if (v > 0) - * i = (*i)->right; - * else - * break; - * } - * - * When you add nodes to a tree, the memory contents of the node do not matter. - * That is, there is no need to initialize the node via c_rbnode_init(). - * However, if you relink nodes multiple times during their lifetime, it is - * usually very convenient to use c_rbnode_init() and c_rbtree_remove_init(). - * In those cases, you should validate that a node is unlinked before you call - * c_rbtree_add(). - */ -void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) { - assert(t); - assert(l); - assert(n); - assert(!p || l == &p->left || l == &p->right); - assert(p || l == &t->root); - - c_rbnode_set_parent_and_color(n, p, C_RBNODE_RED); - n->left = n->right = NULL; - *l = n; - - c_rbtree_paint(t, n); -} - -static inline CRBNode *c_rbtree_rebalance_one(CRBTree *t, CRBNode *p, CRBNode *n) { - CRBNode *s, *x, *y, *g; - - /* - * Rebalance tree after a node was removed. This happens only if you - * remove a black node and one path is now left with an unbalanced - * number or black nodes. - * This function assumes all paths through p and n have one black node - * less than all other paths. If recursive fixup is required, the - * current node is returned. - */ - - if (n == p->left) { - s = p->right; - if (c_rbnode_is_red(s)) { - /* Case 3: - * We have a red node as sibling. Rotate it onto our - * side so we can later on turn it black. This way, we - * gain the additional black node in our path. */ - g = c_rbnode_parent(p); - x = s->left; - p->right = x; - s->left = p; - c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); - c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); - c_rbtree_swap_child(t, g, p, s); - s = x; - } - - x = s->right; - if (!x || c_rbnode_is_black(x)) { - y = s->left; - if (!y || c_rbnode_is_black(y)) { - /* Case 4: - * Our sibling is black and has only black - * children. Flip it red and turn parent black. - * This way we gained a black node in our path, - * or we fix it recursively one layer up, which - * will rotate the red sibling as parent. */ - c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); - if (c_rbnode_is_black(p)) - return p; - - c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); - return NULL; - } - - /* Case 5: - * Left child of our sibling is red, right one is black. - * Rotate on parent so the right child of our sibling is - * now red, and we can fall through to case 6. */ - x = y->right; - s->left = y->right; - y->right = s; - p->right = y; - if (x) - c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); - x = s; - s = y; - } - - /* Case 6: - * The right child of our sibling is red. Rotate left and flip - * colors, which gains us an additional black node in our path, - * that was previously on our sibling. */ - g = c_rbnode_parent(p); - y = s->left; - p->right = y; - s->left = p; - c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); - if (y) - c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); - c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); - c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); - c_rbtree_swap_child(t, g, p, s); - } else /* if (!n || n == p->right) */ { /* same as above, but mirrored */ - s = p->left; - if (c_rbnode_is_red(s)) { - g = c_rbnode_parent(p); - x = s->right; - p->left = x; - s->right = p; - c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(s, g, C_RBNODE_BLACK); - c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); - c_rbtree_swap_child(t, g, p, s); - s = x; - } - - x = s->left; - if (!x || c_rbnode_is_black(x)) { - y = s->right; - if (!y || c_rbnode_is_black(y)) { - c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); - if (c_rbnode_is_black(p)) - return p; - - c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); - return NULL; - } - - x = y->left; - s->right = y->left; - y->left = s; - p->left = y; - if (x) - c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); - x = s; - s = y; - } - - g = c_rbnode_parent(p); - y = s->right; - p->left = y; - s->right = p; - c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); - if (y) - c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); - c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); - c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); - c_rbtree_swap_child(t, g, p, s); - } - - return NULL; -} - -static inline void c_rbtree_rebalance(CRBTree *t, CRBNode *p) { - CRBNode *n = NULL; - - assert(t); - assert(p); - - do { - n = c_rbtree_rebalance_one(t, p, n); - p = n ? c_rbnode_parent(n) : NULL; - } while (p); -} - -/** - * c_rbtree_remove() - remove node from tree - * @t: tree to operate one - * @n: node to remove - * - * This removes the given node from its tree. Once unlinked, the tree is - * rebalanced. - * The caller *must* ensure that the given tree is actually the tree it is - * linked on. Otherwise, behavior is undefined. - * - * This does *NOT* reset @n to being unlinked (for performance reason, this - * function *never* modifies @n at all). If you need this, use - * c_rbtree_remove_init(). - */ -void c_rbtree_remove(CRBTree *t, CRBNode *n) { - CRBNode *p, *s, *gc, *x, *next = NULL; - unsigned long c; - - assert(t); - assert(n); - assert(c_rbnode_is_linked(n)); - - /* - * There are three distinct cases during node removal of a tree: - * * The node has no children, in which case it can simply be removed. - * * The node has exactly one child, in which case the child displaces - * its parent. - * * The node has two children, in which case there is guaranteed to - * be a successor to the node (successor being the node ordered - * directly after it). This successor cannot have two children by - * itself (two interior nodes can never be successive). Therefore, - * we can simply swap the node with its successor (including color) - * and have reduced this case to either of the first two. - * - * Whenever the node we removed was black, we have to rebalance the - * tree. Note that this affects the actual node we _remove_, not @n (in - * case we swap it). - * - * p: parent - * s: successor - * gc: grand-...-child - * x: temporary - * next: next node to rebalance on - */ - - if (!n->left) { - /* - * Case 1: - * The node has no left child. If it neither has a right child, - * it is a leaf-node and we can simply unlink it. If it also - * was black, we have to rebalance, as always if we remove a - * black node. - * But if the node has a right child, the child *must* be red - * (otherwise, the right path has more black nodes as the - * non-existing left path), and the node to be removed must - * hence be black. We simply replace the node with its child, - * turning the red child black, and thus no rebalancing is - * required. - */ - p = c_rbnode_parent(n); - c = c_rbnode_color(n); - c_rbtree_swap_child(t, p, n, n->right); - if (n->right) - c_rbnode_set_parent_and_color(n->right, p, c); - else - next = (c == C_RBNODE_BLACK) ? p : NULL; - } else if (!n->right) { - /* - * Case 1.1: - * The node has exactly one child, and it is on the left. Treat - * it as mirrored case of Case 1 (i.e., replace the node by its - * child). - */ - p = c_rbnode_parent(n); - c = c_rbnode_color(n); - c_rbtree_swap_child(t, p, n, n->left); - c_rbnode_set_parent_and_color(n->left, p, c); - } else { - /* - * Case 2: - * We are dealing with a full interior node with a child not on - * both sides. Find its successor and swap it. Then remove the - * node similar to Case 1. For performance reasons we don't - * perform the full swap, but skip links that are about to be - * removed, anyway. - */ - s = n->right; - if (!s->left) { - /* right child is next, no need to touch grandchild */ - p = s; - gc = s->right; - } else { - /* find successor and swap partially */ - s = c_rbnode_leftmost(s); - p = c_rbnode_parent(s); - - gc = s->right; - p->left = s->right; - s->right = n->right; - c_rbnode_set_parent(n->right, s); - } - - /* node is partially swapped, now remove as in Case 1 */ - s->left = n->left; - c_rbnode_set_parent(n->left, s); - - x = c_rbnode_parent(n); - c = c_rbnode_color(n); - c_rbtree_swap_child(t, x, n, s); - if (gc) - c_rbnode_set_parent_and_color(gc, p, C_RBNODE_BLACK); - else - next = c_rbnode_is_black(s) ? p : NULL; - c_rbnode_set_parent_and_color(s, x, c); - } - - if (next) - c_rbtree_rebalance(t, next); -} diff --git a/src/basic/c-rbtree.h b/src/basic/c-rbtree.h deleted file mode 100644 index 20c5515ca1..0000000000 --- a/src/basic/c-rbtree.h +++ /dev/null @@ -1,297 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. See COPYING for details. - - 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 . -***/ - -/* - * Standalone Red-Black-Tree Implementation in Standard ISO-C11 - * - * This header provides an RB-Tree API, that is fully implemented in ISO-C11 - * and has no external dependencies. Furthermore, tree traversal, memory - * allocations, and key comparisons a fully in control of the API user. The - * implementation only provides the RB-Tree specific rebalancing and coloring. - * - * A tree is represented by the "CRBTree" structure. It contains a *singly* - * field, which is a pointer to the root node. If NULL, the tree is empty. If - * non-NULL, there is at least a single element in the tree. - * - * Each node of the tree is represented by the "CRBNode" structure. It has - * three fields. The @left and @right members can be accessed by the API user - * directly to traverse the tree. The third member is an implementation detail - * and encodes the parent pointer and color of the node. - * API users are required to embed the CRBNode object into their own objects - * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode - * pointers into pointers to their own structure. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct CRBNode CRBNode; -typedef struct CRBTree CRBTree; - -/** - * struct CRBNode - Node of a Red-Black Tree - * @__parent_and_color: internal state - * @left: left child, or NULL - * @right: right child, or NULL - * - * Each node in an RB-Tree must embed an CRBNode object. This object contains - * pointers to its left and right child, which can be freely accessed by the - * API user at any time. They are NULL, if the node does not have a left/right - * child. - * - * The @__parent_and_color field must never be accessed directly. It encodes - * the pointer to the parent node, and the color of the node. Use the accessor - * functions instead. - * - * There is no reason to initialize a CRBNode object before linking it. - * However, if you need a boolean state that tells you whether the node is - * linked or not, you should initialize the node via c_rbnode_init() or - * C_RBNODE_INIT. - */ -struct CRBNode { - CRBNode *__parent_and_color; - CRBNode *left; - CRBNode *right; -}; - -#define C_RBNODE_INIT(_var) { .__parent_and_color = &(_var) } - -CRBNode *c_rbnode_leftmost(CRBNode *n); -CRBNode *c_rbnode_rightmost(CRBNode *n); -CRBNode *c_rbnode_next(CRBNode *n); -CRBNode *c_rbnode_prev(CRBNode *n); - -/** - * struct CRBTree - Red-Black Tree - * @root: pointer to the root node, or NULL - * - * Each Red-Black Tree is rooted in an CRBTree object. This object contains a - * pointer to the root node of the tree. The API user is free to access the - * @root member at any time, and use it to traverse the tree. - * - * To initialize an RB-Tree, set it to NULL / all zero. - */ -struct CRBTree { - CRBNode *root; -}; - -CRBNode *c_rbtree_first(CRBTree *t); -CRBNode *c_rbtree_last(CRBTree *t); - -void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n); -void c_rbtree_remove(CRBTree *t, CRBNode *n); - -/** - * c_rbnode_init() - mark a node as unlinked - * @n: node to operate on - * - * This marks the node @n as unlinked. The node will be set to a valid state - * that can never happen if the node is linked in a tree. Furthermore, this - * state is fully known to the implementation, and as such handled gracefully - * in all cases. - * - * You are *NOT* required to call this on your node. c_rbtree_add() can handle - * uninitialized nodes just fine. However, calling this allows to use - * c_rbnode_is_linked() to check for the state of a node. Furthermore, - * iterators and accessors can be called on initialized (yet unlinked) nodes. - * - * Use the C_RBNODE_INIT macro if you want to initialize static variables. - */ -static inline void c_rbnode_init(CRBNode *n) { - *n = (CRBNode)C_RBNODE_INIT(*n); -} - -/** - * c_rbnode_is_linked() - check whether a node is linked - * @n: node to check, or NULL - * - * This checks whether the passed node is linked. If you pass NULL, or if the - * node is not linked into a tree, this will return false. Otherwise, this - * returns true. - * - * Note that you must have either linked the node or initialized it, before - * calling this function. Never call this function on uninitialized nodes. - * Furthermore, removing a node via c_rbtree_remove() does *NOT* mark the node - * as unlinked. You have to call c_rbnode_init() yourself after removal, or use - * the c_rbtree_remove_init() helper. - * - * Return: true if the node is linked, false if not. - */ -static inline _Bool c_rbnode_is_linked(CRBNode *n) { - return n && n->__parent_and_color != n; -} - -/** - * c_rbnode_parent() - return parent pointer - * @n node to access - * - * This returns a pointer to the parent of the given node @n. If @n does not - * have a parent, NULL is returned. If @n is not linked, @n itself is returned. - * - * You should not call this on unlinked or uninitialized nodes! If you do, you - * better know how its semantics. - * - * Return: Pointer to parent. - */ -static inline CRBNode *c_rbnode_parent(CRBNode *n) { - return (CRBNode*)((unsigned long)n->__parent_and_color & ~1UL); -} - -/** - * c_rbtree_remove_init() - safely remove node from tree and reinitialize it - * @t: tree to operate on - * @n: node to remove, or NULL - * - * This is almost the same as c_rbtree_remove(), but extends it slightly, to be - * more convenient to use in many cases: - * - if @n is unlinked or NULL, this is a no-op - * - @n is reinitialized after being removed - */ -static inline void c_rbtree_remove_init(CRBTree *t, CRBNode *n) { - if (c_rbnode_is_linked(n)) { - c_rbtree_remove(t, n); - c_rbnode_init(n); - } -} - -/** - * CRBCompareFunc - compare a node to a key - * @t: tree where the node is linked to - * @k: key to compare - * @n: node to compare - * - * If you use the tree-traversal helpers (which are optional), you need to - * provide this callback so they can compare nodes in a tree to the key you - * look for. - * - * The tree @t is provided as optional context to this callback. The key you - * look for is provided as @k, the current node that should be compared to is - * provided as @n. This function should work like strcmp(), that is, return -1 - * if @key orders before @n, 0 if both compare equal, and 1 if it orders after - * @n. - */ -typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n); - -/** - * c_rbtree_find_node() - find node - * @t: tree to search through - * @f: comparison function - * @k: key to search for - * - * This searches through @t for a node that compares equal to @k. The function - * @f must be provided by the caller, which is used to compare nodes to @k. See - * the documentation of CRBCompareFunc for details. - * - * If there are multiple entries that compare equal to @k, this will return a - * pseudo-randomly picked node. If you need stable lookup functions for trees - * where duplicate entries are allowed, you better code your own lookup. - * - * Return: Pointer to matching node, or NULL. - */ -static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) { - CRBNode *i; - - assert(t); - assert(f); - - i = t->root; - while (i) { - int v = f(t, (void *)k, i); - if (v < 0) - i = i->left; - else if (v > 0) - i = i->right; - else - return i; - } - - return NULL; -} - -/** - * c_rbtree_find_entry() - find entry - * @_t: tree to search through - * @_f: comparison function - * @_k: key to search for - * @_t: type of the structure that embeds the nodes - * @_o: name of the node-member in type @_t - * - * This is very similar to c_rbtree_find_node(), but instead of returning a - * pointer to the CRBNode, it returns a pointer to the surrounding object. This - * object must embed the CRBNode object. The type of the surrounding object - * must be given as @_t, and the name of the embedded CRBNode member as @_o. - * - * See c_rbtree_find_node() for more details. - * - * Return: Pointer to found entry, NULL if not found. - */ -#define c_rbtree_find_entry(_m, _f, _k, _t, _o) \ - ((_t *)(((char *)c_rbtree_find_node((_m), (_f), (_k)) ?: \ - (char *)NULL + offsetof(_t, _o)) - offsetof(_t, _o))) - -/** - * c_rbtree_find_slot() - find slot to insert new node - * @t: tree to search through - * @f: comparison function - * @k: key to search for - * @p: output storage for parent pointer - * - * This searches through @t just like c_rbtree_find_node() does. However, - * instead of returning a pointer to a node that compares equal to @k, this - * searches for a slot to insert a node with key @k. A pointer to the slot is - * returned, and a pointer to the parent of the slot is stored in @p. Both - * can be passed directly to c_rbtree_add(), together with your node to insert. - * - * If there already is a node in the tree, that compares equal to @k, this will - * return NULL and store the conflicting node in @p. In all other cases, - * this will return a pointer (non-NULL) to the empty slot to insert the node - * at. @p will point to the parent node of that slot. - * - * If you want trees that allow duplicate nodes, you better code your own - * insertion function. - * - * Return: Pointer to slot to insert node, or NULL on conflicts. - */ -static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) { - CRBNode **i; - - assert(t); - assert(f); - assert(p); - - i = &t->root; - *p = NULL; - while (*i) { - int v = f(t, (void *)k, *i); - *p = *i; - if (v < 0) - i = &(*i)->left; - else if (v > 0) - i = &(*i)->right; - else - return NULL; - } - - return i; -} - -#ifdef __cplusplus -} -#endif diff --git a/src/test/test-rbtree.c b/src/test/test-rbtree.c deleted file mode 100644 index 8ae416c557..0000000000 --- a/src/test/test-rbtree.c +++ /dev/null @@ -1,362 +0,0 @@ -/*** - This file is part of systemd. See COPYING for details. - - 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 . -***/ - -/* - * Tests for RB-Tree - */ - -#undef NDEBUG -#include -#include -#include -#include "c-rbtree.h" - -/* verify that all API calls are exported */ -static void test_api(void) { - CRBTree t = {}; - CRBNode n = C_RBNODE_INIT(n); - - assert(!c_rbnode_is_linked(&n)); - - /* init, is_linked, add, remove, remove_init */ - - c_rbtree_add(&t, NULL, &t.root, &n); - assert(c_rbnode_is_linked(&n)); - - c_rbtree_remove_init(&t, &n); - assert(!c_rbnode_is_linked(&n)); - - c_rbtree_add(&t, NULL, &t.root, &n); - assert(c_rbnode_is_linked(&n)); - - c_rbtree_remove(&t, &n); - assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */ - - c_rbnode_init(&n); - assert(!c_rbnode_is_linked(&n)); - - /* first, last, leftmost, rightmost, next, prev */ - - assert(!c_rbtree_first(&t)); - assert(!c_rbtree_last(&t)); - assert(&n == c_rbnode_leftmost(&n)); - assert(&n == c_rbnode_rightmost(&n)); - assert(!c_rbnode_next(&n)); - assert(!c_rbnode_prev(&n)); -} - -/* copied from c-rbtree.c, relies on internal representation */ -static inline _Bool c_rbnode_is_red(CRBNode *n) { - return !((unsigned long)n->__parent_and_color & 1UL); -} - -/* copied from c-rbtree.c, relies on internal representation */ -static inline _Bool c_rbnode_is_black(CRBNode *n) { - return !!((unsigned long)n->__parent_and_color & 1UL); -} - -static size_t validate(CRBTree *t) { - unsigned int i_black, n_black; - CRBNode *n, *p, *o; - size_t count = 0; - - assert(t); - assert(!t->root || c_rbnode_is_black(t->root)); - - /* traverse to left-most child, count black nodes */ - i_black = 0; - n = t->root; - while (n && n->left) { - if (c_rbnode_is_black(n)) - ++i_black; - n = n->left; - } - n_black = i_black; - - /* - * Traverse tree and verify correctness: - * 1) A node is either red or black - * 2) The root is black - * 3) All leaves are black - * 4) Every red node must have two black child nodes - * 5) Every path to a leaf contains the same number of black nodes - * - * Note that NULL nodes are considered black, which is why we don't - * check for 3). - */ - o = NULL; - while (n) { - ++count; - - /* verify natural order */ - assert(n > o); - o = n; - - /* verify consistency */ - assert(!n->right || c_rbnode_parent(n->right) == n); - assert(!n->left || c_rbnode_parent(n->left) == n); - - /* verify 2) */ - if (!c_rbnode_parent(n)) - assert(c_rbnode_is_black(n)); - - if (c_rbnode_is_red(n)) { - /* verify 4) */ - assert(!n->left || c_rbnode_is_black(n->left)); - assert(!n->right || c_rbnode_is_black(n->right)); - } else { - /* verify 1) */ - assert(c_rbnode_is_black(n)); - } - - /* verify 5) */ - if (!n->left && !n->right) - assert(i_black == n_black); - - /* get next node */ - if (n->right) { - n = n->right; - if (c_rbnode_is_black(n)) - ++i_black; - - while (n->left) { - n = n->left; - if (c_rbnode_is_black(n)) - ++i_black; - } - } else { - while ((p = c_rbnode_parent(n)) && n == p->right) { - n = p; - if (c_rbnode_is_black(p->right)) - --i_black; - } - - n = p; - if (p && c_rbnode_is_black(p->left)) - --i_black; - } - } - - return count; -} - -static void insert(CRBTree *t, CRBNode *n) { - CRBNode **i, *p; - - assert(t); - assert(n); - assert(!c_rbnode_is_linked(n)); - - i = &t->root; - p = NULL; - while (*i) { - p = *i; - if (n < *i) { - i = &(*i)->left; - } else { - assert(n > *i); - i = &(*i)->right; - } - } - - c_rbtree_add(t, p, i, n); -} - -static void shuffle(void **nodes, size_t n_memb) { - unsigned int i, j; - void *t; - - for (i = 0; i < n_memb; ++i) { - j = rand() % n_memb; - t = nodes[j]; - nodes[j] = nodes[i]; - nodes[i] = t; - } -} - -/* run some pseudo-random tests on the tree */ -static void test_shuffle(void) { - CRBNode *nodes[256]; - CRBTree t = {}; - unsigned int i, j; - size_t n; - - /* allocate and initialize all nodes */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - nodes[i] = malloc(sizeof(*nodes[i])); - assert(nodes[i]); - c_rbnode_init(nodes[i]); - } - - /* shuffle nodes and validate *empty* tree */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); - n = validate(&t); - assert(n == 0); - - /* add all nodes and validate after each insertion */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - insert(&t, nodes[i]); - n = validate(&t); - assert(n == i + 1); - } - - /* shuffle nodes again */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); - - /* remove all nodes (in different order) and validate on each round */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - c_rbtree_remove(&t, nodes[i]); - n = validate(&t); - assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); - c_rbnode_init(nodes[i]); - } - - /* shuffle nodes and validate *empty* tree again */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); - n = validate(&t); - assert(n == 0); - - /* add all nodes again */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - insert(&t, nodes[i]); - n = validate(&t); - assert(n == i + 1); - } - - /* 4 times, remove half of the nodes and add them again */ - for (j = 0; j < 4; ++j) { - /* shuffle nodes again */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); - - /* remove half of the nodes */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { - c_rbtree_remove(&t, nodes[i]); - n = validate(&t); - assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); - c_rbnode_init(nodes[i]); - } - - /* shuffle the removed half */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes) / 2); - - /* add the removed half again */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { - insert(&t, nodes[i]); - n = validate(&t); - assert(n == sizeof(nodes) / sizeof(*nodes) / 2 + i + 1); - } - } - - /* shuffle nodes again */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); - - /* remove all */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - c_rbtree_remove(&t, nodes[i]); - n = validate(&t); - assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); - c_rbnode_init(nodes[i]); - } - - /* free nodes again */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) - free(nodes[i]); -} - -typedef struct { - unsigned long key; - CRBNode rb; -} Node; - -#define node_from_rb(_rb) ((Node *)((char *)(_rb) - offsetof(Node, rb))) - -static int compare(CRBTree *t, void *k, CRBNode *n) { - unsigned long key = (unsigned long)k; - Node *node = node_from_rb(n); - - return (key < node->key) ? -1 : (key > node->key) ? 1 : 0; -} - -/* run tests against the c_rbtree_find*() helpers */ -static void test_map(void) { - CRBNode **slot, *p; - CRBTree t = {}; - Node *nodes[2048]; - unsigned long i; - - /* allocate and initialize all nodes */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - nodes[i] = malloc(sizeof(*nodes[i])); - assert(nodes[i]); - nodes[i]->key = i; - c_rbnode_init(&nodes[i]->rb); - } - - /* shuffle nodes */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); - - /* add all nodes, and verify that each node is linked */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - assert(!c_rbnode_is_linked(&nodes[i]->rb)); - assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); - - slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p); - assert(slot); - c_rbtree_add(&t, p, slot, &nodes[i]->rb); - - assert(c_rbnode_is_linked(&nodes[i]->rb)); - assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); - } - - /* shuffle nodes again */ - shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); - - /* remove all nodes (in different order) */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { - assert(c_rbnode_is_linked(&nodes[i]->rb)); - assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); - - c_rbtree_remove_init(&t, &nodes[i]->rb); - - assert(!c_rbnode_is_linked(&nodes[i]->rb)); - assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); - } - - /* free nodes again */ - for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) - free(nodes[i]); -} - -int main(int argc, char **argv) { - unsigned int i; - - /* we want stable tests, so use fixed seed */ - srand(0xdeadbeef); - - test_api(); - - /* - * The tests are pseudo random; run them multiple times, each run will - * have different orders and thus different results. - */ - for (i = 0; i < 4; ++i) { - test_shuffle(); - test_map(); - } - - return 0; -} -- cgit v1.2.3-54-g00ecf From 6eb7c172b58d81a5f6c3998ce304a7324fc65050 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 11:27:28 +0200 Subject: tree-wide: add new SIGNAL_VALID() macro-like function that validates signal numbers And port all code over to use it. --- src/basic/signal-util.c | 2 +- src/basic/signal-util.h | 4 ++++ src/core/dbus-kill.c | 4 ++-- src/core/dbus-unit.c | 5 +++-- src/core/unit.c | 4 ++-- src/libsystemd/sd-event/sd-event.c | 5 ++--- src/login/logind-session-dbus.c | 3 ++- src/login/logind-user-dbus.c | 3 ++- src/machine/machine-dbus.c | 3 ++- 9 files changed, 20 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index e3047b209b..280b5c3251 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -255,7 +255,7 @@ int signal_from_string(const char *s) { } if (safe_atou(s, &u) >= 0) { signo = (int) u + offset; - if (signo > 0 && signo < _NSIG) + if (SIGNAL_VALID(signo)) return signo; } return -EINVAL; diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index a7322ff26a..dfd6eb564d 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -50,3 +50,7 @@ static inline void block_signals_reset(sigset_t *ss) { assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \ t; \ }) + +static inline bool SIGNAL_VALID(int signo) { + return signo > 0 && signo < _NSIG; +} diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c index fc50fafaad..0f54c6b84b 100644 --- a/src/core/dbus-kill.c +++ b/src/core/dbus-kill.c @@ -58,7 +58,7 @@ int bus_kill_context_set_transient_property( k = kill_mode_from_string(m); if (k < 0) - return -EINVAL; + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Kill mode '%s' not known.", m); if (mode != UNIT_CHECK) { c->kill_mode = k; @@ -75,7 +75,7 @@ int bus_kill_context_set_transient_property( if (r < 0) return r; - if (sig <= 0 || sig >= _NSIG) + if (!SIGNAL_VALID(sig)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal %i out of range", sig); if (mode != UNIT_CHECK) { diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index b351f6a2c2..c507265070 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -27,6 +27,7 @@ #include "locale-util.h" #include "log.h" #include "selinux-access.h" +#include "signal-util.h" #include "special.h" #include "string-util.h" #include "strv.h" @@ -547,7 +548,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error * return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho); } - if (signo <= 0 || signo >= _NSIG) + if (!SIGNAL_VALID(signo)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); r = bus_verify_manage_units_async_full( @@ -1002,7 +1003,6 @@ int bus_unit_queue_job( type = JOB_TRY_RELOAD; } - if (type == JOB_STOP && (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) && unit_active_state(u) == UNIT_INACTIVE) @@ -1259,6 +1259,7 @@ int bus_unit_set_properties( } int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { + assert(u); if (u->load_state == UNIT_LOADED) return 0; diff --git a/src/core/unit.c b/src/core/unit.c index c028f57f13..a8174e6041 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -47,6 +47,7 @@ #include "path-util.h" #include "process-util.h" #include "set.h" +#include "signal-util.h" #include "special.h" #include "stat-util.h" #include "stdio-util.h" @@ -3062,8 +3063,7 @@ bool unit_active_or_pending(Unit *u) { int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) { assert(u); assert(w >= 0 && w < _KILL_WHO_MAX); - assert(signo > 0); - assert(signo < _NSIG); + assert(SIGNAL_VALID(signo)); if (!UNIT_VTABLE(u)->kill) return -EOPNOTSUPP; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 841358ed03..9fd744768d 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -1145,8 +1145,7 @@ _public_ int sd_event_add_signal( int r; assert_return(e, -EINVAL); - assert_return(sig > 0, -EINVAL); - assert_return(sig < _NSIG, -EINVAL); + assert_return(SIGNAL_VALID(sig), -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -2200,7 +2199,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { if (_unlikely_(n != sizeof(si))) return -EIO; - assert(si.ssi_signo < _NSIG); + assert(SIGNAL_VALID(si.ssi_signo)); read_one = true; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index ff9170683b..0f8862c0d9 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -28,6 +28,7 @@ #include "logind-session-device.h" #include "logind-session.h" #include "logind.h" +#include "signal-util.h" #include "strv.h" #include "util.h" @@ -300,7 +301,7 @@ int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); } - if (signo <= 0 || signo >= _NSIG) + if (!SIGNAL_VALID(signo)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); r = bus_verify_polkit_async( diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index fd98c7beca..b73f9ea69e 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -25,6 +25,7 @@ #include "formats-util.h" #include "logind-user.h" #include "logind.h" +#include "signal-util.h" #include "strv.h" #include "user-util.h" @@ -222,7 +223,7 @@ int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error * if (r < 0) return r; - if (signo <= 0 || signo >= _NSIG) + if (!SIGNAL_VALID(signo)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); r = user_kill(u, signo); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index c5bbf2fbde..c7ff0efac8 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -46,6 +46,7 @@ #include "mkdir.h" #include "path-util.h" #include "process-util.h" +#include "signal-util.h" #include "strv.h" #include "terminal-util.h" #include "user-util.h" @@ -166,7 +167,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); } - if (signo <= 0 || signo >= _NSIG) + if (!SIGNAL_VALID(signo)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); r = bus_verify_polkit_async( -- cgit v1.2.3-54-g00ecf From 2c52204c3f615df482d42e5c27d609fd8cb16a7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 11:30:24 +0200 Subject: nstall: no need to export unit_file_lookup_state() anymore We only use it inside of install.c, hence let's make it static. --- src/shared/install.c | 4 +++- src/shared/install.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 7497a39219..3d48f612f3 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -65,6 +65,8 @@ typedef struct { OrderedHashmap *have_processed; } InstallContext; +static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); + static int in_search_path(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; char **i; @@ -1958,7 +1960,7 @@ int unit_file_get_default( return 0; } -int unit_file_lookup_state( +static int unit_file_lookup_state( UnitFileScope scope, const LookupPaths *paths, const char *name, diff --git a/src/shared/install.h b/src/shared/install.h index c57c23934b..8d54fd14ad 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -137,7 +137,6 @@ 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, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name); -- cgit v1.2.3-54-g00ecf From 8f9364f98b3816ac90308b198030ba958757bb9b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 17:58:53 +0200 Subject: install: simplify skip_root() a bit Exit early, so that we can get rid of the large if block. --- src/shared/install.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 3d48f612f3..3289b51f41 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -85,25 +85,27 @@ static int in_search_path(const LookupPaths *p, const char *path) { } static const char* skip_root(const LookupPaths *p, const char *path) { - if (p->root_dir) { - char *e; + char *e; - e = path_startswith(path, p->root_dir); - if (!e) - return NULL; + assert(p); + assert(path); - /* Make sure the returned path starts with a slash */ - if (e[0] != '/') { - if (e == path || e[-1] != '/') - return NULL; + if (!p->root_dir) + return path; - e--; - } + e = path_startswith(path, p->root_dir); + if (!e) + return NULL; + + /* Make sure the returned path starts with a slash */ + if (e[0] != '/') { + if (e == path || e[-1] != '/') + return NULL; - return e; + e--; } - return path; + return e; } static int path_is_generator(const LookupPaths *p, const char *path) { -- cgit v1.2.3-54-g00ecf From d096025b81db228718a09e8302a0ec403263dcf2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 17:59:52 +0200 Subject: install: fix errno handling --- src/shared/install.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 3289b51f41..8fc9205107 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1600,7 +1600,7 @@ int unit_file_unmask( return -ENOMEM; if (unlink(path) < 0) { - if (errno != -ENOENT && r >= 0) + if (errno != ENOENT && r >= 0) r = -errno; continue; -- cgit v1.2.3-54-g00ecf From 344ca7556bf6c1c8727c19a0eb8751a27dc0a85f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 18:00:36 +0200 Subject: core,systemctl: add new "systemctl revert" command This allows dropping all user configuration and reverting back to the vendor default of a unit file. It basically undoes what "systemctl edit", "systemctl set-property" and "systemctl mask" do. --- man/systemctl.xml | 22 ++++ src/core/dbus-manager.c | 28 ++++ src/core/org.freedesktop.systemd1.conf | 4 + src/shared/install.c | 234 +++++++++++++++++++++++++++++++-- src/shared/install.h | 3 +- src/systemctl/systemctl.c | 20 ++- src/test/test-install-root.c | 52 ++++++++ 7 files changed, 347 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/man/systemctl.xml b/man/systemctl.xml index 064777810f..5f624243f7 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1244,6 +1244,28 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + + revert NAME... + + + Revert one or more unit files to their vendor versions. This command removes drop-in configuration + files that modify the specified units, as well as any user-configured unit file that overrides a matching + vendor supplied unit file. Specifically, for a unit foo.service the matching directories + foo.service.d/ with all their contained files are removed, both below the persistent and + runtime configuration directories (i.e. below /etc/systemd/system and + /run/systemd/system); if the unit file has a vendor-supplied version (i.e. a unit file + located below /usr) any matching peristent or runtime unit file that overrides it is + removed, too. Note that if a unit file has no vendor-supplied version (i.e. is only defined below + /etc/systemd/system or /run/systemd/system, but not in a unit + file stored below /usr), then it is not removed. Also, if a unit is masked, it is + unmasked. + + Effectively, this command may be used to undo all changes made with systemctl + edit, systemctl set-property and systemctl mask and puts + the original unit file with its settings back in effect. + + + add-wants TARGET NAME... diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index f0ee2fcb36..41f27ec26b 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1758,6 +1758,33 @@ static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_ return method_disable_unit_files_generic(message, userdata, "enable", unit_file_unmask, error); } +static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + Manager *m = userdata; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + 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 = unit_file_revert(m->unit_file_scope, NULL, l, &changes, &n_changes); + if (r < 0) + return r; + + return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); +} + static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) { UnitFileChange *changes = NULL; unsigned n_changes = 0; @@ -2005,6 +2032,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("PresetUnitFilesWithMode", "assbb", "ba(sss)", method_preset_unit_files_with_mode, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RevertUnitFiles", "as", "a(sss)", method_revert_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 6a7a37ee92..f78eedbd6e 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -174,6 +174,10 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="LinkUnitFiles"/> + + diff --git a/src/shared/install.c b/src/shared/install.c index 8fc9205107..8d9f96553b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -45,6 +45,7 @@ #include "mkdir.h" #include "path-lookup.h" #include "path-util.h" +#include "rm-rf.h" #include "set.h" #include "special.h" #include "stat-util.h" @@ -136,27 +137,35 @@ static int path_is_transient(const LookupPaths *p, const char *path) { return path_equal(p->transient, parent); } -static int path_is_config(const LookupPaths *p, const char *path) { +static int path_is_control(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; - const char *rpath; assert(p); assert(path); - /* Checks whether the specified path is intended for configuration or is outside of it. We check both the - * top-level directory and the one actually configured. The latter is particularly relevant for cases where we - * operate on a root directory. */ + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; - rpath = skip_root(p, path); - if (rpath && (path_startswith(rpath, "/etc") || path_startswith(rpath, "/run"))) - return true; + return path_equal(parent, p->persistent_control) || + path_equal(parent, p->runtime_control); +} + +static int path_is_config(const LookupPaths *p, const char *path) { + _cleanup_free_ char *parent = NULL; + + assert(p); + assert(path); + + /* Note that we do *not* have generic checks for /etc or /run in place, since with them we couldn't discern + * configuration from transient or generated units */ parent = dirname_malloc(path); if (!parent) return -ENOMEM; return path_equal(parent, p->persistent_config) || - path_equal(parent, p->runtime_config); + path_equal(parent, p->runtime_config); } static int path_is_runtime(const LookupPaths *p, const char *path) { @@ -166,6 +175,9 @@ static int path_is_runtime(const LookupPaths *p, const char *path) { assert(p); assert(path); + /* Everything in /run is considered runtime. On top of that we also add explicit checks for the various runtime + * directories, as safety net. */ + rpath = skip_root(p, path); if (rpath && path_startswith(rpath, "/run")) return true; @@ -174,7 +186,33 @@ static int path_is_runtime(const LookupPaths *p, const char *path) { if (!parent) return -ENOMEM; - return path_equal(parent, p->runtime_config); + return path_equal(parent, p->runtime_config) || + path_equal(parent, p->generator) || + path_equal(parent, p->generator_early) || + path_equal(parent, p->generator_late) || + path_equal(parent, p->transient) || + path_equal(parent, p->runtime_control); +} + +static int path_is_vendor(const LookupPaths *p, const char *path) { + const char *rpath; + + assert(p); + assert(path); + + rpath = skip_root(p, path); + if (!rpath) + return 0; + + if (path_startswith(rpath, "/usr")) + return true; + +#ifdef HAVE_SPLIT_USR + if (path_startswith(rpath, "/lib")) + return true; +#endif + + return path_equal(rpath, SYSTEM_DATA_UNIT_PATH); } int unit_file_changes_add( @@ -1703,6 +1741,182 @@ int unit_file_link( return r; } +static int path_shall_revert(const LookupPaths *paths, const char *path) { + int r; + + assert(paths); + assert(path); + + /* Checks whether the path is one where the drop-in directories shall be removed. */ + + r = path_is_config(paths, path); + if (r != 0) + return r; + + r = path_is_control(paths, path); + if (r != 0) + return r; + + return path_is_transient(paths, path); +} + +int unit_file_revert( + UnitFileScope scope, + const char *root_dir, + char **files, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + /* _cleanup_(install_context_done) InstallContext c = {}; */ + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_strv_free_ char **todo = NULL; + size_t n_todo = 0, n_allocated = 0; + char **i; + int r, q; + + /* Puts a unit file back into vendor state. This means: + * + * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and + * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated"). + * + * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in + * "config", but not in "transient" or "control" or even "generated"). + * + * We remove all that in both the runtime and the persistant directories, if that applies. + */ + + r = lookup_paths_init(&paths, scope, 0, root_dir); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + bool has_vendor = false; + char **p; + + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + + STRV_FOREACH(p, paths.search_path) { + _cleanup_free_ char *path = NULL, *dropin = NULL; + struct stat st; + + path = path_make_absolute(*i, *p); + if (!path) + return -ENOMEM; + + r = lstat(path, &st); + if (r < 0) { + if (errno != ENOENT) + return -errno; + } else if (S_ISREG(st.st_mode)) { + /* Check if there's a vendor version */ + r = path_is_vendor(&paths, path); + if (r < 0) + return r; + if (r > 0) + has_vendor = true; + } + + dropin = strappend(path, ".d"); + if (!dropin) + return -ENOMEM; + + r = lstat(dropin, &st); + if (r < 0) { + if (errno != ENOENT) + return -errno; + } else if (S_ISDIR(st.st_mode)) { + /* Remove the drop-ins */ + r = path_shall_revert(&paths, dropin); + if (r < 0) + return r; + if (r > 0) { + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; + + todo[n_todo++] = dropin; + dropin = NULL; + } + } + } + + if (!has_vendor) + continue; + + /* OK, there's a vendor version, hence drop all configuration versions */ + STRV_FOREACH(p, paths.search_path) { + _cleanup_free_ char *path = NULL; + struct stat st; + + path = path_make_absolute(*i, *p); + if (!path) + return -ENOMEM; + + r = lstat(path, &st); + if (r < 0) { + if (errno != ENOENT) + return -errno; + } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { + r = path_is_config(&paths, path); + if (r < 0) + return r; + if (r > 0) { + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; + + todo[n_todo++] = path; + path = NULL; + } + } + } + } + + strv_uniq(todo); + + r = 0; + STRV_FOREACH(i, todo) { + _cleanup_strv_free_ char **fs = NULL; + const char *rp; + char **j; + + (void) get_files_in_directory(*i, &fs); + + q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL); + if (q < 0 && q != -ENOENT && r >= 0) { + r = q; + continue; + } + + STRV_FOREACH(j, fs) { + _cleanup_free_ char *t = NULL; + + t = strjoin(*i, "/", *j, NULL); + if (!t) + return -ENOMEM; + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL); + } + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL); + + rp = skip_root(&paths, *i); + q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i); + if (q < 0) + return q; + } + + q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes); + if (r >= 0) + r = q; + + q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes); + if (r >= 0) + r = q; + + return r; +} + int unit_file_add_dependency( UnitFileScope scope, bool runtime, diff --git a/src/shared/install.h b/src/shared/install.h index 8d54fd14ad..6f8b45d4f6 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -128,11 +128,12 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) { 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); int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); +int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +int unit_file_revert(UnitFileScope scope, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); 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, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 3344d25f77..b94af9cf08 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1993,7 +1993,7 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha if (changes[i].type == UNIT_FILE_SYMLINK) log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); else - log_info("Removed symlink %s.", changes[i].path); + log_info("Removed %s.", changes[i].path); } } @@ -5437,6 +5437,8 @@ static int enable_unit(int argc, char *argv[], void *userdata) { r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); else if (streq(verb, "unmask")) r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes); + else if (streq(verb, "revert")) + r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes); else assert_not_reached("Unknown verb"); @@ -5455,7 +5457,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int expect_carries_install_info = false; - bool send_force = true, send_preset_mode = false; + bool send_runtime = true, send_force = true, send_preset_mode = false; const char *method; sd_bus *bus; @@ -5490,6 +5492,9 @@ static int enable_unit(int argc, char *argv[], void *userdata) { else if (streq(verb, "unmask")) { method = "UnmaskUnitFiles"; send_force = false; + } else if (streq(verb, "revert")) { + method = "RevertUnitFiles"; + send_runtime = send_force = false; } else assert_not_reached("Unknown verb"); @@ -5513,9 +5518,11 @@ static int enable_unit(int argc, char *argv[], void *userdata) { return bus_log_create_error(r); } - r = sd_bus_message_append(m, "b", arg_runtime); - if (r < 0) - return bus_log_create_error(r); + if (send_runtime) { + r = sd_bus_message_append(m, "b", arg_runtime); + if (r < 0) + return bus_log_create_error(r); + } if (send_force) { r = sd_bus_message_append(m, "b", arg_force); @@ -6280,6 +6287,8 @@ static void systemctl_help(void) { " unmask NAME... Unmask one or more units\n" " link PATH... Link one or more units files into\n" " the search path\n" + " revert NAME... Revert one or more unit files to vendor\n" + " version\n" " add-wants TARGET NAME... Add 'Wants' dependency for the target\n" " on specified one or more units\n" " add-requires TARGET NAME... Add 'Requires' dependency for the target\n" @@ -7403,6 +7412,7 @@ static int systemctl_main(int argc, char *argv[]) { { "mask", 2, VERB_ANY, 0, enable_unit }, { "unmask", 2, VERB_ANY, 0, enable_unit }, { "link", 2, VERB_ANY, 0, enable_unit }, + { "revert", 2, VERB_ANY, 0, enable_unit }, { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root }, { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies }, { "set-default", 2, 2, 0, set_default }, diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index bc4206a1b0..2138655e29 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -630,6 +630,57 @@ static void test_preset_and_list(const char *root) { assert_se(got_yes && got_no); } +static void test_revert(const char *root) { + const char *p; + UnitFileState state; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + + assert(root); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/xx.service"); + assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC); + + /* Initially there's nothing to revert */ + assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service"); + assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0); + + /* Revert the override file */ + assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d/dropin.conf"); + assert_se(mkdir_parents(p, 0755) >= 0); + assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE) >= 0); + + /* Revert the dropin file */ + assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d"); + assert_se(changes[1].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[1].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + int main(int argc, char *argv[]) { char root[] = "/tmp/rootXXXXXX"; const char *p; @@ -658,6 +709,7 @@ int main(int argc, char *argv[]) { test_template_enable(root); test_indirect(root); test_preset_and_list(root); + test_revert(root); assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); -- cgit v1.2.3-54-g00ecf From e20b2a867ac5ac7ff6d43898fb83bc78f730909e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 18:10:32 +0200 Subject: core: when creating a drop-in snippet, add a comment explaining this to it --- src/core/unit.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index a8174e6041..fb4f3ddff6 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3357,7 +3357,7 @@ static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) { int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { _cleanup_free_ char *p = NULL, *q = NULL; - const char *dir; + const char *dir, *prefixed; int r; assert(u); @@ -3376,7 +3376,10 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co if (!dir) return -EINVAL; - r = write_drop_in(dir, u->id, 50, name, data); + prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n", + data); + + r = write_drop_in(dir, u->id, 50, name, prefixed); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 815b09d39b74a9ece31b7d7ef45f8f00784b8d8b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 18:13:02 +0200 Subject: core: optimize unit_write_drop_in a bit There's no point in first determining the drop-in file name path, then forgetting it again, and then determining it again. Instead, just generated it once, and then write to ti directly. --- src/core/unit.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index fb4f3ddff6..08f3288776 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3379,17 +3379,19 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n", data); - r = write_drop_in(dir, u->id, 50, name, prefixed); + r = drop_in_file(dir, u->id, 50, name, &p, &q); if (r < 0) return r; - r = drop_in_file(dir, u->id, 50, name, &p, &q); + (void) mkdir_p(p, 0755); + r = write_string_file_atomic_label(q, prefixed); if (r < 0) return r; - r = strv_extend(&u->dropin_paths, q); + r = strv_push(&u->dropin_paths, q); if (r < 0) return r; + q = NULL; strv_uniq(u->dropin_paths); -- cgit v1.2.3-54-g00ecf From d2120590ffdcc041f098667355ca3db5161d25d9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Apr 2016 18:54:05 +0200 Subject: tests: override XDG_RUNTIME_DIR where we use the user runtime dir We don#t really support systems where XDG_RUNTIME_DIR is not supported for systemd --user. Hence, let's always set our own XDG_RUNTIME_DIR for tests that involve systemd --user, so that we know it is set, and that it doesn't polute the user's actual runtime dir. --- Makefile.am | 4 +++- src/basic/rm-rf.h | 9 +++++++++ src/shared/tests.c | 33 +++++++++++++++++++++++++++++++++ src/shared/tests.h | 22 ++++++++++++++++++++++ src/test/test-cgroup-mask.c | 6 ++++++ src/test/test-engine.c | 5 +++++ src/test/test-path.c | 8 ++++++-- src/test/test-sched-prio.c | 5 +++++ src/test/test-unit-file.c | 5 +++++ 9 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 src/shared/tests.c create mode 100644 src/shared/tests.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index ea6b0340b5..34eaefd0bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1036,7 +1036,9 @@ libshared_la_SOURCES = \ src/shared/machine-pool.c \ src/shared/machine-pool.h \ src/shared/resolve-util.c \ - src/shared/resolve-util.h + src/shared/resolve-util.h \ + src/shared/tests.h \ + src/shared/tests.c if HAVE_UTMP libshared_la_SOURCES += \ diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h index 6d03268919..40b5b527d5 100644 --- a/src/basic/rm-rf.h +++ b/src/basic/rm-rf.h @@ -30,3 +30,12 @@ typedef enum RemoveFlags { int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev); int rm_rf(const char *path, RemoveFlags flags); + +/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */ +static inline void rm_rf_and_free(char *p) { + if (!p) + return; + (void) rm_rf(p, REMOVE_ROOT); + free(p); +} +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_and_free); diff --git a/src/shared/tests.c b/src/shared/tests.c new file mode 100644 index 0000000000..409116290d --- /dev/null +++ b/src/shared/tests.c @@ -0,0 +1,33 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#include + +#include "tests.h" + +char* setup_fake_runtime_dir(void) { + char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p; + + assert_se(mkdtemp(t)); + assert_se(setenv("XDG_RUNTIME_DIR", t, 1) >= 0); + assert_se(p = strdup(t)); + + return p; +} diff --git a/src/shared/tests.h b/src/shared/tests.h new file mode 100644 index 0000000000..93f09013a1 --- /dev/null +++ b/src/shared/tests.h @@ -0,0 +1,22 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +char* setup_fake_runtime_dir(void); diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 332755cf41..4eb8fcd773 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -21,7 +21,9 @@ #include "macro.h" #include "manager.h" +#include "rm-rf.h" #include "test-helper.h" +#include "tests.h" #include "unit.h" static int test_cgroup_mask(void) { @@ -107,7 +109,11 @@ static int test_cgroup_mask(void) { } int main(int argc, char* argv[]) { + _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; int rc = 0; + + assert_se(runtime_dir = setup_fake_runtime_dir()); TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask()); + return rc; } diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 52b34c03df..361d1e7b0b 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -23,9 +23,12 @@ #include "bus-util.h" #include "manager.h" +#include "rm-rf.h" #include "test-helper.h" +#include "tests.h" int main(int argc, char *argv[]) { + _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; Manager *m = NULL; Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL; @@ -34,6 +37,8 @@ int main(int argc, char *argv[]) { Job *j; int r; + assert_se(runtime_dir = setup_fake_runtime_dir()); + /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); r = manager_new(UNIT_FILE_USER, true, &m); diff --git a/src/test/test-path.c b/src/test/test-path.c index e0c8db50ae..435cafd83a 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -30,6 +30,7 @@ #include "string-util.h" #include "strv.h" #include "test-helper.h" +#include "tests.h" #include "unit.h" #include "util.h" @@ -243,7 +244,7 @@ static void test_path_makedirectory_directorymode(Manager *m) { } int main(int argc, char *argv[]) { - test_function_t tests[] = { + static const test_function_t tests[] = { test_path_exists, test_path_existsglob, test_path_changed, @@ -253,12 +254,15 @@ int main(int argc, char *argv[]) { test_path_makedirectory_directorymode, NULL, }; - test_function_t *test = NULL; + + _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; + const test_function_t *test = NULL; Manager *m = NULL; log_parse_environment(); log_open(); + assert_se(runtime_dir = setup_fake_runtime_dir()); assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0); for (test = tests; test && *test; test++) { diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index 5083cd53c2..3e9caafc71 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -21,9 +21,12 @@ #include "macro.h" #include "manager.h" +#include "rm-rf.h" #include "test-helper.h" +#include "tests.h" int main(int argc, char *argv[]) { + _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; Manager *m = NULL; Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched; Service *ser; @@ -31,6 +34,8 @@ int main(int argc, char *argv[]) { FDSet *fdset = NULL; int r; + assert_se(runtime_dir = setup_fake_runtime_dir()); + /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); r = manager_new(UNIT_FILE_USER, true, &m); diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 7f2fee772b..114ddf8478 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -35,10 +35,12 @@ #include "install.h" #include "load-fragment.h" #include "macro.h" +#include "rm-rf.h" #include "specifier.h" #include "string-util.h" #include "strv.h" #include "test-helper.h" +#include "tests.h" #include "user-util.h" #include "util.h" @@ -840,11 +842,14 @@ static void test_config_parse_pass_environ(void) { } int main(int argc, char *argv[]) { + _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; int r; log_parse_environment(); log_open(); + assert_se(runtime_dir = setup_fake_runtime_dir()); + r = test_unit_file_get_set(); test_config_parse_exec(); test_config_parse_capability_set(); -- cgit v1.2.3-54-g00ecf From d94c2b06f9800d635f3cb05b4a6c67145aa1ba09 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 11 Apr 2016 17:24:08 +0200 Subject: machinectl: add new "machinectl clean" command This new command removes all, or all hidden container images that have been downloaded. --- man/machinectl.xml | 32 ++++++++++++++--- src/machine/machinectl.c | 46 ++++++++++++++++++++++++ src/machine/machined-dbus.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ src/shared/machine-image.c | 12 +++---- src/shared/machine-image.h | 26 ++++++++++++++ 5 files changed, 192 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/man/machinectl.xml b/man/machinectl.xml index cee4bb72ce..a77d2419af 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -133,7 +133,9 @@ When listing VM or container images, do not suppress images beginning in a dot character - (.). + (.). + + When cleaning VM or container images, remove all images, not just hidden ones. @@ -217,9 +219,11 @@ When used with bind, applies - a read-only bind mount. - + a read-only bind mount. + When used with clone, import-raw or import-tar a + read-only container or VM image is created. + @@ -599,7 +603,10 @@ 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. + change them in the copy. + + If combined with the switch a read-only cloned image is + created. @@ -660,6 +667,23 @@ itself. + + clean + + Remove hidden VM or container images (or all). This command removes all hidden machine images + from /var/lib/machines, i.e. those whose name begins with a dot. Use machinectl + list-images --all to see a list of all machine images, including the hidden ones. + + When combined with the switch removes all images, not just hidden ones. This + command effectively empties /var/lib/machines. + + Note that commands such as machinectl pull-tar or machinectl + pull-raw usually create hidden, read-only, unmodified machine images from the downloaded image first, + before cloning a writable working copy of it, in order to avoid duplicate downloads in case of images that are + reused multiple times. Use machinectl clean to remove old, hidden images created this + way. + + Image Transfer Commands diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 1d3264a1de..35177aa29e 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2338,6 +2338,50 @@ static int set_limit(int argc, char *argv[], void *userdata) { return 0; } +static int clean_images(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + uint64_t usage, total = 0; + char fb[FORMAT_BYTES_MAX]; + sd_bus *bus = userdata; + const char *name; + unsigned c = 0; + int r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "CleanPool", + &error, + &reply, + "s", arg_all ? "all" : "hidden"); + if (r < 0) + return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r)); + + r = sd_bus_message_enter_container(reply, 'a', "(st)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) { + log_info("Removed image '%s'. Freed exclusive disk space: %s", + name, format_bytes(fb, sizeof(fb), usage)); + + total += usage; + c++; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + log_info("Removed %u images in total. Total freed exclusive disk space %s.", + c, format_bytes(fb, sizeof(fb), total)); + + return 0; +} + static int help(int argc, char *argv[], void *userdata) { printf("%s [OPTIONS...] {COMMAND} ...\n\n" @@ -2396,6 +2440,7 @@ static int help(int argc, char *argv[], void *userdata) { " read-only NAME [BOOL] Mark or unmark image read-only\n" " remove NAME... Remove an image\n" " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n" + " clean Remove hidden (or all) images\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" @@ -2635,6 +2680,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "list-transfers", VERB_ANY, 1, 0, list_transfers }, { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer }, { "set-limit", 2, 3, 0, set_limit }, + { "clean", VERB_ANY, 1, 0, clean_images }, {} }; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 20894433e7..c9639c3cf2 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -802,6 +802,93 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata, return bus_image_method_mark_read_only(message, i, error); } +static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) { + enum { + REMOVE_ALL, + REMOVE_HIDDEN, + } mode; + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(image_hashmap_freep) Hashmap *images = NULL; + Manager *m = userdata; + Image *image; + const char *mm; + Iterator i; + int r; + + assert(message); + + r = sd_bus_message_read(message, "s", &mm); + if (r < 0) + return r; + + if (streq(mm, "all")) + mode = REMOVE_ALL; + else if (streq(mm, "hidden")) + mode = REMOVE_HIDDEN; + else + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm); + + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.machine1.manage-machines", + NULL, + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + images = hashmap_new(&string_hash_ops); + if (!images) + return -ENOMEM; + + r = image_discover(images); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; + + HASHMAP_FOREACH(image, images, i) { + + /* We can't remove vendor images (i.e. those in /usr) */ + if (IMAGE_IS_VENDOR(image)) + continue; + + if (IMAGE_IS_HOST(image)) + continue; + + if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image)) + continue; + + r = image_remove(image); + if (r == -EBUSY) /* keep images that are currently being used. */ + continue; + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to remove image %s: %m", image->name); + + r = sd_bus_message_append(reply, "(st)", image->name, image->usage_exclusive); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; uint64_t limit; @@ -1144,6 +1231,7 @@ const sd_bus_vtable manager_vtable[] = { 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_METHOD("CleanPool", "s", "a(st)", method_clean_pool, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index d2f1c4a40c..bebfc40efe 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -401,8 +401,7 @@ int image_remove(Image *i) { assert(i); - if (path_equal(i->path, "/") || - path_startswith(i->path, "/usr")) + if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i)) return -EROFS; settings = image_settings_path(i); @@ -474,8 +473,7 @@ int image_rename(Image *i, const char *new_name) { if (!image_name_is_valid(new_name)) return -EINVAL; - if (path_equal(i->path, "/") || - path_startswith(i->path, "/usr")) + if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i)) return -EROFS; settings = image_settings_path(i); @@ -642,8 +640,7 @@ int image_read_only(Image *i, bool b) { int r; assert(i); - if (path_equal(i->path, "/") || - path_startswith(i->path, "/usr")) + if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i)) return -EROFS; /* Make sure we don't interfere with a running nspawn */ @@ -751,8 +748,7 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile int image_set_limit(Image *i, uint64_t referenced_max) { assert(i); - if (path_equal(i->path, "/") || - path_startswith(i->path, "/usr")) + if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i)) return -EROFS; if (i->type != IMAGE_SUBVOLUME) diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index 31b720d50c..7410168c4f 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -25,6 +25,8 @@ #include "hashmap.h" #include "lockfile-util.h" #include "macro.h" +#include "path-util.h" +#include "string-util.h" #include "time-util.h" typedef enum ImageType { @@ -75,3 +77,27 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile int image_name_lock(const char *name, int operation, LockFile *ret); int image_set_limit(Image *i, uint64_t referenced_max); + +static inline bool IMAGE_IS_HIDDEN(const struct Image *i) { + assert(i); + + return i->name && i->name[0] == '.'; +} + +static inline bool IMAGE_IS_VENDOR(const struct Image *i) { + assert(i); + + return i->path && path_startswith(i->path, "/usr"); +} + +static inline bool IMAGE_IS_HOST(const struct Image *i) { + assert(i); + + if (i->name && streq(i->name, ".host")) + return true; + + if (i->path && path_equal(i->path, "/")) + return true; + + return false; +} -- cgit v1.2.3-54-g00ecf From 8e20adcaa0cf06a85d36e2fda35fa1d70d5d63c8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 11 Apr 2016 17:57:05 +0200 Subject: core: make sure we generate a nicer error when a linked unit is attempted to be enabled We don't allow using config symlinks to enable units, but the error message we printed was awful. Fix that, and generate a more readable error. Fixes #3010. --- src/core/dbus-manager.c | 35 ++++++++++++++++++------------- src/libsystemd/sd-bus/bus-common-errors.c | 1 + src/libsystemd/sd-bus/bus-common-errors.h | 1 + src/systemctl/systemctl.c | 2 ++ 4 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 41f27ec26b..0939a55182 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1607,6 +1607,19 @@ fail: return r; } +static int install_error(sd_bus_error *error, int c) { + assert(c < 0); + + if (c == -ESHUTDOWN) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); + if (c == -EADDRNOTAVAIL) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated."); + if (c == -ELOOP) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED, "Refusing to operate on linked unit file."); + + return c; +} + static int method_enable_unit_files_generic( sd_bus_message *message, Manager *m, @@ -1638,12 +1651,8 @@ static int method_enable_unit_files_generic( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes); - if (r == -ESHUTDOWN) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); - if (r == -EADDRNOTAVAIL) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated."); if (r < 0) - return r; + return install_error(error, r); return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes); } @@ -1709,7 +1718,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes); if (r < 0) - return r; + return install_error(error, r); return reply_unit_file_changes_and_free(m, message, r, changes, n_changes); } @@ -1745,7 +1754,7 @@ static int method_disable_unit_files_generic( r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes); if (r < 0) - return r; + return install_error(error, r); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1780,7 +1789,7 @@ static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_ r = unit_file_revert(m->unit_file_scope, NULL, l, &changes, &n_changes); if (r < 0) - return r; + return install_error(error, r); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1811,7 +1820,7 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes); if (r < 0) - return r; + return install_error(error, r); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1852,7 +1861,7 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes); if (r < 0) { unit_file_changes_free(changes, n_changes); - return r; + return install_error(error, r); } return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); @@ -1890,12 +1899,8 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd return -EINVAL; r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); - if (r == -ESHUTDOWN) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); - if (r == -EADDRNOTAVAIL) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated."); if (r < 0) - return r; + return install_error(error, r); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index f16878cd1a..02e3bf904c 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -39,6 +39,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, ESHUTDOWN), SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_GENERATED, EADDRNOTAVAIL), + SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_LINKED, ELOOP), SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR), SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM), SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index c16605ba87..c8f369cb78 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -35,6 +35,7 @@ #define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" #define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" #define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated" +#define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked" #define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" #define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b94af9cf08..9efdc63dde 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5446,6 +5446,8 @@ static int enable_unit(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Unit file is masked."); if (r == -EADDRNOTAVAIL) return log_error_errno(r, "Unit file is transient or generated."); + if (r == -ELOOP) + return log_error_errno(r, "Refusing to operate on linked unit file."); if (r < 0) return log_error_errno(r, "Operation failed: %m"); -- cgit v1.2.3-54-g00ecf From 50724a7afcaea472d9143a169c51318abf5f69ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 11 Apr 2016 18:07:04 +0200 Subject: sd-lldp: drop LLDP ethernet export from sd-lldp.h We only use it for the Tx code anyway, hence sd-lldp.h shouldn't expose it, as it only implements Rx. --- src/network/networkd-lldp-tx.c | 6 ++++-- src/systemd/sd-lldp.h | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index c940e63052..6bde04bc32 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -30,6 +30,8 @@ #include "string-util.h" #include "unaligned.h" +#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } + /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */ #define LLDP_TX_FAST_INIT 4U @@ -127,7 +129,7 @@ static int lldp_make_packet( h = (struct ether_header*) packet; h->ether_type = htobe16(ETHERTYPE_LLDP); - memcpy(h->ether_dhost, &(struct ether_addr) { SD_LLDP_MULTICAST_ADDR }, ETH_ALEN); + memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN); memcpy(h->ether_shost, hwaddr, ETH_ALEN); p = (uint8_t*) packet + sizeof(struct ether_header); @@ -199,7 +201,7 @@ static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) .ll.sll_protocol = htobe16(ETHERTYPE_LLDP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, - .ll.sll_addr = SD_LLDP_MULTICAST_ADDR, + .ll.sll_addr = LLDP_MULTICAST_ADDR, }; _cleanup_close_ int fd = -1; diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index fa6ab9ad3b..4ea7be7f38 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -33,8 +33,6 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_lldp sd_lldp; typedef struct sd_lldp_neighbor sd_lldp_neighbor; -#define SD_LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } - /* IEEE 802.3AB Clause 9: TLV Types */ enum { SD_LLDP_TYPE_END = 0, -- cgit v1.2.3-54-g00ecf From 60ca5641b562d0d8021be652b3f7c9934d025dd5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 11 Apr 2016 18:07:45 +0200 Subject: sd-lldp: minor whitespace fixes --- src/systemd/sd-lldp.h | 72 +++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 4ea7be7f38..5772d5794a 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -35,16 +35,16 @@ typedef struct sd_lldp_neighbor sd_lldp_neighbor; /* IEEE 802.3AB Clause 9: TLV Types */ enum { - SD_LLDP_TYPE_END = 0, - SD_LLDP_TYPE_CHASSIS_ID = 1, - SD_LLDP_TYPE_PORT_ID = 2, - SD_LLDP_TYPE_TTL = 3, - SD_LLDP_TYPE_PORT_DESCRIPTION = 4, - SD_LLDP_TYPE_SYSTEM_NAME = 5, - SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6, - SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7, - SD_LLDP_TYPE_MGMT_ADDRESS = 8, - SD_LLDP_TYPE_PRIVATE = 127, + SD_LLDP_TYPE_END = 0, + SD_LLDP_TYPE_CHASSIS_ID = 1, + SD_LLDP_TYPE_PORT_ID = 2, + SD_LLDP_TYPE_TTL = 3, + SD_LLDP_TYPE_PORT_DESCRIPTION = 4, + SD_LLDP_TYPE_SYSTEM_NAME = 5, + SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6, + SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7, + SD_LLDP_TYPE_MGMT_ADDRESS = 8, + SD_LLDP_TYPE_PRIVATE = 127, }; /* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ @@ -61,28 +61,28 @@ enum { /* IEEE 802.3AB Clause 9.5.3: Port subtype */ enum { - SD_LLDP_PORT_SUBTYPE_RESERVED = 0, - SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, - SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, - SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, - SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, - SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, - SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, + SD_LLDP_PORT_SUBTYPE_RESERVED = 0, + SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, + SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, + SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, + SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, + SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, + SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, + SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, }; enum { - SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, - SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, - SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, - SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, - SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, - SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, - SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, - SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, - SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, - SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, - SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, + SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, + SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, + SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, + SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, + SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, + SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, + SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, + SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, + SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, + SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, + SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, }; #define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) @@ -102,13 +102,13 @@ enum { #define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } enum { - SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, - SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, - SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, - SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, - SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, - SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, - SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, + SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, + SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, + SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, + SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, + SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, + SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, + SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, }; typedef enum sd_lldp_event { -- cgit v1.2.3-54-g00ecf From f9ba08fb4fcd64aaf6896d8a5b586180f244fcb7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 11 Apr 2016 18:20:02 +0200 Subject: core: keep track of the mtime of the transient unit file we wrote Otherwise "systemctl status" will immediately report that our unit file is out of date. --- src/core/unit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index 08f3288776..fb88260d23 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1243,6 +1243,8 @@ int unit_load(Unit *u) { fclose(u->transient_file); u->transient_file = NULL; + + u->dropin_mtime = now(CLOCK_REALTIME); } if (UNIT_VTABLE(u)->load) { -- cgit v1.2.3-54-g00ecf From 99ef0330e15db969f7b096cedeecf63a09efbe86 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Apr 2016 13:51:06 +0200 Subject: core: make sure we always free the list of changes --- src/core/dbus-manager.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 0939a55182..2392ed6c16 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1651,8 +1651,10 @@ static int method_enable_unit_files_generic( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes); - if (r < 0) + if (r < 0) { + unit_file_changes_free(changes, n_changes); return install_error(error, r); + } return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes); } @@ -1717,8 +1719,10 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes); - if (r < 0) + if (r < 0) { + unit_file_changes_free(changes, n_changes); return install_error(error, r); + } return reply_unit_file_changes_and_free(m, message, r, changes, n_changes); } @@ -1753,8 +1757,10 @@ static int method_disable_unit_files_generic( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes); - if (r < 0) + if (r < 0) { + unit_file_changes_free(changes, n_changes); return install_error(error, r); + } return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1788,8 +1794,10 @@ static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = unit_file_revert(m->unit_file_scope, NULL, l, &changes, &n_changes); - if (r < 0) + if (r < 0) { + unit_file_changes_free(changes, n_changes); return install_error(error, r); + } return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1819,8 +1827,10 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes); - if (r < 0) + if (r < 0) { + unit_file_changes_free(changes, n_changes); return install_error(error, r); + } return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1899,8 +1909,10 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd return -EINVAL; r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); - if (r < 0) + if (r < 0) { + unit_file_changes_free(changes, n_changes); return install_error(error, r); + } return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } -- cgit v1.2.3-54-g00ecf From 0bed31c1038c439cc5956fb44017ba28e503095b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Apr 2016 13:51:28 +0200 Subject: test-dnssec: drop unused variable --- src/resolve/test-dnssec.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index 155be9946f..b3018e8239 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -230,7 +230,6 @@ static void test_dnssec_verify_rrset2(void) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; DnssecResult result; - int r; nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); assert_se(nsec); -- cgit v1.2.3-54-g00ecf From 3c6d8e57e870ed56dbb53ce62f0a3d32de101cd8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Apr 2016 16:13:28 +0200 Subject: systemctl: when we want to know whether there's a native unit file, don't choke on ELOOP ELOOP indicates that there's a symlink in /etc for a native unit file, and that's completely OK. --- src/systemctl/systemctl.c | 4 ++-- src/sysv-generator/sysv-generator.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9efdc63dde..f0e788a508 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5272,9 +5272,9 @@ static int enable_sysv_units(const char *verb, char **args) { continue; j = unit_file_exists(arg_scope, &paths, name); - if (j < 0) + if (j < 0 && !IN_SET(j, -ELOOP, -ESHUTDOWN, -EADDRNOTAVAIL)) return log_error_errno(j, "Failed to lookup unit file state: %m"); - found_native = j > 0; + found_native = j != 0; /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled, * prefer the native unit */ diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index cae920eb3b..9392a3d2b5 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -807,10 +807,10 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { continue; r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name); - if (r < 0) { + if (r < 0 && !IN_SET(r, -ELOOP, -ESHUTDOWN, -EADDRNOTAVAIL)) { log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); continue; - } else if (r > 0) { + } else if (r != 0) { log_debug("Native unit for %s already exists, skipping.", name); continue; } -- cgit v1.2.3-54-g00ecf From 1116e14c49ac1291eb5e46fcf5e691ef57267b54 Mon Sep 17 00:00:00 2001 From: Nicolas Braud-Santoni Date: Tue, 12 Apr 2016 18:00:19 +0200 Subject: load-fragment: Resolve specifiers in DeviceAllow (#3019) Closes #1602 --- src/core/load-fragment.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index f1a874cfdf..a54f0d764c 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2847,11 +2847,12 @@ int config_parse_device_allow( void *data, void *userdata) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *t = NULL; CGroupContext *c = data; CGroupDeviceAllow *a; - const char *m; + const char *m = NULL; size_t n; + int r; if (isempty(rvalue)) { while (c->device_allow) @@ -2860,8 +2861,16 @@ int config_parse_device_allow( return 0; } - n = strcspn(rvalue, WHITESPACE); - path = strndup(rvalue, n); + r = unit_full_printf(userdata, rvalue, &t); + if(r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve specifiers in %s, ignoring: %m", + rvalue); + } + + n = strcspn(t, WHITESPACE); + + path = strndup(t, n); if (!path) return log_oom(); @@ -2872,7 +2881,7 @@ int config_parse_device_allow( return 0; } - m = rvalue + n + strspn(rvalue + n, WHITESPACE); + m = t + n + strspn(t + n, WHITESPACE); if (isempty(m)) m = "rwm"; -- cgit v1.2.3-54-g00ecf From 78e334b50f12a3ef386fb5de03d0549fa853c692 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 8 Apr 2016 22:20:22 -0400 Subject: basic/util: silence stupid gcc warnings about unitialized variable --- src/basic/util.c | 7 ++++--- src/core/machine-id-setup.c | 9 +++++---- src/core/unit.c | 9 +++++---- 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/basic/util.c b/src/basic/util.c index 957b0e1ff1..b70c50047f 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -792,10 +792,11 @@ int update_reboot_parameter_and_warn(const char *param) { return 0; } - RUN_WITH_UMASK(0022) + RUN_WITH_UMASK(0022) { r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE); - if (r < 0) - return log_warning_errno(r, "Failed to write reboot parameter file: %m"); + if (r < 0) + return log_warning_errno(r, "Failed to write reboot parameter file: %m"); + } return 0; } diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 86da16c31e..9de528b6cf 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -259,11 +259,12 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) { /* Hmm, we couldn't write it? So let's write it to * /run/machine-id as a replacement */ - RUN_WITH_UMASK(0022) + RUN_WITH_UMASK(0022) { r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE); - if (r < 0) { - (void) unlink(run_machine_id); - return log_error_errno(r, "Cannot write %s: %m", run_machine_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 */ diff --git a/src/core/unit.c b/src/core/unit.c index fb88260d23..49c990c2d7 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3480,11 +3480,12 @@ int unit_make_transient(Unit *u) { /* Let's open the file we'll write the transient settings into. This file is kept open as long as we are * creating the transient, and is closed in unit_load(), as soon as we start loading the file. */ - RUN_WITH_UMASK(0022) + RUN_WITH_UMASK(0022) { f = fopen(path, "we"); - if (!f) { - free(path); - return -errno; + if (!f) { + free(path); + return -errno; + } } if (u->transient_file) -- cgit v1.2.3-54-g00ecf From 81d621034badfd75edb5e1fc88334af9a87a18e3 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 9 Apr 2016 14:04:09 -0400 Subject: tree-wide: remove useless NULLs from strjoina The coccinelle patch didn't work in some places, I have no idea why. --- coccinelle/strjoina.cocci | 6 ++++++ src/core/unit.c | 13 ++++++------- src/coredump/coredump.c | 2 +- src/login/logind-session.c | 2 +- src/machine/machine-dbus.c | 2 +- src/resolve/resolved-dns-dnssec.c | 2 +- src/shared/bus-util.c | 4 ++-- src/shared/path-lookup.c | 2 +- src/systemctl/systemctl.c | 2 +- 9 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 coccinelle/strjoina.cocci (limited to 'src') diff --git a/coccinelle/strjoina.cocci b/coccinelle/strjoina.cocci new file mode 100644 index 0000000000..a6236eb0f9 --- /dev/null +++ b/coccinelle/strjoina.cocci @@ -0,0 +1,6 @@ +@@ +expression n, m; +expression list s; +@@ +- n = strjoina(m, s, NULL); ++ n = strjoina(m, s); diff --git a/src/core/unit.c b/src/core/unit.c index 49c990c2d7..c60ae2be9d 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2518,12 +2518,11 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) { return -EBUSY; match = strjoina("type='signal'," - "sender='org.freedesktop.DBus'," - "path='/org/freedesktop/DBus'," - "interface='org.freedesktop.DBus'," - "member='NameOwnerChanged'," - "arg0='", name, "'", - NULL); + "sender='org.freedesktop.DBus'," + "path='/org/freedesktop/DBus'," + "interface='org.freedesktop.DBus'," + "member='NameOwnerChanged'," + "arg0='", name, "'"); return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u); } @@ -3437,7 +3436,7 @@ int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char * if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) return 0; - ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL); + ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data); return unit_write_drop_in(u, mode, name, ndata); } diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 085909c20c..f65cb6f9dd 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -1095,7 +1095,7 @@ static int process_kernel(int argc, char* argv[]) { IOVEC_SET_STRING(iovec[n_iovec++], core_environ); } - core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL); + core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000"); IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp); IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); diff --git a/src/login/logind-session.c b/src/login/logind-session.c index e088225beb..676fbc15a3 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -513,7 +513,7 @@ static int session_start_scope(Session *s) { if (!scope) return log_oom(); - description = strjoina("Session ", s->id, " of user ", s->user->name, NULL); + description = strjoina("Session ", s->id, " of user ", s->user->name); r = manager_start_scope( s->manager, diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index c7ff0efac8..ab54d9e934 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -730,7 +730,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu return r; /* Name and mode */ - unit = strjoina("container-shell@", p, ".service", NULL); + unit = strjoina("container-shell@", p, ".service"); r = sd_bus_message_append(tm, "ss", unit, "fail"); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 0af7551425..a54aed3a63 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -1734,7 +1734,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) if (r <= 0) return r; - wc = strjoina("*.", common_suffix, NULL); + wc = strjoina("*.", common_suffix); return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name); } diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 0caaca03c7..2b86b1fcd6 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -2050,8 +2050,8 @@ static void log_job_error_with_service_result(const char* service, const char *r _cleanup_free_ char *t; t = strv_join((char**) extra_args, " "); - systemctl = strjoina("systemctl ", t ?: "", NULL); - journalctl = strjoina("journalctl ", t ?: "", NULL); + systemctl = strjoina("systemctl ", t ? : ""); + journalctl = strjoina("journalctl ", t ? : ""); } if (!isempty(result)) { diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index ca69a0aef2..167108ee1b 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -249,7 +249,7 @@ static int acquire_generator_dirs( if (!e) return -ENXIO; - prefix = strjoina(e, "/systemd/", NULL); + prefix = strjoina(e, "/systemd/"); break; } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index f0e788a508..65b52be04a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3254,7 +3254,7 @@ static int kill_unit(int argc, char *argv[], void *userdata) { /* --fail was specified */ if (streq(arg_job_mode, "fail")) - kill_who = strjoina(arg_kill_who, "-fail", NULL); + kill_who = strjoina(arg_kill_who, "-fail"); r = expand_names(bus, strv_skip(argv, 1), NULL, &names); if (r < 0) -- cgit v1.2.3-54-g00ecf From f5faf24679c81217bf1bc21b9228dd651db387d7 Mon Sep 17 00:00:00 2001 From: Ismo Puustinen Date: Wed, 13 Apr 2016 15:38:03 +0300 Subject: sd-bus: query pid also when searching for supplementary gids If the SD_BUS_CREDS_SUPPLEMENTARY_GIDS value is requested, the pid is queried to find out the supplementary gids value from /proc/pid/status. Otherwise sd_bus_creds_get_supplementary_gids() won't work unless some other value in mask triggered fetching the pid information. --- src/libsystemd/sd-bus/bus-control.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index e860876c12..52128e7b5c 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -678,6 +678,7 @@ int bus_get_name_creds_kdbus( (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_SUPPLEMENTARY_GIDS| 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| SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| @@ -795,6 +796,7 @@ static int bus_get_name_creds_dbus1( ((mask & SD_BUS_CREDS_AUGMENT) && (mask & (SD_BUS_CREDS_UID|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_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| SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| @@ -947,6 +949,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** (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_SUPPLEMENTARY_GIDS| 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| SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| -- cgit v1.2.3-54-g00ecf From ea9b54f827feff046d7d6e5c485d01cf98214762 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 13 Apr 2016 21:09:32 -0400 Subject: test-strv: add a test that extending empty strv works as expected Just making sure :) --- src/test/test-strv.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/test/test-strv.c b/src/test/test-strv.c index fea1f848cd..fc01dcfaf1 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -358,7 +358,7 @@ static void test_strv_extend_strv_concat(void) { } static void test_strv_extend_strv(void) { - _cleanup_strv_free_ char **a = NULL, **b = NULL; + _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL; a = strv_new("abc", "def", "ghi", NULL); b = strv_new("jkl", "mno", "abc", "pqr", NULL); @@ -373,8 +373,14 @@ static void test_strv_extend_strv(void) { assert_se(streq(a[3], "jkl")); assert_se(streq(a[4], "mno")); assert_se(streq(a[5], "pqr")); - assert_se(strv_length(a) == 6); + + assert_se(strv_extend_strv(&n, b, false) >= 0); + assert_se(streq(n[0], "jkl")); + assert_se(streq(n[1], "mno")); + assert_se(streq(n[2], "abc")); + assert_se(streq(n[3], "pqr")); + assert_se(strv_length(n) == 4); } static void test_strv_extend(void) { -- cgit v1.2.3-54-g00ecf From e215d211d25139a46970101525ebdde874daf2f0 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 13 Apr 2016 21:10:33 -0400 Subject: shared/path-lookup: fix leak CID #1354671: char **l would be leaked. Also rename l to paths, to make the code easier to read, and do strv deduplication immediately when extending. No need to allocate strings to remove them a few lines down. --- src/shared/path-lookup.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 167108ee1b..80a2ea7940 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -451,7 +451,7 @@ int lookup_paths_init( *transient = NULL, *persistent_control = NULL, *runtime_control = NULL; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ - char **l = NULL; + _cleanup_strv_free_ char **paths = NULL; const char *e; int r; @@ -506,13 +506,12 @@ int lookup_paths_init( /* FIXME: empty components in other places should be * rejected. */ - r = path_split_and_make_absolute(e, &l); + r = path_split_and_make_absolute(e, &paths); if (r < 0) return r; - } else - l = NULL; + } - if (!l || append) { + if (!paths || append) { /* Let's figure something out. */ _cleanup_strv_free_ char **add = NULL; @@ -587,14 +586,9 @@ int lookup_paths_init( if (!add) return -ENOMEM; - if (l) { - r = strv_extend_strv(&l, add, false); - if (r < 0) + r = strv_extend_strv(&paths, add, true); + if (r < 0) return r; - } else { - l = add; - add = NULL; - } } r = patch_root_prefix(&persistent_config, root); @@ -626,12 +620,12 @@ int lookup_paths_init( if (r < 0) return r; - r = patch_root_prefix_strv(l, root); + r = patch_root_prefix_strv(paths, root); if (r < 0) return -ENOMEM; - p->search_path = strv_uniq(l); - l = NULL; + p->search_path = strv_uniq(paths); + paths = NULL; p->persistent_config = persistent_config; p->runtime_config = runtime_config; -- cgit v1.2.3-54-g00ecf From 78df0edc1b594017b1d3493eb2033d8a92d9d43f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 13 Apr 2016 21:11:28 -0400 Subject: systemctl: fix leak CID #1354670. --- src/systemctl/systemctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 65b52be04a..91829fcbcf 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6087,8 +6087,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { return r; STRV_FOREACH(name, names) { - _cleanup_free_ char *path = NULL; - char *new_path, *tmp_path; + _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL; r = unit_find_paths(bus, *name, &lp, &path, NULL); if (r < 0) @@ -6111,6 +6110,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { r = strv_push_pair(paths, new_path, tmp_path); if (r < 0) return log_oom(); + new_path = tmp_path = NULL; } return 0; -- cgit v1.2.3-54-g00ecf From 23d8b221c0490b1b00044072b329d3ab76d561e3 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 14 Apr 2016 15:26:57 +0530 Subject: networkd: Add support to configure proxy arp support to interfaces (#3020) Fixes: #2889 --- man/systemd.network.xml | 11 +++++++++- src/network/networkd-link.c | 35 ++++++++++++++++++++++++++++++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 1 + 5 files changed, 48 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index c9ef041004..d7947836e9 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -548,6 +548,15 @@ Defaults to unset. + + ProxyARP= + A boolean. Configures proxy ARP. Proxy ARP is the technique in which one host, + usually a router, answers ARP requests intended for another machine. By "faking" its identity, + the router accepts responsibility for routing packets to the "real" destination. (see RFC 1027. + Defaults to unset. + + Bridge= @@ -844,7 +853,7 @@ global DUID that may be specified in networkd.conf 5. - The configured DHCP DUID should conform to the specification in + The configured DHCP DUID should conform to the specification in RFC 3315, RFC 6355. diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 88b3cbe90a..9059a68fe3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -165,6 +165,21 @@ static bool link_ipv6_forward_enabled(Link *link) { return link->network->ip_forward & ADDRESS_FAMILY_IPV6; } +static bool link_proxy_arp_enabled(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return false; + + if (!link->network) + return false; + + if (link->network->proxy_arp < 0) + return false; + + return true; +} + static bool link_ipv6_accept_ra_enabled(Link *link) { assert(link); @@ -1039,6 +1054,22 @@ static int link_set_bridge_fdb(Link *const link) { return r; } +static int link_set_proxy_arp(Link *const link) { + const char *p = NULL; + int r; + + if (!link_proxy_arp_enabled(link)) + return 0; + + p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp"); + + r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m"); + + return 0; +} + static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -2167,6 +2198,10 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = link_set_proxy_arp(link); + if (r < 0) + return r; + r = link_set_ipv4_forward(link); if (r < 0) return r; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 9793938080..1da99cd5bc 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -61,6 +61,7 @@ Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits) Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit) +Network.ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp) Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) Address.Address, config_parse_address, 0, 0 Address.Peer, config_parse_address, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 5946ba18dc..1c7adf5180 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -132,6 +132,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_dad_transmits = -1; network->ipv6_hop_limit = -1; network->duid_type = _DUID_TYPE_INVALID; + network->proxy_arp = -1; r = config_parse(NULL, filename, file, "Match\0" diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 5400a8bc9d..3d44113b05 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -139,6 +139,7 @@ struct Network { int ipv6_accept_ra; int ipv6_dad_transmits; int ipv6_hop_limit; + int proxy_arp; union in_addr_union ipv6_token; IPv6PrivacyExtensions ipv6_privacy_extensions; -- cgit v1.2.3-54-g00ecf From cacf980ed44a28e276a6cc7f8fc41f991e2ab354 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 15 Apr 2016 01:14:29 +0200 Subject: core/mount-setup.c: also relabel /dev/shm for selinux (#3039) daemons, which wish to transition state from the initramfs to the real root, might use /dev/shm for their state. As /dev is not relabeled across mount points, /dev/shm has to be relabled explicitly. --- src/core/mount-setup.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 32fe51c67e..40fc548b42 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -375,6 +375,7 @@ int mount_setup(bool loaded_policy) { before_relabel = now(CLOCK_MONOTONIC); nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); + nftw("/dev/shm", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); after_relabel = now(CLOCK_MONOTONIC); -- cgit v1.2.3-54-g00ecf From bac75eb3783c5481be9833c3b1551b819fd3fb60 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Apr 2016 17:41:46 -0400 Subject: systemctl: make --root=/ disable dbus again Before 0f03c2a4c093 specifying any path would cause the systemctl client to do the installation itself, instead of going over dbus. Restore that behaviour. --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 91829fcbcf..9310a0f430 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6718,7 +6718,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, true, &arg_root); + r = parse_path_argument_and_warn(optarg, false, &arg_root); if (r < 0) return r; break; -- cgit v1.2.3-54-g00ecf From 103a5027f6bfec1ca2963803d9ed9af698acc82f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Apr 2016 18:21:58 -0400 Subject: sd-bus: use IN_SET --- src/libsystemd/sd-bus/sd-bus.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 862f26aad7..04da94e7e3 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1778,7 +1778,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, r = bus_write_message(bus, m, hint_sync_call, &idx); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); return -ECONNRESET; } @@ -2083,7 +2083,7 @@ _public_ int sd_bus_call( r = bus_read_message(bus, false, 0); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = -ECONNRESET; } @@ -2116,7 +2116,7 @@ _public_ int sd_bus_call( r = dispatch_wqueue(bus); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = -ECONNRESET; } @@ -2766,7 +2766,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit case BUS_OPENING: r = bus_socket_process_opening(bus); - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = 1; } else if (r < 0) @@ -2777,7 +2777,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit case BUS_AUTHENTICATING: r = bus_socket_process_authenticating(bus); - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = 1; } else if (r < 0) @@ -2791,7 +2791,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit case BUS_RUNNING: case BUS_HELLO: r = process_running(bus, hint_priority, priority, ret); - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = 1; @@ -2914,7 +2914,7 @@ _public_ int sd_bus_flush(sd_bus *bus) { for (;;) { r = dispatch_wqueue(bus); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); return -ECONNRESET; } -- cgit v1.2.3-54-g00ecf From 6e1045e538a08ec68787359820a57b8b637ade70 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Apr 2016 18:31:42 -0400 Subject: journald: rewrite function with switch, fix handling of -ESHUTDOWN The comments and the log messages are next to one another, so it's easier to check that the messages match the comments. The sign was omitted in the check for -ESHUTDOWN, so it was never matched. --- src/journal/journald-server.c | 48 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 2939322925..b1d1bf9e14 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -492,38 +492,36 @@ static void server_cache_hostname(Server *s) { } static bool shall_try_append_again(JournalFile *f, int r) { - - /* -E2BIG Hit configured limit - -EFBIG Hit fs limit - -EDQUOT Quota limit hit - -ENOSPC Disk full - -EIO I/O error of some kind (mmap) - -EHOSTDOWN Other machine - -EBUSY Unclean shutdown - -EPROTONOSUPPORT Unsupported feature - -EBADMSG Corrupted - -ENODATA Truncated - -ESHUTDOWN Already archived - -EIDRM Journal file has been deleted */ - - if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC) + switch(r) { + case -E2BIG: /* Hit configured limit */ + case -EFBIG: /* Hit fs limit */ + case -EDQUOT: /* Quota limit hit */ + case -ENOSPC: /* Disk full */ log_debug("%s: Allocation limit reached, rotating.", f->path); - else if (r == -EHOSTDOWN) + return true; + case -EIO: /* I/O error of some kind (mmap) */ + log_warning("%s: IO error, rotating.", f->path); + return true; + case -EHOSTDOWN: /* Other machine */ log_info("%s: Journal file from other machine, rotating.", f->path); - else if (r == -EBUSY) + return true; + case -EBUSY: /* Unclean shutdown */ log_info("%s: Unclean shutdown, rotating.", f->path); - else if (r == -EPROTONOSUPPORT) + return true; + case -EPROTONOSUPPORT: /* Unsupported feature */ log_info("%s: Unsupported feature, rotating.", f->path); - else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN) + return true; + case -EBADMSG: /* Corrupted */ + case -ENODATA: /* Truncated */ + case -ESHUTDOWN: /* Already archived */ log_warning("%s: Journal file corrupted, rotating.", f->path); - else if (r == -EIO) - log_warning("%s: IO error, rotating.", f->path); - else if (r == -EIDRM) + return true; + case -EIDRM: /* Journal file has been deleted */ log_warning("%s: Journal file has been deleted, rotating.", f->path); - else + return true; + default: return false; - - return true; + } } static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n, int priority) { -- cgit v1.2.3-54-g00ecf From 76ec966f0e33685f8331603805c0349adceea836 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Apr 2016 18:41:34 -0400 Subject: tree-wide: use ERFKILL instead of ESHUTDOWN for "unit masked" If the error code ever leaks (we print the strerror error instead of providing our own), the message for ESHUTDOWN is "Cannot send after transport endpoint shutdown", which can be misleading. In particular it suggest that some mishandling of the dbus connection occured. Let's change that to ERFKILL which has the advantage that a) it sounds implausible as actual error, b) has the connotation of disabling something manually. --- src/core/dbus-manager.c | 2 +- src/core/transaction.c | 2 +- src/shared/install.c | 2 +- src/systemctl/systemctl.c | 6 +++--- src/sysv-generator/sysv-generator.c | 2 +- src/test/test-install-root.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 2392ed6c16..0b12aae2ef 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1610,7 +1610,7 @@ fail: static int install_error(sd_bus_error *error, int c) { assert(c < 0); - if (c == -ESHUTDOWN) + if (c == -ERFKILL) return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); if (c == -EADDRNOTAVAIL) return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated."); diff --git a/src/core/transaction.c b/src/core/transaction.c index dad387749c..d5370b2a14 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -939,7 +939,7 @@ int transaction_add_job_and_dependencies( if (r < 0) { /* unit masked, job type not applicable and unit not found are not considered as errors. */ log_unit_full(dep, - IN_SET(r, -ESHUTDOWN, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING, + IN_SET(r, -ERFKILL, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING, r, "Cannot add dependency job, ignoring: %s", bus_error_message(e, r)); sd_bus_error_free(e); diff --git a/src/shared/install.c b/src/shared/install.c index 8d9f96553b..35d83dd16c 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -754,7 +754,7 @@ static int install_info_may_process(UnitFileInstallInfo *i, const LookupPaths *p * not subject to enable/disable operations. */ if (i->type == UNIT_FILE_TYPE_MASKED) - return -ESHUTDOWN; + return -ERFKILL; if (path_is_generator(paths, i->path)) return -EADDRNOTAVAIL; if (path_is_transient(paths, i->path)) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9310a0f430..4942dbb6ad 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5272,7 +5272,7 @@ static int enable_sysv_units(const char *verb, char **args) { continue; j = unit_file_exists(arg_scope, &paths, name); - if (j < 0 && !IN_SET(j, -ELOOP, -ESHUTDOWN, -EADDRNOTAVAIL)) + if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) return log_error_errno(j, "Failed to lookup unit file state: %m"); found_native = j != 0; @@ -5442,7 +5442,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { else assert_not_reached("Unknown verb"); - if (r == -ESHUTDOWN) + if (r == -ERFKILL) return log_error_errno(r, "Unit file is masked."); if (r == -EADDRNOTAVAIL) return log_error_errno(r, "Unit file is transient or generated."); @@ -5617,7 +5617,7 @@ static int add_dependency(int argc, char *argv[], void *userdata) { unsigned n_changes = 0; r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); - if (r == -ESHUTDOWN) + if (r == -ERFKILL) return log_error_errno(r, "Unit file is masked."); if (r == -EADDRNOTAVAIL) return log_error_errno(r, "Unit file is transient or generated."); diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 9392a3d2b5..fe4bbeeb75 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -807,7 +807,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { continue; r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name); - if (r < 0 && !IN_SET(r, -ELOOP, -ESHUTDOWN, -EADDRNOTAVAIL)) { + if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) { log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); continue; } else if (r != 0) { diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 2138655e29..998c345a1a 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -80,7 +80,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); /* Enabling a masked unit should fail! */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ERFKILL); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; -- cgit v1.2.3-54-g00ecf From 9a0a413a195a21888cf926be5595d0efc1eef0fe Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Apr 2016 19:31:53 -0400 Subject: systemctl/core: ignore masked units in preset-all With any masked unit that would that would be enabled by presets, we'd get: test@rawhide $ sudo systemctl preset-all Failed to execute operation: Unit file is masked. test@rawhide $ sudo systemctl --root=/ preset-all Operation failed: Cannot send after transport endpoint shutdown Simply ignore those units: test@rawhide $ sudo systemctl preset-all Unit xxx.service is masked, ignoring. --- src/core/dbus-manager.c | 12 +++++++----- src/shared/bus-util.c | 10 ++++++++-- src/shared/install.c | 4 ++++ src/shared/install.h | 5 +++++ src/systemctl/systemctl.c | 16 ++++++++++++---- 5 files changed, 36 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 0b12aae2ef..9a913a6c91 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1565,11 +1565,13 @@ static int reply_unit_file_changes_and_free( unsigned i; int r; - if (n_changes > 0) { - r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); - if (r < 0) - log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); - } + for (i = 0; i < n_changes; i++) + if (unit_file_change_is_modification(changes[i].type)) { + r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); + if (r < 0) + log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); + break; + } r = sd_bus_message_new_method_return(message, &reply); if (r < 0) diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 2b86b1fcd6..677970b7f0 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -2203,11 +2203,17 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un if (!quiet) { if (streq(type, "symlink")) log_info("Created symlink from %s to %s.", path, source); - else + else if (streq(type, "unlink")) log_info("Removed symlink %s.", path); + else if (streq(type, "masked")) + log_info("Unit %s is masked, ignoring.", path); + else + log_notice("Manager reported unknown change type \"%s\" for %s.", type, path); } - r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source); + r = unit_file_changes_add(changes, n_changes, + unit_file_change_type_from_string(type), + path, source); if (r < 0) return r; } diff --git a/src/shared/install.c b/src/shared/install.c index 35d83dd16c..74de8141f1 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2539,6 +2539,9 @@ int unit_file_preset_all( continue; r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name); + if (r == -ERFKILL) + r = unit_file_changes_add(changes, n_changes, + UNIT_FILE_IS_MASKED, de->d_name, NULL); if (r < 0) return r; } @@ -2652,6 +2655,7 @@ DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { [UNIT_FILE_SYMLINK] = "symlink", [UNIT_FILE_UNLINK] = "unlink", + [UNIT_FILE_IS_MASKED] = "masked", }; DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); diff --git a/src/shared/install.h b/src/shared/install.h index 6f8b45d4f6..6b760def9b 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -72,10 +72,15 @@ enum UnitFilePresetMode { enum UnitFileChangeType { UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK, + UNIT_FILE_IS_MASKED, _UNIT_FILE_CHANGE_TYPE_MAX, _UNIT_FILE_CHANGE_TYPE_INVALID = -1 }; +static inline bool unit_file_change_is_modification(UnitFileChangeType type) { + return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK); +} + struct UnitFileChange { UnitFileChangeType type; char *path; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 4942dbb6ad..0c64cbab80 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1989,12 +1989,20 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha assert(changes || n_changes == 0); - for (i = 0; i < n_changes; i++) { - if (changes[i].type == UNIT_FILE_SYMLINK) + for (i = 0; i < n_changes; i++) + switch(changes[i].type) { + case UNIT_FILE_SYMLINK: log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); - else + break; + case UNIT_FILE_UNLINK: log_info("Removed %s.", changes[i].path); - } + break; + case UNIT_FILE_IS_MASKED: + log_info("Unit %s is masked, ignoring.", changes[i].path); + break; + default: + assert_not_reached("bad change type"); + } } static int set_default(int argc, char *argv[], void *userdata) { -- cgit v1.2.3-54-g00ecf From 3ae5990c6ed54f5d4acec12c2e9e40d110c72230 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Apr 2016 22:52:06 -0400 Subject: tree-wide: introduce PATH_IN_SET macro --- src/basic/path-util.c | 8 ++++---- src/basic/path-util.h | 13 +++++++++++++ src/core/mount.c | 6 ++---- src/test/test-path-util.c | 6 ++++++ 4 files changed, 25 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 822c09bfba..044a12889d 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -569,10 +569,10 @@ static int binary_is_good(const char *binary) { if (r < 0) return r; - return !path_equal(d, "true") && - !path_equal(d, "/bin/true") && - !path_equal(d, "/usr/bin/true") && - !path_equal(d, "/dev/null"); + return !PATH_IN_SET(d, "true" + "/bin/true", + "/usr/bin/true", + "/dev/null"); } int fsck_exists(const char *fstype) { diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 2c2f87a9f2..f43d477eb9 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -48,6 +48,19 @@ 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); +/* Note: the search terminates on the first NULL item. */ +#define PATH_IN_SET(p, ...) \ + ({ \ + char **s; \ + bool _found = false; \ + STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__)) \ + if (path_equal(p, *s)) { \ + _found = true; \ + break; \ + } \ + _found; \ + }) + int 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); diff --git a/src/core/mount.c b/src/core/mount.c index 74ab54bfd0..632c5c824c 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -376,8 +376,7 @@ static int mount_add_quota_links(Mount *m) { static bool should_umount(Mount *m) { MountParameters *p; - if (path_equal(m->where, "/") || - path_equal(m->where, "/usr") || + if (PATH_IN_SET(m->where, "/", "/usr") || path_startswith(m->where, "/run/initramfs")) return false; @@ -408,8 +407,7 @@ static int mount_add_default_dependencies(Mount *m) { * Also, don't bother with anything mounted below virtual * file systems, it's also going to be virtual, and hence * not worth the effort. */ - if (path_equal(m->where, "/") || - path_equal(m->where, "/usr") || + if (PATH_IN_SET(m->where, "/", "/usr") || path_startswith(m->where, "/run/initramfs") || path_startswith(m->where, "/proc") || path_startswith(m->where, "/sys") || diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index d376dd56c5..7ce2695c5c 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -90,6 +90,12 @@ static void test_path(void) { assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc")); assert_se(path_equal(path_kill_slashes(p3), "/./")); } + + assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo")); + assert_se(PATH_IN_SET("/bin", "/bin")); + assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin")); + assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar")); + assert_se(!PATH_IN_SET("/", "/abc", "/def")); } static void test_find_binary(const char *self) { -- cgit v1.2.3-54-g00ecf From 24737c291738313fd67924172988a8986f60e958 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Apr 2016 23:08:23 -0400 Subject: install: allow paths like LookupPath.generator to be NULL Fixes #3047. --- src/basic/path-util.h | 4 ++++ src/shared/install.c | 28 ++++++++++++++-------------- src/test/test-path-util.c | 6 ++++++ 3 files changed, 24 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/basic/path-util.h b/src/basic/path-util.h index f43d477eb9..34d5cd1570 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -48,6 +48,10 @@ 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); +static inline bool path_equal_ptr(const char *a, const char *b) { + return !!a == !!b && (!a || path_equal(a, b)); +} + /* Note: the search terminates on the first NULL item. */ #define PATH_IN_SET(p, ...) \ ({ \ diff --git a/src/shared/install.c b/src/shared/install.c index 74de8141f1..10c724edbd 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -119,9 +119,9 @@ static int path_is_generator(const LookupPaths *p, const char *path) { if (!parent) return -ENOMEM; - return path_equal(p->generator, parent) || - path_equal(p->generator_early, parent) || - path_equal(p->generator_late, parent); + return path_equal_ptr(parent, p->generator) || + path_equal_ptr(parent, p->generator_early) || + path_equal_ptr(parent, p->generator_late); } static int path_is_transient(const LookupPaths *p, const char *path) { @@ -134,7 +134,7 @@ static int path_is_transient(const LookupPaths *p, const char *path) { if (!parent) return -ENOMEM; - return path_equal(p->transient, parent); + return path_equal_ptr(parent, p->transient); } static int path_is_control(const LookupPaths *p, const char *path) { @@ -147,8 +147,8 @@ static int path_is_control(const LookupPaths *p, const char *path) { if (!parent) return -ENOMEM; - return path_equal(parent, p->persistent_control) || - path_equal(parent, p->runtime_control); + return path_equal_ptr(parent, p->persistent_control) || + path_equal_ptr(parent, p->runtime_control); } static int path_is_config(const LookupPaths *p, const char *path) { @@ -164,8 +164,8 @@ static int path_is_config(const LookupPaths *p, const char *path) { if (!parent) return -ENOMEM; - return path_equal(parent, p->persistent_config) || - path_equal(parent, p->runtime_config); + return path_equal_ptr(parent, p->persistent_config) || + path_equal_ptr(parent, p->runtime_config); } static int path_is_runtime(const LookupPaths *p, const char *path) { @@ -186,12 +186,12 @@ static int path_is_runtime(const LookupPaths *p, const char *path) { if (!parent) return -ENOMEM; - return path_equal(parent, p->runtime_config) || - path_equal(parent, p->generator) || - path_equal(parent, p->generator_early) || - path_equal(parent, p->generator_late) || - path_equal(parent, p->transient) || - path_equal(parent, p->runtime_control); + return path_equal_ptr(parent, p->runtime_config) || + path_equal_ptr(parent, p->generator) || + path_equal_ptr(parent, p->generator_early) || + path_equal_ptr(parent, p->generator_late) || + path_equal_ptr(parent, p->transient) || + path_equal_ptr(parent, p->runtime_control); } static int path_is_vendor(const LookupPaths *p, const char *path) { diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 7ce2695c5c..5d77e2959c 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -96,6 +96,12 @@ static void test_path(void) { assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin")); assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar")); assert_se(!PATH_IN_SET("/", "/abc", "/def")); + + assert_se(path_equal_ptr(NULL, NULL)); + assert_se(path_equal_ptr("/a", "/a")); + assert_se(!path_equal_ptr("/a", "/b")); + assert_se(!path_equal_ptr("/a", NULL)); + assert_se(!path_equal_ptr(NULL, "/a")); } static void test_find_binary(const char *self) { -- cgit v1.2.3-54-g00ecf From 6f7202cfd512d18f561af6708fe0823c9545f674 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 18 Apr 2016 03:45:42 +0200 Subject: tree-wide: fall back to now(CLOCK_MONOTONIC) if CLOCK_BOOTTIME unsupported (#3037) It was added in 2.6.39, and causes an assertion to fail when running in mock hosted on 2.6.32-based RHEL-6: Assertion 'clock_gettime(map_clock_id(clock_id), &ts) == 0' failed at systemd/src/basic/time-util.c:70, function now(). Aborting. --- src/core/dbus-timer.c | 2 +- src/core/timer.c | 2 +- src/libsystemd/sd-event/sd-event.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index bc121b83a2..a0e61b023e 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -156,7 +156,7 @@ static int property_get_next_elapse_monotonic( usec_t a, b; a = now(CLOCK_MONOTONIC); - b = now(CLOCK_BOOTTIME); + b = now(clock_boottime_or_monotonic()); if (t->next_elapse_monotonic_or_boottime + a > b) x = t->next_elapse_monotonic_or_boottime + a - b; diff --git a/src/core/timer.c b/src/core/timer.c index a51a67ea11..b286b714fa 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -320,7 +320,7 @@ static usec_t monotonic_to_boottime(usec_t t) { if (t <= 0) return 0; - a = now(CLOCK_BOOTTIME); + a = now(clock_boottime_or_monotonic()); b = now(CLOCK_MONOTONIC); if (t + a > b) diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 9fd744768d..79b98c293c 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -2527,7 +2527,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { } dual_timestamp_get(&e->timestamp); - e->timestamp_boottime = now(CLOCK_BOOTTIME); + e->timestamp_boottime = now(clock_boottime_or_monotonic()); for (i = 0; i < m; i++) { -- cgit v1.2.3-54-g00ecf From b047c62e6663f2c52e7c6dba6b013bcf97431ff9 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Sun, 17 Apr 2016 19:52:45 -0700 Subject: conf-parser: Set EXTRACT_RETAIN_ESCAPE when extracting words (#2917) If you reference another unit with an escaped name, the escaped characters should remain in the extracted word. This used to work correctly prior to commit 34f253f0. The problem can be seen when units with escaped names are referenced. $ cat "/usr/lib/systemd/system/dev-disk-by\x2dlabel-eos\x2dswap.swap" [Swap] What=/dev/disk/by-label/eos-swap [Install] WantedBy=dev-disk-by\x2dlabel-eos\x2dswap.device $ systemctl enable "dev-disk-by\x2dlabel-eos\x2dswap.swap" Created symlink /etc/systemd/system/dev-disk-byx2dlabel-eosx2dswap.device.wants/dev-disk-by\x2dlabel-eos\x2dswap.swap, pointing to /usr/lib/systemd/system/dev-disk-by\x2dlabel-eos\x2dswap.swap. The wants directory should be created with the x2ds escaped with \. --- src/shared/conf-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index bd0a1f483b..1141f9964f 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -732,7 +732,7 @@ int config_parse_strv(const char *unit, for (;;) { char *word = NULL; int r; - r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); + r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE); if (r == 0) break; if (r == -ENOMEM) -- cgit v1.2.3-54-g00ecf From 3fef7a3fcdcaa6bc6b4bea9d76f994d8f6385487 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Mon, 18 Apr 2016 17:15:52 +0530 Subject: networkd: allow setting of multicast querier for linux bridge (#3051) --- man/systemd.netdev.xml | 11 ++++++++ src/basic/missing.h | 35 ++++++++++++++++++++++++- src/libsystemd/sd-netlink/netlink-types.c | 43 ++++++++++++++++++++++++++----- src/network/networkd-netdev-bridge.c | 17 ++++++++++++ src/network/networkd-netdev-bridge.h | 2 ++ src/network/networkd-netdev-gperf.gperf | 1 + 6 files changed, 102 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index c5fb2fa7fb..48c283c8df 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -310,6 +310,17 @@ of the Listening and Learning states before the Forwarding state is entered. + + MulticastQuerier= + + A boolean. This setting controls the IFLA_BR_MCAST_QUERIER option in the kernel. + If enabled, the kernel will send general ICMP queries from a zero source address. + This feature should allow faster convergence on startup, but it causes some + multicast-aware switches to misbehave and disrupt forwarding of multicast packets. + When unset, the kernel's default setting applies. + + + diff --git a/src/basic/missing.h b/src/basic/missing.h index 66cd5921ad..6a49ccd281 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -746,7 +746,40 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BR_AGEING_TIME 4 #define IFLA_BR_STP_STATE 5 #define IFLA_BR_PRIORITY 6 -#define __IFLA_BR_MAX 7 +#define IFLA_BR_VLAN_FILTERING 7 +#define IFLA_BR_VLAN_PROTOCOL 8 +#define IFLA_BR_GROUP_FWD_MASK 9 +#define IFLA_BR_ROOT_ID 10 +#define IFLA_BR_BRIDGE_ID 11 +#define IFLA_BR_ROOT_PORT 12 +#define IFLA_BR_ROOT_PATH_COST 13 +#define IFLA_BR_TOPOLOGY_CHANGE 14 +#define IFLA_BR_TOPOLOGY_CHANGE_DETECTED 15 +#define IFLA_BR_HELLO_TIMER 16 +#define IFLA_BR_TCN_TIMER 17 +#define IFLA_BR_TOPOLOGY_CHANGE_TIMER 18 +#define IFLA_BR_GC_TIMER 19 +#define IFLA_BR_GROUP_ADDR 20 +#define IFLA_BR_FDB_FLUSH 21 +#define IFLA_BR_MCAST_ROUTER 22 +#define IFLA_BR_MCAST_SNOOPING 23 +#define IFLA_BR_MCAST_QUERY_USE_IFADDR 24 +#define IFLA_BR_MCAST_QUERIER 25 +#define IFLA_BR_MCAST_HASH_ELASTICITY 26 +#define IFLA_BR_MCAST_HASH_MAX 27 +#define IFLA_BR_MCAST_LAST_MEMBER_CNT 28 +#define IFLA_BR_MCAST_STARTUP_QUERY_CNT 29 +#define IFLA_BR_MCAST_LAST_MEMBER_INTVL 30 +#define IFLA_BR_MCAST_MEMBERSHIP_INTVL 31 +#define IFLA_BR_MCAST_QUERIER_INTVL 32 +#define IFLA_BR_MCAST_QUERY_INTVL 33 +#define IFLA_BR_MCAST_QUERY_RESPONSE_INTVL 34 +#define IFLA_BR_MCAST_STARTUP_QUERY_INTVL 35 +#define IFLA_BR_NF_CALL_IPTABLES 36 +#define IFLA_BR_NF_CALL_IP6TABLES 37 +#define IFLA_BR_NF_CALL_ARPTABLES 38 +#define IFLA_BR_VLAN_DEFAULT_PVID 39 +#define __IFLA_BR_MAX 40 #define IFLA_BR_MAX (__IFLA_BR_MAX - 1) #endif diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index a5758bb516..3a4bac2ced 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -95,12 +95,43 @@ static const NLType rtnl_link_info_data_macvlan_types[] = { }; static const NLType rtnl_link_info_data_bridge_types[] = { - [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_VLAN_FILTERING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_ROOT_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_ROOT_PATH_COST] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_TOPOLOGY_CHANGE] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_TOPOLOGY_CHANGE_DETECTED] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_HELLO_TIMER] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_TCN_TIMER] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_TOPOLOGY_CHANGE_TIMER] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_GC_TIMER] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_GROUP_ADDR] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_FDB_FLUSH] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_MCAST_ROUTER] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_SNOOPING] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_QUERIER] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_MCAST_HASH_MAX] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 }, + [IFLA_BR_NF_CALL_IPTABLES] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NETLINK_TYPE_U16 }, }; static const NLType rtnl_link_info_data_vlan_types[] = { diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index cdcd08f057..3f91b2eaea 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -89,6 +89,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m"); } + if (b->mcast_querier >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_QUERIER, b->mcast_querier); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m"); + } + r = sd_netlink_message_close_container(req); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); @@ -106,8 +112,19 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess return r; } +static void bridge_init(NetDev *n) { + Bridge *b; + + b = BRIDGE(n); + + assert(b); + + b->mcast_querier = -1; +} + const NetDevVTable bridge_vtable = { .object_size = sizeof(Bridge), + .init = bridge_init, .sections = "Match\0NetDev\0Bridge\0", .post_create = netdev_bridge_post_create, .create_type = NETDEV_CREATE_MASTER, diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index 27f26f7870..3f6f1d0502 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -26,6 +26,8 @@ typedef struct Bridge Bridge; struct Bridge { NetDev meta; + int mcast_querier; + usec_t forward_delay; usec_t hello_time; usec_t max_age; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 8f506af092..15a787a9e3 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -92,3 +92,4 @@ Bond.LearnPacketIntervalSec, config_parse_sec, 0, Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time) Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age) Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay) +Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier) -- cgit v1.2.3-54-g00ecf From 0b6b45d5e09b48c0637caab85f3b667ec7e8afef Mon Sep 17 00:00:00 2001 From: michaelolbrich Date: Mon, 18 Apr 2016 15:28:00 +0200 Subject: basic: user-utils.c needs missing.h for secure_getenv (#3059) Otherwise building may fail with: src/basic/user-util.c: In function 'get_home_dir': src/basic/user-util.c:343:9: error: implicit declaration of function 'secure_getenv' [-Werror=implicit-function-declaration] --- src/basic/user-util.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 19155bce53..f65ca3edaa 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -30,6 +30,7 @@ #include #include +#include "missing.h" #include "alloc-util.h" #include "fd-util.h" #include "formats-util.h" -- cgit v1.2.3-54-g00ecf From 596fc2636a898c0948cb9d2b3d3e7972084bc992 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 17 Apr 2016 15:43:16 -0400 Subject: Various formatting and style fixes --- src/core/dbus-manager.c | 7 ++-- src/shared/install.c | 7 ++-- src/shared/install.h | 102 ++++++++++++++++++++++++++++++++++++++++------ src/systemctl/systemctl.c | 29 +++++-------- src/test/test-install.c | 42 ++++++++++--------- 5 files changed, 129 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 9a913a6c91..0c3b011b8b 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1731,8 +1731,8 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use static int method_disable_unit_files_generic( sd_bus_message *message, - Manager *m, const - char *verb, + Manager *m, + const char *verb, int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), sd_bus_error *error) { @@ -1885,8 +1885,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd UnitFileChange *changes = NULL; unsigned n_changes = 0; int runtime, force, r; - char *target; - char *type; + char *target, *type; UnitDependency dep; assert(message); diff --git a/src/shared/install.c b/src/shared/install.c index 10c724edbd..1522435f7f 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -434,8 +434,7 @@ static int remove_marked_symlinks_fd( /* We remove all links pointing to a file or path that is marked, as well as all files sharing * the same name as a file that is marked. */ - found = - set_contains(remove_symlinks_to, dest) || + found = set_contains(remove_symlinks_to, dest) || set_contains(remove_symlinks_to, basename(dest)) || set_contains(remove_symlinks_to, de->d_name); @@ -1481,7 +1480,7 @@ static int install_context_apply( if (q < 0) r = q; else - r+= q; + r += q; } } @@ -2413,7 +2412,7 @@ static int execute_preset( if (q < 0) r = q; else - r+= q; + r += q; } } diff --git a/src/shared/install.h b/src/shared/install.h index 6b760def9b..99cd1409f3 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -130,18 +130,96 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) { return !strv_isempty(i->also); } -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); -int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); -int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_revert(UnitFileScope scope, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); -int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); -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, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); +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); +int unit_file_reenable( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes); +int unit_file_preset( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + UnitFilePresetMode mode, + bool force, + UnitFileChange **changes, + unsigned *n_changes); +int unit_file_preset_all( + UnitFileScope scope, + bool runtime, + const char *root_dir, + UnitFilePresetMode mode, + bool force, + UnitFileChange **changes, + unsigned *n_changes); +int unit_file_mask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes); +int unit_file_unmask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + UnitFileChange **changes, + unsigned *n_changes); +int unit_file_link( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes); +int unit_file_revert( + UnitFileScope scope, + const char *root_dir, + char **files, + UnitFileChange **changes, + unsigned *n_changes); +int unit_file_set_default( + UnitFileScope scope, + const char *root_dir, + const char *file, + bool force, + UnitFileChange **changes, + unsigned *n_changes); +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, + const char *target, + UnitDependency dep, + bool force, + UnitFileChange **changes, + unsigned *n_changes); int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0c64cbab80..5f87e4a97f 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5684,23 +5684,22 @@ static int add_dependency(int argc, char *argv[], void *userdata) { } static int preset_all(int argc, char *argv[], void *userdata) { - UnitFileChange *changes = NULL; - unsigned n_changes = 0; int r; if (install_client_side()) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); - if (r < 0) { + if (r < 0) log_error_errno(r, "Operation failed: %m"); - goto finish; + else { + if (!arg_quiet) + dump_unit_file_changes(changes, n_changes); } - if (!arg_quiet) - dump_unit_file_changes(changes, n_changes); - - r = 0; - + unit_file_changes_free(changes, n_changes); + return r; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -5731,16 +5730,10 @@ static int preset_all(int argc, char *argv[], void *userdata) { if (r < 0) return r; - if (!arg_no_reload) - r = daemon_reload(argc, argv, userdata); - else - r = 0; + if (arg_no_reload) + return 0; + return daemon_reload(argc, argv, userdata); } - -finish: - unit_file_changes_free(changes, n_changes); - - return r; } static int unit_is_enabled(int argc, char *argv[], void *userdata) { diff --git a/src/test/test-install.c b/src/test/test-install.c index 874d617621..50315c1d9a 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -46,6 +46,9 @@ int main(int argc, char* argv[]) { unsigned n_changes = 0; UnitFileState state = 0; + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + h = hashmap_new(&string_hash_ops); r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); assert_se(r == 0); @@ -65,12 +68,12 @@ int main(int argc, char* argv[]) { unit_file_list_free(h); - log_error("enable"); + log_info("/*** enable **/"); r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); - log_error("enable2"); + log_info("/*** enable2 **/"); r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); @@ -82,8 +85,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); - log_error("disable"); - + log_info("/*** disable ***/"); changes = NULL; n_changes = 0; @@ -97,13 +99,13 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_DISABLED); - log_error("mask"); + log_info("/*** mask ***/"); changes = NULL; n_changes = 0; r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); - log_error("mask2"); + log_info("/*** mask2 ***/"); r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); @@ -114,13 +116,13 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_MASKED); - log_error("unmask"); + log_info("/*** unmask ***/"); changes = NULL; n_changes = 0; r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); - log_error("unmask2"); + log_info("/*** unmask2 ***/"); r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); @@ -131,7 +133,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_DISABLED); - log_error("mask"); + log_info("/*** mask ***/"); changes = NULL; n_changes = 0; @@ -145,13 +147,13 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_MASKED); - log_error("disable"); + log_info("/*** disable ***/"); changes = NULL; n_changes = 0; r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); - log_error("disable2"); + log_info("/*** disable2 ***/"); r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); @@ -162,7 +164,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_MASKED); - log_error("umask"); + log_info("/*** umask ***/"); changes = NULL; n_changes = 0; @@ -176,7 +178,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_DISABLED); - log_error("enable files2"); + log_info("/*** enable files2 ***/"); changes = NULL; n_changes = 0; @@ -190,7 +192,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); - log_error("disable files2"); + log_info("/*** disable files2 ***/"); changes = NULL; n_changes = 0; @@ -203,7 +205,7 @@ int main(int argc, char* argv[]) { r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r < 0); - log_error("link files2"); + log_info("/*** link files2 ***/"); changes = NULL; n_changes = 0; @@ -217,7 +219,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_LINKED); - log_error("disable files2"); + log_info("/*** disable files2 ***/"); changes = NULL; n_changes = 0; @@ -230,7 +232,7 @@ int main(int argc, char* argv[]) { r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r < 0); - log_error("link files2"); + log_info("/*** link files2 ***/"); changes = NULL; n_changes = 0; @@ -244,7 +246,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_LINKED); - log_error("reenable files2"); + log_info("/*** reenable files2 ***/"); changes = NULL; n_changes = 0; @@ -258,7 +260,7 @@ int main(int argc, char* argv[]) { assert_se(r >= 0); assert_se(state == UNIT_FILE_ENABLED); - log_error("disable files2"); + log_info("/*** disable files2 ***/"); changes = NULL; n_changes = 0; @@ -270,7 +272,7 @@ int main(int argc, char* argv[]) { r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); assert_se(r < 0); - log_error("preset files"); + log_info("/*** preset files ***/"); changes = NULL; n_changes = 0; -- cgit v1.2.3-54-g00ecf From 795ff6d5d827eb5743d9e37c4acaee4bdeff58b4 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 17 Apr 2016 15:56:46 -0400 Subject: shared/install: add helper function unit_file_changes_have_modification() As suggested in review of #3049. --- src/core/dbus-manager.c | 12 +++++------- src/shared/install.h | 12 ++++++++---- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 0c3b011b8b..ddfde23028 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1565,13 +1565,11 @@ static int reply_unit_file_changes_and_free( unsigned i; int r; - for (i = 0; i < n_changes; i++) - if (unit_file_change_is_modification(changes[i].type)) { - r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); - if (r < 0) - log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); - break; - } + if (unit_file_changes_have_modification(changes, n_changes)) { + r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); + if (r < 0) + log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); + } r = sd_bus_message_new_method_return(message, &reply); if (r < 0) diff --git a/src/shared/install.h b/src/shared/install.h index 99cd1409f3..219b48f428 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -77,16 +77,20 @@ enum UnitFileChangeType { _UNIT_FILE_CHANGE_TYPE_INVALID = -1 }; -static inline bool unit_file_change_is_modification(UnitFileChangeType type) { - return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK); -} - struct UnitFileChange { UnitFileChangeType type; char *path; char *source; }; +static inline bool unit_file_changes_have_modification(const UnitFileChange* changes, unsigned n_changes) { + unsigned i; + for (i = 0; i < n_changes; i++) + if (IN_SET(changes[i].type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK)) + return true; + return false; +} + struct UnitFileList { char *path; UnitFileState state; -- cgit v1.2.3-54-g00ecf From 490d20e65dd85628f910299a3925bbff466b2e74 Mon Sep 17 00:00:00 2001 From: "Vittorio G (VittGam)" Date: Tue, 19 Apr 2016 11:18:18 +0200 Subject: sleep: Add debug feature to bypass hibernation memory checks. (#3064) This new feature bypasses checking if a swap partition is mounted or if there is enough swap space available for hibernation to succeed. This can be useful when a system with a Solid State Disk (SSD) has no normal swap partition or file configured, and a custom systemd unit is used to mount a swap file just before hibernating and unmount it just after resuming. Signed-off-by: Vittorio Gambaletta --- src/shared/sleep-config.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 35aa60101f..f00624d0f2 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -28,6 +28,7 @@ #include "alloc-util.h" #include "conf-parser.h" #include "def.h" +#include "env-util.h" #include "fd-util.h" #include "fileio.h" #include "log.h" @@ -231,6 +232,9 @@ static bool enough_memory_for_hibernation(void) { size_t size = 0, used = 0; int r; + if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0) + return true; + r = hibernation_partition_size(&size, &used); if (r < 0) return false; -- cgit v1.2.3-54-g00ecf From af3d811352094f3f1304bdf8ba9cdd2b4b03b55c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 17 Apr 2016 10:16:44 -0400 Subject: shared/install,systemctl,core: report offending file on installation error Fixes #2191: $ systemctl --root=/ enable sddm Created symlink /etc/systemd/system/display-manager.service, pointing to /usr/lib/systemd/system/sddm.service. $ sudo build/systemctl --root=/ enable gdm Failed to enable unit, file /etc/systemd/system/display-manager.service already exists and is a symlink to /usr/lib/systemd/system/sddm.service. $ sudo build/systemctl --root= enable sddm $ sudo build/systemctl --root= enable gdm Failed to enable unit: File /etc/systemd/system/display-manager.service already exists and is a symlink to /usr/lib/systemd/system/sddm.service. (I tried a few different approaches to pass the error information back to the caller. Adding a new parameter to hold the error results in a gigantic patch and a lot of hassle to pass the args arounds. Adding this information to the changes array is straightforward and can be more easily extended in the future.) In case local installation is performed, the full set of errors can be reported and we do that. When running over dbus, only the first error is reported. --- src/core/dbus-manager.c | 119 ++++++++++++++++++++++++++++----------------- src/shared/bus-util.c | 21 ++++---- src/shared/install.c | 120 ++++++++++++++++++++++++++++++++++++++-------- src/shared/install.h | 7 ++- src/systemctl/systemctl.c | 83 ++++++-------------------------- 5 files changed, 205 insertions(+), 145 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index ddfde23028..d48b0ca69d 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1585,15 +1585,19 @@ static int reply_unit_file_changes_and_free( if (r < 0) goto fail; - for (i = 0; i < n_changes; i++) { - r = sd_bus_message_append( - reply, "(sss)", - unit_file_change_type_to_string(changes[i].type), - changes[i].path, - changes[i].source); - if (r < 0) - goto fail; - } + for (i = 0; i < n_changes; i++) + if (changes[i].type >= 0) { + const char *change = unit_file_change_type_to_string(changes[i].type); + assert(change != NULL); + + r = sd_bus_message_append( + reply, "(sss)", + change, + changes[i].path, + changes[i].source); + if (r < 0) + goto fail; + } r = sd_bus_message_close_container(reply); if (r < 0) @@ -1607,17 +1611,56 @@ fail: return r; } -static int install_error(sd_bus_error *error, int c) { +/* Create an error reply, using the error information from changes[] + * if possible, and fall back to generating an error from error code c. + * The error message only describes the first error. + * + * Coordinate with unit_file_dump_changes() in install.c. + */ +static int install_error( + sd_bus_error *error, + int c, + UnitFileChange *changes, + unsigned n_changes) { + int r; + unsigned i; assert(c < 0); - if (c == -ERFKILL) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked."); - if (c == -EADDRNOTAVAIL) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, "Unit file is transient or generated."); - if (c == -ELOOP) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED, "Refusing to operate on linked unit file."); + for (i = 0; i < n_changes; i++) + switch(changes[i].type) { + case 0 ... INT_MAX: + continue; + case -EEXIST: + if (changes[i].source) + r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, + "File %s already exists and is a symlink to %s.", + changes[i].path, changes[i].source); + else + r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, + "File %s already exists.", + changes[i].path); + goto found; + case -ERFKILL: + r = sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, + "Unit file %s is masked.", changes[i].path); + goto found; + case -EADDRNOTAVAIL: + r = sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED, + "Unit %s is transient or generated.", changes[i].path); + goto found; + case -ELOOP: + r = sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED, + "Refusing to operate on linked unit file %s", changes[i].path); + goto found; + default: + r = sd_bus_error_set_errnof(error, changes[i].type, "File %s: %m", changes[i].path); + goto found; + } - return c; + r = c; + found: + unit_file_changes_free(changes, n_changes); + return r; } static int method_enable_unit_files_generic( @@ -1651,10 +1694,8 @@ static int method_enable_unit_files_generic( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return install_error(error, r); - } + if (r < 0) + return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes); } @@ -1719,10 +1760,8 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return install_error(error, r); - } + if (r < 0) + return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, r, changes, n_changes); } @@ -1757,10 +1796,8 @@ static int method_disable_unit_files_generic( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return install_error(error, r); - } + if (r < 0) + return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1794,10 +1831,8 @@ static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = unit_file_revert(m->unit_file_scope, NULL, l, &changes, &n_changes); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return install_error(error, r); - } + if (r < 0) + return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1827,10 +1862,8 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return install_error(error, r); - } + if (r < 0) + return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1869,10 +1902,8 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return install_error(error, r); - } + if (r < 0) + return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1908,10 +1939,8 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd return -EINVAL; r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); - if (r < 0) { - unit_file_changes_free(changes, n_changes); - return install_error(error, r); - } + if (r < 0) + return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 677970b7f0..6a1877d8aa 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -2200,20 +2200,16 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un return bus_log_parse_error(r); while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) { - if (!quiet) { - if (streq(type, "symlink")) - log_info("Created symlink from %s to %s.", path, source); - else if (streq(type, "unlink")) - log_info("Removed symlink %s.", path); - else if (streq(type, "masked")) - log_info("Unit %s is masked, ignoring.", path); - else - log_notice("Manager reported unknown change type \"%s\" for %s.", type, path); + /* We expect only "success" changes to be sent over the bus. + Hence, reject anything negative. */ + UnitFileChangeType ch = unit_file_change_type_from_string(type); + + if (ch < 0) { + log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path); + continue; } - r = unit_file_changes_add(changes, n_changes, - unit_file_change_type_from_string(type), - path, source); + r = unit_file_changes_add(changes, n_changes, ch, path, source); if (r < 0) return r; } @@ -2224,6 +2220,7 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un if (r < 0) return bus_log_parse_error(r); + unit_file_dump_changes(0, NULL, *changes, *n_changes, false); return 0; } diff --git a/src/shared/install.c b/src/shared/install.c index 1522435f7f..febe33ed7b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -276,6 +276,70 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { free(changes); } +void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet) { + unsigned i; + bool logged = false; + + assert(changes || n_changes == 0); + /* If verb is not specified, errors are not allowed! */ + assert(verb || r >= 0); + + for (i = 0; i < n_changes; i++) { + assert(verb || changes[i].type >= 0); + + switch(changes[i].type) { + case UNIT_FILE_SYMLINK: + if (!quiet) + log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); + break; + case UNIT_FILE_UNLINK: + if (!quiet) + log_info("Removed %s.", changes[i].path); + break; + case UNIT_FILE_IS_MASKED: + if (!quiet) + log_info("Unit %s is masked, ignoring.", changes[i].path); + break; + case -EEXIST: + if (changes[i].source) + log_error_errno(changes[i].type, + "Failed to %s unit, file %s already exists and is a symlink to %s.", + verb, changes[i].path, changes[i].source); + else + log_error_errno(changes[i].type, + "Failed to %s unit, file %s already exists.", + verb, changes[i].path); + logged = true; + break; + case -ERFKILL: + log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.", + verb, changes[i].path); + logged = true; + break; + case -EADDRNOTAVAIL: + log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.", + verb, changes[i].path); + logged = true; + break; + case -ELOOP: + log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s", + verb, changes[i].path); + logged = true; + break; + default: + assert(changes[i].type < 0); + log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.", + verb, changes[i].path); + logged = true; + } + } + + if (r < 0 && !logged) + log_error_errno(r, "Failed to %s: %m.", verb); +} + + + static int create_symlink( const char *old_path, const char *new_path, @@ -300,8 +364,10 @@ static int create_symlink( return 1; } - if (errno != EEXIST) + if (errno != EEXIST) { + unit_file_changes_add(changes, n_changes, -errno, new_path, NULL); return -errno; + } r = readlink_malloc(new_path, &dest); if (r < 0) @@ -310,8 +376,10 @@ static int create_symlink( if (path_equal(dest, old_path)) return 0; - if (!force) + if (!force) { + unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest); return -EEXIST; + } r = symlink_atomic(old_path, new_path); if (r < 0) @@ -421,6 +489,7 @@ static int remove_marked_symlinks_fd( p = path_make_absolute(de->d_name, path); if (!p) return -ENOMEM; + path_kill_slashes(p); q = readlink_malloc(p, &dest); if (q == -ENOENT) @@ -444,10 +513,10 @@ static int remove_marked_symlinks_fd( if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) { if (r == 0) r = -errno; + unit_file_changes_add(changes, n_changes, -errno, p, NULL); continue; } - path_kill_slashes(p); (void) rmdir_parents(p, config_path); unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); @@ -745,19 +814,26 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam return ordered_hashmap_get(c->will_process, name); } -static int install_info_may_process(UnitFileInstallInfo *i, const LookupPaths *paths) { +static int install_info_may_process( + UnitFileInstallInfo *i, + const LookupPaths *paths, + UnitFileChange **changes, + unsigned *n_changes) { assert(i); assert(paths); /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus * not subject to enable/disable operations. */ - if (i->type == UNIT_FILE_TYPE_MASKED) + if (i->type == UNIT_FILE_TYPE_MASKED) { + unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL); return -ERFKILL; - if (path_is_generator(paths, i->path)) - return -EADDRNOTAVAIL; - if (path_is_transient(paths, i->path)) + } + if (path_is_generator(paths, i->path) || + path_is_transient(paths, i->path)) { + unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL); return -EADDRNOTAVAIL; + } return 0; } @@ -1637,8 +1713,11 @@ int unit_file_unmask( return -ENOMEM; if (unlink(path) < 0) { - if (errno != ENOENT && r >= 0) - r = -errno; + if (errno != ENOENT) { + if (r >= 0) + r = -errno; + unit_file_changes_add(changes, n_changes, -errno, path, NULL); + } continue; } @@ -1953,7 +2032,7 @@ int unit_file_add_dependency( r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); if (r < 0) return r; - r = install_info_may_process(target_info, &paths); + r = install_info_may_process(target_info, &paths, changes, n_changes); if (r < 0) return r; @@ -1965,7 +2044,7 @@ int unit_file_add_dependency( r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; - r = install_info_may_process(i, &paths); + r = install_info_may_process(i, &paths, changes, n_changes); if (r < 0) return r; @@ -2018,7 +2097,7 @@ int unit_file_enable( r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i); if (r < 0) return r; - r = install_info_may_process(i, &paths); + r = install_info_may_process(i, &paths, changes, n_changes); if (r < 0) return r; @@ -2131,7 +2210,7 @@ int unit_file_set_default( r = install_info_discover(scope, &c, &paths, name, 0, &i); if (r < 0) return r; - r = install_info_may_process(i, &paths); + r = install_info_may_process(i, &paths, changes, n_changes); if (r < 0) return r; @@ -2163,7 +2242,7 @@ int unit_file_get_default( r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; - r = install_info_may_process(i, &paths); + r = install_info_may_process(i, &paths, NULL, 0); if (r < 0) return r; @@ -2425,7 +2504,9 @@ static int preset_prepare_one( InstallContext *minus, LookupPaths *paths, UnitFilePresetMode mode, - const char *name) { + const char *name, + UnitFileChange **changes, + unsigned *n_changes) { UnitFileInstallInfo *i; int r; @@ -2443,7 +2524,7 @@ static int preset_prepare_one( if (r < 0) return r; - r = install_info_may_process(i, paths); + r = install_info_may_process(i, paths, changes, n_changes); if (r < 0) return r; } else @@ -2482,7 +2563,7 @@ int unit_file_preset( if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) return -EINVAL; - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i); + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, changes, n_changes); if (r < 0) return r; } @@ -2537,7 +2618,8 @@ int unit_file_preset_all( if (!IN_SET(de->d_type, DT_LNK, DT_REG)) continue; - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name); + /* we don't pass changes[] in, because we want to handle errors on our own */ + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, NULL, 0); if (r == -ERFKILL) r = unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, de->d_name, NULL); diff --git a/src/shared/install.h b/src/shared/install.h index 219b48f428..82c62095d5 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -77,8 +77,12 @@ enum UnitFileChangeType { _UNIT_FILE_CHANGE_TYPE_INVALID = -1 }; +/* type can either one of the UnitFileChangeTypes listed above, or a negative error. + * If source is specified, it should be the contents of the path symlink. + * In case of an error, source should be the existing symlink contents or NULL + */ struct UnitFileChange { - UnitFileChangeType type; + int type; /* UnitFileChangeType or bust */ char *path; char *source; }; @@ -233,6 +237,7 @@ Hashmap* 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); +void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet); int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 5f87e4a97f..cfdc851a6d 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1984,27 +1984,6 @@ static int get_default(int argc, char *argv[], void *userdata) { return 0; } -static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) { - unsigned i; - - assert(changes || n_changes == 0); - - for (i = 0; i < n_changes; i++) - switch(changes[i].type) { - case UNIT_FILE_SYMLINK: - log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); - break; - case UNIT_FILE_UNLINK: - log_info("Removed %s.", changes[i].path); - break; - case UNIT_FILE_IS_MASKED: - log_info("Unit %s is masked, ignoring.", changes[i].path); - break; - default: - assert_not_reached("bad change type"); - } -} - static int set_default(int argc, char *argv[], void *userdata) { _cleanup_free_ char *unit = NULL; int r; @@ -2021,14 +2000,9 @@ static int set_default(int argc, char *argv[], void *userdata) { unsigned n_changes = 0; r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); - if (r < 0) - return log_error_errno(r, "Failed to set default target: %m"); - - if (!arg_quiet) - dump_unit_file_changes(changes, n_changes); - + unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet); unit_file_changes_free(changes, n_changes); - r = 0; + return r; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -3117,7 +3091,7 @@ static int set_exit_code(uint8_t code) { NULL, "y", code); if (r < 0) - return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r)); return 0; } @@ -4967,7 +4941,7 @@ static int daemon_reload(int argc, char *argv[], void *userdata) { * reply */ r = 0; else if (r < 0) - return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r)); return r < 0 ? r : 0; } @@ -5450,18 +5424,9 @@ static int enable_unit(int argc, char *argv[], void *userdata) { else assert_not_reached("Unknown verb"); - if (r == -ERFKILL) - return log_error_errno(r, "Unit file is masked."); - if (r == -EADDRNOTAVAIL) - return log_error_errno(r, "Unit file is transient or generated."); - if (r == -ELOOP) - return log_error_errno(r, "Refusing to operate on linked unit file."); + unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet); if (r < 0) - return log_error_errno(r, "Operation failed: %m"); - - if (!arg_quiet) - dump_unit_file_changes(changes, n_changes); - + return r; r = 0; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; @@ -5542,7 +5507,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) - return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r)); if (expect_carries_install_info) { r = sd_bus_message_read(reply, "b", &carries_install_info); @@ -5625,18 +5590,9 @@ static int add_dependency(int argc, char *argv[], void *userdata) { unsigned n_changes = 0; r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); - if (r == -ERFKILL) - return log_error_errno(r, "Unit file is masked."); - if (r == -EADDRNOTAVAIL) - return log_error_errno(r, "Unit file is transient or generated."); - if (r < 0) - return log_error_errno(r, "Can't add dependency: %m"); - - if (!arg_quiet) - dump_unit_file_changes(changes, n_changes); - + unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet); unit_file_changes_free(changes, n_changes); - + return r; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -5668,19 +5624,16 @@ static int add_dependency(int argc, char *argv[], void *userdata) { r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) - return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r)); r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); if (r < 0) return r; - if (!arg_no_reload) - r = daemon_reload(argc, argv, userdata); - else - r = 0; + if (arg_no_reload) + return 0; + return daemon_reload(argc, argv, userdata); } - - return r; } static int preset_all(int argc, char *argv[], void *userdata) { @@ -5691,13 +5644,7 @@ static int preset_all(int argc, char *argv[], void *userdata) { unsigned n_changes = 0; r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); - if (r < 0) - log_error_errno(r, "Operation failed: %m"); - else { - if (!arg_quiet) - dump_unit_file_changes(changes, n_changes); - } - + unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet); unit_file_changes_free(changes, n_changes); return r; } else { @@ -5724,7 +5671,7 @@ static int preset_all(int argc, char *argv[], void *userdata) { arg_runtime, arg_force); if (r < 0) - return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r)); r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); if (r < 0) -- cgit v1.2.3-54-g00ecf From 1fa0336081a671001a59ea56376132f3ef069a7b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 19 Apr 2016 00:04:35 -0400 Subject: shared/install: change value of _UNIT_FILE_CHANGE_TYPE_INVALID -1 could be confused with -EPERM. But we still need a negative enum value to force gcc to use int for the enum type, even though it is unused. Otherwise we get warnings. --- src/shared/install.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/install.h b/src/shared/install.h index 82c62095d5..4133faffa2 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -74,7 +74,7 @@ enum UnitFileChangeType { UNIT_FILE_UNLINK, UNIT_FILE_IS_MASKED, _UNIT_FILE_CHANGE_TYPE_MAX, - _UNIT_FILE_CHANGE_TYPE_INVALID = -1 + _UNIT_FILE_CHANGE_INVALID = INT_MIN }; /* type can either one of the UnitFileChangeTypes listed above, or a negative error. @@ -243,6 +243,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char const char *unit_file_state_to_string(UnitFileState s) _const_; UnitFileState unit_file_state_from_string(const char *s) _pure_; +/* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */ const char *unit_file_change_type_to_string(UnitFileChangeType s) _const_; UnitFileChangeType unit_file_change_type_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From fe4aede922f145df8b82108d937b65dcd3443588 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 17 Apr 2016 20:37:30 -0400 Subject: systemctl: warning about missing install info for template units The advice string didn't talk about template units at all. Extend it and print when trying to enable a template unit without install info. Fixes #2345. --- src/shared/install.c | 7 +++++-- src/systemctl/systemctl.c | 9 ++++++--- src/test/test-install-root.c | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index febe33ed7b..71012eafb4 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1466,8 +1466,10 @@ static int install_info_symlink_link( assert(i->path); r = in_search_path(paths, i->path); - if (r != 0) + if (r < 0) return r; + if (r > 0) + return 0; path = strjoin(config_path, "/", i->name, NULL); if (!path) @@ -1506,7 +1508,8 @@ static int install_info_apply( r = q; q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes); - if (r == 0) + /* Do not count links to the unit file towards the "carries_install_info" count */ + if (r == 0 && q < 0) r = q; return r; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index cfdc851a6d..115c00ea9c 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5527,15 +5527,18 @@ static int enable_unit(int argc, char *argv[], void *userdata) { } if (carries_install_info == 0) - log_warning("The unit files have no [Install] section. They are not meant to be enabled\n" - "using systemctl.\n" + log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n" + "settings in the [Install] section, and DefaultInstance for template units).\n" + "This means they are not meant to be enabled using systemctl.\n" "Possible reasons for having this kind of units are:\n" "1) A unit may be statically enabled by being symlinked from another unit's\n" " .wants/ or .requires/ directory.\n" "2) A unit's purpose may be to act as a helper for some other unit which has\n" " a requirement dependency on it.\n" "3) A unit may be started when needed via activation (socket, path, timer,\n" - " D-Bus, udev, scripted systemctl call, ...).\n"); + " D-Bus, udev, scripted systemctl call, ...).\n" + "4) In case of template units, the unit is meant to be enabled with some\n" + " instance name specified."); if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) { char *new_args[n_changes + 2]; diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 998c345a1a..2d73c9743b 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -107,7 +107,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); /* Enabling it again should succeed but be a NOP */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; -- cgit v1.2.3-54-g00ecf From 5cfde70c6e7c8afcd2c9cdb3505301c3e6cde6da Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 17 Apr 2016 20:46:00 -0400 Subject: run: change --tty option to --pty as documented Keep the previous option name as hidden, for compatibility. Fixes #3054. --- src/run/run.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/run/run.c b/src/run/run.c index f92a7f4e2e..c0aa2c5924 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -125,7 +125,6 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, - ARG_NO_ASK_PASSWORD, ARG_USER, ARG_SYSTEM, ARG_SCOPE, @@ -133,12 +132,11 @@ static int parse_argv(int argc, char *argv[]) { ARG_DESCRIPTION, ARG_SLICE, ARG_SEND_SIGHUP, + ARG_SERVICE_TYPE, ARG_EXEC_USER, ARG_EXEC_GROUP, - ARG_SERVICE_TYPE, ARG_NICE, ARG_SETENV, - ARG_TTY, ARG_ON_ACTIVE, ARG_ON_BOOT, ARG_ON_STARTUP, @@ -147,6 +145,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_ON_CALENDAR, ARG_TIMER_PROPERTY, ARG_NO_BLOCK, + ARG_NO_ASK_PASSWORD, }; static const struct option options[] = { @@ -168,7 +167,8 @@ static int parse_argv(int argc, char *argv[]) { { "nice", required_argument, NULL, ARG_NICE }, { "setenv", required_argument, NULL, ARG_SETENV }, { "property", required_argument, NULL, 'p' }, - { "tty", no_argument, NULL, 't' }, + { "tty", no_argument, NULL, 't' }, /* deprecated */ + { "pty", no_argument, NULL, 't' }, { "quiet", no_argument, NULL, 'q' }, { "on-active", required_argument, NULL, ARG_ON_ACTIVE }, { "on-boot", required_argument, NULL, ARG_ON_BOOT }, -- cgit v1.2.3-54-g00ecf From 0c7739039b090a2c1f8c894c0e6eb75fc25663a0 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Tue, 19 Apr 2016 17:59:47 +0300 Subject: coredump: create unnamed temporary files if possible (O_TMPFILE) (#3065) Don't leave temporary files if the coredump service is aborted during the operation Yeah, these are temporary files that systemd-coredump needs while processing the coredumps. Of course, if the coredump service is aborted during the operation we better shouldn't leave those files around. This is hence a bug to fix in our coredumping code. See https://github.com/systemd/systemd/issues/2804#issuecomment-210578147 Another option is to simply use O_TMPFILE, and when it is not available fall back to the current behaviour. After all, the files are cleaned up eventually, through normal tmpfiles aging, and the offending file systems are pretty exotic these days, or not in the upstream kernel. See https://github.com/systemd/systemd/issues/2804#issuecomment-211496707 --- src/coredump/coredump.c | 84 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index f65cb6f9dd..2bbb958861 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -49,6 +49,7 @@ #include "journald-native.h" #include "log.h" #include "macro.h" +#include "missing.h" #include "mkdir.h" #include "parse-util.h" #include "process-util.h" @@ -212,6 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { #define filename_escape(s) xescape((s), "./ ") +static inline const char *coredump_tmpfile_name(const char *s) { + return s ? s : "(unnamed temporary file)"; +} + static int fix_permissions( int fd, const char *filename, @@ -220,7 +225,6 @@ static int fix_permissions( uid_t uid) { assert(fd >= 0); - assert(filename); assert(target); assert(context); @@ -230,10 +234,20 @@ static int fix_permissions( (void) fix_xattr(fd, context); if (fsync(fd) < 0) - return log_error_errno(errno, "Failed to sync coredump %s: %m", filename); + return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename)); + + if (filename) { + if (rename(filename, target) < 0) + return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target); + } else { + _cleanup_free_ char *proc_fd_path = NULL; - if (rename(filename, target) < 0) - return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target); + if (asprintf(&proc_fd_path, "/proc/self/fd/%d", fd) < 0) + return log_oom(); + + if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0) + return log_error_errno(errno, "Failed to create coredump %s: %m", target); + } return 0; } @@ -294,6 +308,33 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { return 0; } +static int open_coredump_tmpfile(const char *target, char **ret_filename) { + _cleanup_free_ char *tmp = NULL; + int fd; + int r; + + assert(target); + assert(ret_filename); + + fd = open("/var/lib/systemd/coredump", O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0640); + if (fd < 0) { + log_debug_errno(errno, "Failed to use O_TMPFILE: %m"); + + r = tempfn_random(target, NULL, &tmp); + if (r < 0) + return log_error_errno(r, "Failed to determine temporary file name: %m"); + + fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640); + if (fd < 0) + return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp); + } + + *ret_filename = tmp; + tmp = NULL; + + return fd; +} + static int save_external_coredump( const char *context[_CONTEXT_MAX], int input_fd, @@ -335,15 +376,11 @@ static int save_external_coredump( if (r < 0) return log_error_errno(r, "Failed to determine coredump file name: %m"); - r = tempfn_random(fn, NULL, &tmp); - if (r < 0) - return log_error_errno(r, "Failed to determine temporary file name: %m"); - mkdir_p_label("/var/lib/systemd/coredump", 0755); - fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640); + fd = open_coredump_tmpfile(fn, &tmp); if (fd < 0) - return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp); + return fd; r = copy_bytes(input_fd, fd, max_size, false); if (r == -EFBIG) { @@ -358,12 +395,12 @@ static int save_external_coredump( } if (fstat(fd, &st) < 0) { - log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp); + log_error_errno(errno, "Failed to fstat coredump %s: %m", coredump_tmpfile_name(tmp)); goto fail; } if (lseek(fd, 0, SEEK_SET) == (off_t) -1) { - log_error_errno(errno, "Failed to seek on %s: %m", tmp); + log_error_errno(errno, "Failed to seek on %s: %m", coredump_tmpfile_name(tmp)); goto fail; } @@ -381,21 +418,13 @@ static int save_external_coredump( goto uncompressed; } - r = tempfn_random(fn_compressed, NULL, &tmp_compressed); - if (r < 0) { - log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed); + fd_compressed = open_coredump_tmpfile(fn_compressed, &tmp_compressed); + if (fd_compressed < 0) goto uncompressed; - } - - fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640); - if (fd_compressed < 0) { - log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed); - goto uncompressed; - } r = compress_stream(fd, fd_compressed, -1); if (r < 0) { - log_error_errno(r, "Failed to compress %s: %m", tmp_compressed); + log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed)); goto fail_compressed; } @@ -404,7 +433,8 @@ static int save_external_coredump( goto fail_compressed; /* OK, this worked, we can get rid of the uncompressed version now */ - unlink_noerrno(tmp); + if (tmp) + unlink_noerrno(tmp); *ret_filename = fn_compressed; /* compressed */ *ret_node_fd = fd_compressed; /* compressed */ @@ -417,7 +447,8 @@ static int save_external_coredump( return 0; fail_compressed: - (void) unlink(tmp_compressed); + if (tmp_compressed) + (void) unlink(tmp_compressed); } uncompressed: @@ -438,7 +469,8 @@ uncompressed: return 0; fail: - (void) unlink(tmp); + if (tmp) + (void) unlink(tmp); return r; } -- cgit v1.2.3-54-g00ecf From 409472cb8c072791dee8958af9349ee2276b8f09 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Wed, 20 Apr 2016 03:18:17 +0200 Subject: systemctl: hide "following" units if '--all' is not passed (#2967) No need to dump all the redundant device units on the user, just because he specified that he wants to see units of a specific state. This was broken by commit ebc962656cee33e3e8395f456a8208c3ca41969c. --- src/systemctl/systemctl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 115c00ea9c..059e985463 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -341,6 +341,12 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) { if (arg_all) return true; + /* Note that '--all' is not purely a state filter, but also a + * filter that hides units that "follow" other units (which is + * used for device units that appear under different names). */ + if (!isempty(u->following)) + return false; + if (!strv_isempty(arg_states)) return true; @@ -349,7 +355,7 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) { if (u->job_id > 0) return true; - if (streq(u->active_state, "inactive") || u->following[0]) + if (streq(u->active_state, "inactive")) return false; return true; -- cgit v1.2.3-54-g00ecf From 129baf1bbfe3174a667c1ae73de131c503c025ea Mon Sep 17 00:00:00 2001 From: Michał Bartoszkiewicz Date: Wed, 20 Apr 2016 10:06:26 +0200 Subject: logind: use type to determine graphical sessions (#3071) --- src/login/logind-session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 676fbc15a3..a8b1d5943d 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -797,7 +797,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) { /* Graphical sessions should really implement a real * idle hint logic */ - if (s->display) + if (SESSION_TYPE_IS_GRAPHICAL(s->type)) goto dont_know; /* For sessions with an explicitly configured tty, let's check -- cgit v1.2.3-54-g00ecf From ae5b39588734aacef5b6b411cf2053fdcef4764a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 19 Apr 2016 21:30:14 -0400 Subject: basic/terminal-util: cache value for colors_enabled After all it's something that we query over and over. For example, systemctl calls colors_enabled() four times for each failing service. The compiler is unable to optimize those calls away because they (potentially) accesses external and global state through on_tty() and getenv(). --- src/basic/terminal-util.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 0a9d2bbdef..9521b79daa 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1135,14 +1135,19 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { } bool colors_enabled(void) { - const char *colors; + static int enabled = -1; - colors = getenv("SYSTEMD_COLORS"); - if (!colors) { - if (streq_ptr(getenv("TERM"), "dumb")) - return false; - return on_tty(); + if (_unlikely_(enabled < 0)) { + const char *colors; + + colors = getenv("SYSTEMD_COLORS"); + if (colors) + enabled = parse_boolean(colors) != 0; + else if (streq_ptr(getenv("TERM"), "dumb")) + enabled = false; + else + enabled = on_tty(); } - return parse_boolean(colors) != 0; + return enabled; } -- cgit v1.2.3-54-g00ecf From a5f1cb3bad6742ca21e31d8cd71190b93b3c0cef Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 19 Apr 2016 21:54:55 -0400 Subject: nspawn: add -E as alias for --setenv v2: - "=" is required, so remove the tags that v1 added --- man/systemd-nspawn.xml | 3 ++- src/nspawn/nspawn.c | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 8a004af1a2..6732b9d7be 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -737,7 +737,8 @@ - + + Specifies an environment variable assignment to pass to the init process in the container, in the format diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8c1672ba0c..a07f148ef6 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -250,7 +250,7 @@ static void help(void) { " 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" + " -E --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" " --keep-unit Do not register a scope for the machine, reuse\n" @@ -333,7 +333,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_TMPFS, ARG_OVERLAY, ARG_OVERLAY_RO, - ARG_SETENV, ARG_SHARE_SYSTEM, ARG_REGISTER, ARG_KEEP_UNIT, @@ -374,7 +373,7 @@ static int parse_argv(int argc, char *argv[]) { { "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO }, { "machine", required_argument, NULL, 'M' }, { "slice", required_argument, NULL, 'S' }, - { "setenv", required_argument, NULL, ARG_SETENV }, + { "setenv", required_argument, NULL, 'E' }, { "selinux-context", required_argument, NULL, 'Z' }, { "selinux-apifs-context", required_argument, NULL, 'L' }, { "quiet", no_argument, NULL, 'q' }, @@ -711,7 +710,7 @@ static int parse_argv(int argc, char *argv[]) { break; } - case ARG_SETENV: { + case 'E': { char **n; if (!env_assignment_is_valid(optarg)) { -- cgit v1.2.3-54-g00ecf From b5911366d048743b26e65415eb35aae5138d83fd Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 20 Apr 2016 08:38:01 -0400 Subject: run: add -E as alias for --setenv --- man/systemd-run.xml | 8 ++++---- src/run/run.c | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/man/systemd-run.xml b/man/systemd-run.xml index 473f83eac6..245daae946 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -226,11 +226,11 @@ - + + - Runs the service process with the specified - environment variables set. Also see - Environment= in + Runs the service process with the specified environment variable set. + Also see Environment= in systemd.exec5. diff --git a/src/run/run.c b/src/run/run.c index c0aa2c5924..1993a424ca 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -103,7 +103,7 @@ static void help(void) { " --uid=USER Run as system user\n" " --gid=GROUP Run as system group\n" " --nice=NICE Nice level\n" - " --setenv=NAME=VALUE Set environment\n" + " -E --setenv=NAME=VALUE Set environment\n" " -t --pty Run service on pseudo tty\n" " -q --quiet Suppress information messages during runtime\n\n" "Timer options:\n\n" @@ -136,7 +136,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_EXEC_USER, ARG_EXEC_GROUP, ARG_NICE, - ARG_SETENV, ARG_ON_ACTIVE, ARG_ON_BOOT, ARG_ON_STARTUP, @@ -165,7 +164,7 @@ static int parse_argv(int argc, char *argv[]) { { "uid", required_argument, NULL, ARG_EXEC_USER }, { "gid", required_argument, NULL, ARG_EXEC_GROUP }, { "nice", required_argument, NULL, ARG_NICE }, - { "setenv", required_argument, NULL, ARG_SETENV }, + { "setenv", required_argument, NULL, 'E' }, { "property", required_argument, NULL, 'p' }, { "tty", no_argument, NULL, 't' }, /* deprecated */ { "pty", no_argument, NULL, 't' }, @@ -266,7 +265,7 @@ static int parse_argv(int argc, char *argv[]) { arg_nice_set = true; break; - case ARG_SETENV: + case 'E': if (strv_extend(&arg_environment, optarg) < 0) return log_oom(); -- cgit v1.2.3-54-g00ecf From 4d46e5db1518e6ed0f727e8561f130b4f512033f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 20 Apr 2016 08:41:25 -0400 Subject: machinectl: add -E as alias for --setenv --- man/machinectl.xml | 18 ++++++++---------- src/machine/machinectl.c | 7 +++---- 2 files changed, 11 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/man/machinectl.xml b/man/machinectl.xml index a77d2419af..43a3b98840 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -195,16 +195,14 @@ - - - When used with the shell - command, sets an environment variable to pass to the executed - shell. Takes a pair of environment variable name and value, - separated by = as argument. This switch - may be used multiple times to set multiple environment - variables. Note that this switch is not supported for the - login command (see - below). + + + + When used with the shell command, sets an environment + variable to pass to the executed shell. Takes an environment variable name and value, + separated by =. This switch may be used multiple times to set multiple + environment variables. Note that this switch is not supported for the + login command (see below). diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 35177aa29e..c370ed57ec 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2402,7 +2402,7 @@ static int help(int argc, char *argv[], void *userdata) { " --kill-who=WHO Who to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" " --uid=USER Specify user ID to invoke shell as\n" - " --setenv=VAR=VALUE Add an environment variable for shell\n" + " -E --setenv=VAR=VALUE Add an environment variable for shell\n" " --read-only Create read-only bind mount\n" " --mkdir Create directory before bind mounting, if missing\n" " -n --lines=INTEGER Number of journal entries to show\n" @@ -2470,7 +2470,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_FORCE, ARG_FORMAT, ARG_UID, - ARG_SETENV, }; static const struct option options[] = { @@ -2496,7 +2495,7 @@ static int parse_argv(int argc, char *argv[]) { { "force", no_argument, NULL, ARG_FORCE }, { "format", required_argument, NULL, ARG_FORMAT }, { "uid", required_argument, NULL, ARG_UID }, - { "setenv", required_argument, NULL, ARG_SETENV }, + { "setenv", required_argument, NULL, 'E' }, {} }; @@ -2624,7 +2623,7 @@ static int parse_argv(int argc, char *argv[]) { arg_uid = optarg; break; - case ARG_SETENV: + case 'E': if (!env_assignment_is_valid(optarg)) { log_error("Environment assignment invalid: %s", optarg); return -EINVAL; -- cgit v1.2.3-54-g00ecf From d5ca5e132463c52c5a9c6285475c7a51b894b9e4 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 19 Apr 2016 21:56:39 -0400 Subject: pid1: disable color output when TERM=dumb This changes the behaviour of pid1 in the following ways: - obviously $TERM is now checked, - $SYSTEMD_COLORS is now honoured too, before only SYSTEMD_LOG_COLORS was checked, - isatty() is run on stdout not stderr. As requested in #3025. --- src/core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/main.c b/src/core/main.c index 2912608435..8dfb3928de 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1338,7 +1338,7 @@ int main(int argc, char *argv[]) { saved_argv = argv; saved_argc = argc; - log_show_color(isatty(STDERR_FILENO) > 0); + log_show_color(colors_enabled()); log_set_upgrade_syslog_to_journal(true); /* Disable the umask logic */ -- cgit v1.2.3-54-g00ecf From f7ac1ed2cafbe57b0e123a4f7f75013d3399788f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 19 Apr 2016 22:34:04 -0400 Subject: tmpfiles: interpret "-" as stdin --- man/systemd-tmpfiles.xml | 10 +++++----- src/tmpfiles/tmpfiles.c | 26 +++++++++++++++++--------- 2 files changed, 22 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml index 447a7eaa17..c1aab51551 100644 --- a/man/systemd-tmpfiles.xml +++ b/man/systemd-tmpfiles.xml @@ -75,11 +75,11 @@ tmpfiles.d5. - If invoked with no arguments, it applies all directives from - all configuration files. If one or more absolute filenames are passed on - the command line, only the directives in these files are applied. - If only the basename of a configuration file is specified, all - configuration directories as specified in + If invoked with no arguments, it applies all directives from all configuration + files. If one or more absolute filenames are passed on the command line, only the + directives in these files are applied. If - is specified instead + of a filename, directives are read from standard input. If only the basename of a + configuration file is specified, all configuration directories as specified in tmpfiles.d5 are searched for a matching file. diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index efd264b34d..85b876d11b 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2198,7 +2198,8 @@ static int parse_argv(int argc, char *argv[]) { } static int read_config_file(const char *fn, bool ignore_enoent) { - _cleanup_fclose_ FILE *f = NULL; + _cleanup_fclose_ FILE *_f = NULL; + FILE *f; char line[LINE_MAX]; Iterator iterator; unsigned v = 0; @@ -2207,16 +2208,23 @@ static int read_config_file(const char *fn, bool ignore_enoent) { assert(fn); - r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f); - if (r < 0) { - if (ignore_enoent && r == -ENOENT) { - log_debug_errno(r, "Failed to open \"%s\": %m", fn); - return 0; - } + if (streq(fn, "-")) { + log_debug("Reading config from stdin."); + fn = ""; + f = stdin; + } else { + r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &_f); + if (r < 0) { + if (ignore_enoent && r == -ENOENT) { + log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn); + return 0; + } - return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn); + return log_error_errno(r, "Failed to open '%s': %m", fn); + } + log_debug("Reading config file \"%s\".", fn); + f = _f; } - log_debug("Reading config file \"%s\".", fn); FOREACH_LINE(line, f, break) { char *l; -- cgit v1.2.3-54-g00ecf From 022ffe4ccac688a5a68bc574ea708938681db1ec Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 19 Apr 2016 22:42:00 -0400 Subject: tmpfiles: shorten some long error messages Also don't print %m when the message already contains all the info. --- src/tmpfiles/tmpfiles.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 85b876d11b..d868cb5d31 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1276,11 +1276,11 @@ static int create_item(Item *i) { if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) { r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA); if (r == -ENOTTY) - log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path); + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path); else if (r == -EROFS) - log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path); + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path); else if (r == -ENOPROTOOPT) - log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path); + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path); else if (r < 0) q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path); else if (r > 0) -- cgit v1.2.3-54-g00ecf From df8dee85da5fa41e95dd7f536e67fcc6940a6488 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 20 Apr 2016 00:06:25 -0400 Subject: tmpfiles: add new 'e' action which cleans up a dir without creating it I wanted to add a config line that would empty a directory without creating it if doesn't exist. Existing actions don't allow this. v2: properly add 'e' to needs_glob() and takes_ownership() --- man/tmpfiles.d.xml | 22 ++++++++++++++++++- src/tmpfiles/tmpfiles.c | 56 +++++++++++++------------------------------------ 2 files changed, 36 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index cd6d7f626c..957475d2bd 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -168,6 +168,12 @@ of the directory will be removed when is used. + + + e + Similar to d, but the directory will not be + created if it does not exist. Lines of this type accept shell-style globs in + place of normal path names. @@ -581,7 +587,7 @@ unconditionally. The age field only applies to lines starting with - d, D, + d, D, e, v, q, Q, C, x and X. If omitted or set to @@ -657,8 +663,22 @@ d /var/tmp 1777 root root 30d # /usr/lib/tmpfiles.d/abrt.conf d /var/tmp/abrt 0755 abrt abrt - + + + + + Apply clean up during boot and based on time + + # /usr/lib/tmpfiles.d/dnf.conf +r! /var/cache/dnf/*/*/download_lock.pid +r! /var/cache/dnf/*/*/metadata_lock.pid +r! /var/lib/dnf/rpmdb_lock.pid +e /var/chache/dnf/ - - - 30d + The lock files will be removed during boot. Any files and directories in + /var/chache/dnf/ will be removed after they have not been + accessed in 30 days. diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index d868cb5d31..2053d35a67 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -94,6 +94,7 @@ typedef enum ItemType { /* These ones take globs */ WRITE_FILE = 'w', + EMPTY_DIRECTORY = 'e', SET_XATTR = 't', RECURSIVE_SET_XATTR = 'T', SET_ACL = 'a', @@ -179,6 +180,7 @@ static bool needs_glob(ItemType t) { IGNORE_DIRECTORY_PATH, REMOVE_PATH, RECURSIVE_REMOVE_PATH, + EMPTY_DIRECTORY, ADJUST_MODE, RELABEL_PATH, RECURSIVE_RELABEL_PATH, @@ -195,6 +197,7 @@ static bool takes_ownership(ItemType t) { CREATE_FILE, TRUNCATE_FILE, CREATE_DIRECTORY, + EMPTY_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, @@ -1217,7 +1220,6 @@ static int create_item(Item *i) { case CREATE_SUBVOLUME: case CREATE_SUBVOLUME_INHERIT_QUOTA: case CREATE_SUBVOLUME_NEW_QUOTA: - RUN_WITH_UMASK(0000) mkdir_parents_label(i->path, 0755); @@ -1289,6 +1291,9 @@ static int create_item(Item *i) { log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path); } + /* fall through */ + + case EMPTY_DIRECTORY: r = path_set_perms(i, i->path); if (q < 0) return q; @@ -1298,7 +1303,6 @@ static int create_item(Item *i) { break; case CREATE_FIFO: - RUN_WITH_UMASK(0000) { mac_selinux_create_file_prepare(i->path, S_IFIFO); r = mkfifo(i->path, i->mode); @@ -1535,47 +1539,20 @@ static int remove_item_instance(Item *i, const char *instance) { } static int remove_item(Item *i) { - int r = 0; - assert(i); log_debug("Running remove action for entry %c %s", (char) i->type, i->path); switch (i->type) { - case CREATE_FILE: - case TRUNCATE_FILE: - case CREATE_DIRECTORY: - case CREATE_SUBVOLUME: - case CREATE_SUBVOLUME_INHERIT_QUOTA: - case CREATE_SUBVOLUME_NEW_QUOTA: - case CREATE_FIFO: - case CREATE_SYMLINK: - case CREATE_CHAR_DEVICE: - case CREATE_BLOCK_DEVICE: - case IGNORE_PATH: - case IGNORE_DIRECTORY_PATH: - case ADJUST_MODE: - case RELABEL_PATH: - case RECURSIVE_RELABEL_PATH: - case WRITE_FILE: - case COPY_FILES: - case SET_XATTR: - case RECURSIVE_SET_XATTR: - case SET_ACL: - case RECURSIVE_SET_ACL: - case SET_ATTRIBUTE: - case RECURSIVE_SET_ATTRIBUTE: - break; - case REMOVE_PATH: case TRUNCATE_DIRECTORY: case RECURSIVE_REMOVE_PATH: - r = glob_item(i, remove_item_instance, false); - break; - } + return glob_item(i, remove_item_instance, false); - return r; + default: + return 0; + } } static int clean_item_instance(Item *i, const char* instance) { @@ -1630,8 +1607,6 @@ static int clean_item_instance(Item *i, const char* instance) { } static int clean_item(Item *i) { - int r = 0; - assert(i); log_debug("Running clean action for entry %c %s", (char) i->type, i->path); @@ -1641,19 +1616,17 @@ static int clean_item(Item *i) { case CREATE_SUBVOLUME: case CREATE_SUBVOLUME_INHERIT_QUOTA: case CREATE_SUBVOLUME_NEW_QUOTA: + case EMPTY_DIRECTORY: case TRUNCATE_DIRECTORY: case IGNORE_PATH: case COPY_FILES: clean_item_instance(i, i->path); - break; + return 0; case IGNORE_DIRECTORY_PATH: - r = glob_item(i, clean_item_instance, false); - break; + return glob_item(i, clean_item_instance, false); default: - break; + return 0; } - - return r; } static int process_item_array(ItemArray *array); @@ -1879,6 +1852,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { case CREATE_SUBVOLUME: case CREATE_SUBVOLUME_INHERIT_QUOTA: case CREATE_SUBVOLUME_NEW_QUOTA: + case EMPTY_DIRECTORY: case TRUNCATE_DIRECTORY: case CREATE_FIFO: case IGNORE_PATH: -- cgit v1.2.3-54-g00ecf From 439689c6ec48faba67565562d75701d5736567e7 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 21 Apr 2016 06:04:13 +0530 Subject: networkd: bump MTU to 1280 for interfaces which have IPv6 enabled (#3077) IPv6 protocol requires a minimum MTU of 1280 bytes on the interface. This fixes #3046. Introduce helper link_ipv6_enabled() to figure out whether IPV6 is enabled. Introduce network_has_static_ipv6_addresses() to find out if any static ipv6 address configured. If IPv6 is not configured on any interface that is SLAAC, DHCPv6 and static IPv6 addresses not configured, then IPv6 will be automatically disabled for that interface, that is we write "1" to /proc/sys/net/ipv6/conf//disable_ipv6. --- man/systemd.network.xml | 11 ++++++++++ src/basic/missing.h | 4 ++++ src/network/networkd-link.c | 50 +++++++++++++++++++++++++++++++++++++++++- src/network/networkd-network.c | 13 +++++++++++ src/network/networkd-network.h | 2 ++ 5 files changed, 79 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index d7947836e9..8ae384185d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -202,6 +202,8 @@ 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. + Note that if IPv6 is enabled on the interface, and the MTU is chosen + below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value. @@ -210,6 +212,15 @@ Identity Association Identifier for the interface, a 32-bit unsigned integer. + + + Note that an interface without any static IPv6 addresses configured, and neither + DHCPv6 nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be + automatically disabled for that interface by writing "1" to + /proc/sys/net/ipv6/conf/ifname/disable_ipv6. + + + diff --git a/src/basic/missing.h b/src/basic/missing.h index 6a49ccd281..6616f0b720 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -828,6 +828,10 @@ struct btrfs_ioctl_quota_ctl_args { #define IPV6_UNICAST_IF 76 #endif +#ifndef IPV6_MIN_MTU +#define IPV6_MIN_MTU 1280 +#endif + #ifndef IFF_MULTI_QUEUE #define IFF_MULTI_QUEUE 0x100 #endif diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9059a68fe3..0fb3aa6c43 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -99,6 +99,15 @@ static bool link_ipv6ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV6; } +static bool link_ipv6_enabled(Link *link) { + assert(link); + + if (!socket_ipv6_is_supported()) + return false; + + return link_dhcp6_enabled(link) || link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network); +} + static bool link_lldp_rx_enabled(Link *link) { assert(link); @@ -218,6 +227,31 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) { return link->network->ipv6_privacy_extensions; } +static int link_enable_ipv6(Link *link) { + const char *p = NULL; + bool disabled; + int r; + + if (link->flags & IFF_LOOPBACK) + return 0; + + disabled = !link_ipv6_enabled(link); + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6"); + + r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m", disabled ? "disable" : "enable", link->ifname); + else { + if (disabled) + log_link_info(link, "IPv6 disabled for interface: %m"); + else + log_link_info(link, "IPv6 enabled for interface: %m"); + } + + return 0; +} + void link_update_operstate(Link *link) { LinkOperationalState operstate; assert(link); @@ -1510,7 +1544,21 @@ static int link_up(Link *link) { return log_link_error_errno(link, r, "Could not set MAC address: %m"); } + /* If IPv6 not configured (no static IPv6 address and neither DHCPv6 nor IPv6LL is enabled) + for this interface then disable IPv6 else enable it. */ + (void) link_enable_ipv6(link); + if (link->network->mtu) { + /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes + on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */ + if (link_ipv6_enabled(link) && link->network->mtu < IPV6_MIN_MTU) { + + log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as " + "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes: %m"); + + link->network->mtu = IPV6_MIN_MTU; + } + r = sd_netlink_message_append_u32(req, IFLA_MTU, link->network->mtu); if (r < 0) return log_link_error_errno(link, r, "Could not set MTU: %m"); @@ -1520,7 +1568,7 @@ static int link_up(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); - if (socket_ipv6_is_supported()) { + if (link_ipv6_enabled(link)) { /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */ r = sd_netlink_message_open_container(req, AF_INET6); if (r < 0) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 1c7adf5180..07f8fb028f 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -399,6 +399,19 @@ int network_apply(Manager *manager, Network *network, Link *link) { return 0; } +bool network_has_static_ipv6_addresses(Network *network) { + Address *address; + + assert(network); + + LIST_FOREACH(addresses, address, network->static_addresses) { + if (address->family == AF_INET6) + return true; + } + + return false; +} + int config_parse_netdev(const char *unit, const char *filename, unsigned line, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 3d44113b05..15417f4828 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -186,6 +186,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret); int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret); int network_apply(Manager *manager, Network *network, Link *link); +bool network_has_static_ipv6_addresses(Network *network); + int config_parse_netdev(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_domains(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_tunnel(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); -- cgit v1.2.3-54-g00ecf From 964b26fe2127d28713bccf03603900a7691216ba Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 21 Apr 2016 06:06:33 +0530 Subject: networkd: respect DHCP UseRoutes option (#3075) This fixes #2282. --- src/network/networkd-dhcp4.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 0589ebf227..c5b61abc9e 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -57,6 +57,10 @@ static int link_set_dhcp_routes(Link *link) { assert(link); assert(link->dhcp_lease); + assert(link->network); + + if (!link->network->dhcp_use_routes) + return 0; r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r < 0 && r != -ENODATA) -- cgit v1.2.3-54-g00ecf From c8a806f2c0939c241b4a99ca861d4f3dca103f14 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 9 Apr 2016 11:13:26 -0400 Subject: core: prefix selinux messages with "selinux: " SELinux outputs semi-random messages like "Unknown permission start for class system", and the user has to dig into message metadata to find out where they are comming from. Add a prefix to give a hint. --- src/core/selinux-access.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index 2cdfcf7b5d..cc287d602d 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -110,6 +110,7 @@ static int callback_type_to_priority(int type) { */ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) { va_list ap; + const char *fmt2; #ifdef HAVE_AUDIT int fd; @@ -131,8 +132,10 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) { } #endif + fmt2 = strjoina("selinux: ", fmt); + va_start(ap, fmt); - log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap); + log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt2, ap); va_end(ap); return 0; -- cgit v1.2.3-54-g00ecf From a2ed707712161869cf53102d786c939e658962e5 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 9 Apr 2016 15:03:19 -0400 Subject: logind: reload config on SIGHUP v2: - fix setting of kill_user_processes and *_ignore_inhibited settings --- src/login/logind-core.c | 3 ++ src/login/logind.c | 82 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 59 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 8bdb3a9a38..73075274e0 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -367,6 +367,9 @@ bool manager_shall_kill(Manager *m, const char *user) { if (!m->kill_user_processes) return false; + if (!m->kill_exclude_users && streq(user, "root")) + return false; + if (strv_contains(m->kill_exclude_users, user)) return false; diff --git a/src/login/logind.c b/src/login/logind.c index d5f6757bd3..268502c437 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -41,17 +41,7 @@ static void manager_free(Manager *m); -static Manager *manager_new(void) { - Manager *m; - int r; - - m = new0(Manager, 1); - if (!m) - return NULL; - - m->console_active_fd = -1; - m->reserve_vt_fd = -1; - +static void manager_reset_config(Manager *m) { m->n_autovts = 6; m->reserve_vt = 6; m->remove_ipc = true; @@ -61,16 +51,38 @@ static Manager *manager_new(void) { m->handle_hibernate_key = HANDLE_HIBERNATE; m->handle_lid_switch = HANDLE_SUSPEND; m->handle_lid_switch_docked = HANDLE_IGNORE; + m->power_key_ignore_inhibited = false; + m->suspend_key_ignore_inhibited = false; + m->hibernate_key_ignore_inhibited = false; 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; - m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ m->user_tasks_max = UINT64_C(12288); + m->kill_user_processes = false; + + m->kill_only_users = strv_free(m->kill_only_users); + m->kill_exclude_users = strv_free(m->kill_exclude_users); +} + +static Manager *manager_new(void) { + Manager *m; + int r; + + m = new0(Manager, 1); + if (!m) + return NULL; + + m->console_active_fd = -1; + m->reserve_vt_fd = -1; + + m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); + m->devices = hashmap_new(&string_hash_ops); m->seats = hashmap_new(&string_hash_ops); m->sessions = hashmap_new(&string_hash_ops); @@ -84,10 +96,6 @@ static Manager *manager_new(void) { if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units) goto fail; - m->kill_exclude_users = strv_new("root", NULL); - if (!m->kill_exclude_users) - goto fail; - m->udev = udev_new(); if (!m->udev) goto fail; @@ -98,6 +106,8 @@ static Manager *manager_new(void) { sd_event_set_watchdog(m->event, true); + manager_reset_config(m); + return m; fail: @@ -986,6 +996,30 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us return 0; } +static int manager_parse_config_file(Manager *m) { + assert(m); + + return config_parse_many(PKGSYSCONFDIR "/logind.conf", + CONF_PATHS_NULSTR("systemd/logind.conf.d"), + "Login\0", + config_item_perf_lookup, logind_gperf_lookup, + false, m); +} + +static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + Manager *m = userdata; + int r; + + manager_reset_config(m); + r = manager_parse_config_file(m); + if (r < 0) + log_warning_errno(r, "Failed to parse config file, using defaults: %m"); + else + log_info("Config file reloaded."); + + return 0; +} + static int manager_startup(Manager *m) { int r; Seat *seat; @@ -997,6 +1031,12 @@ static int manager_startup(Manager *m) { assert(m); + assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGHUP, -1) >= 0); + + r = sd_event_add_signal(m->event, NULL, SIGHUP, manager_dispatch_reload_signal, m); + if (r < 0) + return log_error_errno(r, "Failed to register SIGHUP handler: %m"); + /* Connect to console */ r = manager_connect_console(m); if (r < 0) @@ -1099,16 +1139,6 @@ static int manager_run(Manager *m) { } } -static int manager_parse_config_file(Manager *m) { - assert(m); - - return config_parse_many(PKGSYSCONFDIR "/logind.conf", - CONF_PATHS_NULSTR("systemd/logind.conf.d"), - "Login\0", - config_item_perf_lookup, logind_gperf_lookup, - false, m); -} - int main(int argc, char *argv[]) { Manager *m = NULL; int r; -- cgit v1.2.3-54-g00ecf From 97e5530cf2076a2b4fc55755917262607aaa6338 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 9 Apr 2016 20:40:45 -0400 Subject: logind: flip KillUserProcesses to on by default This ensures that users sessions are properly cleaned up after. The admin can still enable or disable linger for specific users to allow them to run processes after they log out. Doing that through the user session is much cleaner and provides better control. dbus daemon can now be run in the user session (with --enable-user-session, added in 1.10.2), and most distributions opted to pick this configuration. In the normal case it makes a lot of sense to kill remaining processes. The exception is stuff like screen and tmux. But it's easy enough to work around, a simple example was added to the man page in previous commit. In the long run those services should integrate with the systemd users session on their own. https://bugs.freedesktop.org/show_bug.cgi?id=94508 https://github.com/systemd/systemd/issues/2900 --- NEWS | 27 ++++++++++++++++++++++++--- man/logind.conf.xml | 2 +- src/login/logind.c | 2 +- src/login/logind.conf | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index b75638ed36..99e6b51ae3 100644 --- a/NEWS +++ b/NEWS @@ -22,9 +22,26 @@ CHANGES WITH 230 in spe: * systemd-resolve conveniently resolves DANE records with the --tlsa option and OPENPGPKEY records with the --openpgp option. - * Testing tool /usr/lib/systemd/systemd-activate is renamed to - systemd-socket-activate and installed into /usr/bin. It is now fully - supported. + * systemd-logind will now by default terminate user processes that are + part of the user session scope unit (session-XX.scope) when the user + logs out. This behaviour is controlled by the + KillUserProcesses=yes|no setting in logind.conf, and previous default + of "no" is now changed to "yes". This means that user sessions will + be properly cleaned up after, but additional steps are necessary to + allow intentionally long-running processes to survive logout. + + While the user is logged in at least once, user@.service is running, + and any service that should survive the end of any individual login + session can be started at a user service or scope using systemd-run. + systemd-run(1) man page has been extended with an example which + shows how to run screen in a scope unit underneath user@.service. + The same command works for tmux. + + After the user logs out of all sessions, user@.service will be + terminated too, by default, unless the user has "lingering" enabled. + To effectively allow users to run long-term tasks even if they are + logged out, lingering must be enabled for them. See loginctl(1) + for details. * The unified cgroup hierarchy added in Linux 4.5 is now supported. Use systemd.unified_cgroup_hierarchy=1 on the kernel command line @@ -45,6 +62,10 @@ CHANGES WITH 230 in spe: * The Unique Identifier sent in DHCP requests can be configured. + * Testing tool /usr/lib/systemd/systemd-activate is renamed to + systemd-socket-activate and installed into /usr/bin. It is now fully + supported. + * systemd-journald now uses separate threads to flush changes to disk when closing journal files. diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 10a23955a4..6e587c3561 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -124,7 +124,7 @@ corresponding to the session and all processes inside that scope will be terminated. If false, the scope is "abandonded", see systemd.scope5, - and processes are not killed. Defaults to no. + and processes are not killed. Defaults to yes. In addition to session processes, user process may run under the user manager unit user@.service. Depending on the linger diff --git a/src/login/logind.c b/src/login/logind.c index 268502c437..616346799a 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -64,7 +64,7 @@ static void manager_reset_config(Manager *m) { m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ m->user_tasks_max = UINT64_C(12288); - m->kill_user_processes = false; + m->kill_user_processes = true; m->kill_only_users = strv_free(m->kill_only_users); m->kill_exclude_users = strv_free(m->kill_exclude_users); diff --git a/src/login/logind.conf b/src/login/logind.conf index 6095e482ac..8316bb4d74 100644 --- a/src/login/logind.conf +++ b/src/login/logind.conf @@ -14,7 +14,7 @@ [Login] #NAutoVTs=6 #ReserveVT=6 -#KillUserProcesses=no +#KillUserProcesses=yes #KillOnlyUsers= #KillExcludeUsers=root #InhibitDelayMaxSec=5 -- cgit v1.2.3-54-g00ecf From 95365a576f7e81f3e2f02fa3e8225c4b03f12214 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 11 Apr 2016 22:51:31 -0400 Subject: build-sys: add --without-kill-user-processes configure option --- Makefile.am | 6 +- NEWS | 3 + configure.ac | 215 +++++++++++++++++++++++++---------------------- src/login/.gitignore | 1 + src/login/logind.c | 2 +- src/login/logind.conf | 35 -------- src/login/logind.conf.in | 35 ++++++++ 7 files changed, 157 insertions(+), 140 deletions(-) delete mode 100644 src/login/logind.conf create mode 100644 src/login/logind.conf.in (limited to 'src') diff --git a/Makefile.am b/Makefile.am index c566b1f6e4..e97d5bd78f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5725,7 +5725,7 @@ dist_dbussystemservice_DATA += \ dist_dbuspolicy_DATA += \ src/login/org.freedesktop.login1.conf -dist_pkgsysconf_DATA += \ +nodist_pkgsysconf_DATA += \ src/login/logind.conf polkitpolicy_files += \ @@ -5762,7 +5762,8 @@ gperf_gperf_sources += \ EXTRA_DIST += \ src/login/71-seat.rules.in \ src/login/73-seat-late.rules.in \ - units/systemd-logind.service.in + units/systemd-logind.service.in \ + src/login/logind.conf.in # ------------------------------------------------------------------------------ if HAVE_PAM @@ -5879,6 +5880,7 @@ substitutions = \ '|NTP_SERVERS=$(NTP_SERVERS)|' \ '|DNS_SERVERS=$(DNS_SERVERS)|' \ '|DEFAULT_DNSSEC_MODE=$(DEFAULT_DNSSEC_MODE)|' \ + '|KILL_USER_PROCESSES=$(KILL_USER_PROCESSES)|' \ '|systemuidmax=$(SYSTEM_UID_MAX)|' \ '|systemgidmax=$(SYSTEM_GID_MAX)|' \ '|TTY_GID=$(TTY_GID)|' \ diff --git a/NEWS b/NEWS index 99e6b51ae3..7199a67201 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,9 @@ CHANGES WITH 230 in spe: logged out, lingering must be enabled for them. See loginctl(1) for details. + Previous defaults can be restored at compile time by the + --without-kill-user-processes option. + * The unified cgroup hierarchy added in Linux 4.5 is now supported. Use systemd.unified_cgroup_hierarchy=1 on the kernel command line to enable. diff --git a/configure.ac b/configure.ac index 7b9e64a0f6..d4e8ab6664 100644 --- a/configure.ac +++ b/configure.ac @@ -1014,6 +1014,16 @@ fi AM_CONDITIONAL(ENABLE_LOGIND, [test "$have_logind" = "yes"]) AS_IF([test "$have_logind" = "yes"], [ AC_DEFINE(HAVE_LOGIND, [1], [Logind support available]) ]) +AC_ARG_WITH([kill-user-processes], + [AS_HELP_STRING([--without-kill-user-processes], [Set logind's KillUserProcesses=no by default])]) +AS_IF([test "$with_kill_user_processes" != "no"], + [kill_user_processes=true + KILL_USER_PROCESSES=yes], + [kill_user_processes=false + KILL_USER_PROCESSES=no]) +AC_DEFINE_UNQUOTED(KILL_USER_PROCESSES, [$kill_user_processes], [Default KillUserProcesses setting]) +AC_SUBST(KILL_USER_PROCESSES) + # ------------------------------------------------------------------------------ have_machined=no AC_ARG_ENABLE(machined, AS_HELP_STRING([--disable-machined], [disable machine daemon])) @@ -1554,106 +1564,107 @@ AC_OUTPUT AC_MSG_RESULT([ $PACKAGE_NAME $VERSION - libcryptsetup: ${have_libcryptsetup} - PAM: ${have_pam} - AUDIT: ${have_audit} - IMA: ${have_ima} - AppArmor: ${have_apparmor} - SELinux: ${have_selinux} - SECCOMP: ${have_seccomp} - SMACK: ${have_smack} - ZLIB: ${have_zlib} - XZ: ${have_xz} - LZ4: ${have_lz4} - BZIP2: ${have_bzip2} - ACL: ${have_acl} - GCRYPT: ${have_gcrypt} - QRENCODE: ${have_qrencode} - MICROHTTPD: ${have_microhttpd} - GNUTLS: ${have_gnutls} - libcurl: ${have_libcurl} - libidn: ${have_libidn} - libiptc: ${have_libiptc} - ELFUTILS: ${have_elfutils} - binfmt: ${have_binfmt} - vconsole: ${have_vconsole} - quotacheck: ${have_quotacheck} - tmpfiles: ${have_tmpfiles} - sysusers: ${have_sysusers} - firstboot: ${have_firstboot} - randomseed: ${have_randomseed} - backlight: ${have_backlight} - rfkill: ${have_rfkill} - logind: ${have_logind} - machined: ${have_machined} - importd: ${have_importd} - hostnamed: ${have_hostnamed} - timedated: ${have_timedated} - timesyncd: ${have_timesyncd} - Default NTP servers: ${NTP_SERVERS} - time epoch: ${TIME_EPOCH} - localed: ${have_localed} - networkd: ${have_networkd} - resolved: ${have_resolved} - Default DNS servers: ${DNS_SERVERS} - Default DNSSEC mode: ${DEFAULT_DNSSEC_MODE} - 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} - hwdb: ${enable_hwdb} - tpm: ${have_tpm} - kdbus: ${have_kdbus} - Python: ${have_python} - man pages: ${have_manpages} - test coverage: ${have_coverage} - Split /usr: ${enable_split_usr} - SysV compatibility: ${SYSTEM_SYSV_COMPAT} - utmp/wtmp support: ${have_utmp} - ldconfig support: ${enable_ldconfig} - hibernate support: ${enable_hibernate} - extra debugging: ${enable_debug} - tests: ${enable_tests} - - prefix: ${prefix} - rootprefix: ${with_rootprefix} - sysconf dir: ${sysconfdir} - datarootdir: ${datarootdir} - includedir: ${includedir} - lib dir: ${libdir} - rootlib dir: ${with_rootlibdir} - SysV init scripts: ${SYSTEM_SYSVINIT_PATH} - SysV rc?.d directories: ${SYSTEM_SYSVRCND_PATH} - Build Python: ${PYTHON} - PAM modules dir: ${with_pamlibdir} - PAM configuration dir: ${with_pamconfdir} - D-Bus policy dir: ${with_dbuspolicydir} - D-Bus session dir: ${with_dbussessionservicedir} - D-Bus system dir: ${with_dbussystemservicedir} - Bash completions dir: ${with_bashcompletiondir} - Zsh completions dir: ${with_zshcompletiondir} - Extra start script: ${RC_LOCAL_SCRIPT_PATH_START} - Extra stop script: ${RC_LOCAL_SCRIPT_PATH_STOP} - Wheel group: ${have_wheel_group} - Debug shell: ${SUSHELL} @ ${DEBUGTTY} - TTY GID: ${TTY_GID} - Maximum System UID: ${SYSTEM_UID_MAX} - Maximum System GID: ${SYSTEM_GID_MAX} - Certificate root: ${CERTIFICATEROOT} - - CFLAGS: ${OUR_CFLAGS} ${CFLAGS} - CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} - LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS} + libcryptsetup: ${have_libcryptsetup} + PAM: ${have_pam} + AUDIT: ${have_audit} + IMA: ${have_ima} + AppArmor: ${have_apparmor} + SELinux: ${have_selinux} + SECCOMP: ${have_seccomp} + SMACK: ${have_smack} + ZLIB: ${have_zlib} + XZ: ${have_xz} + LZ4: ${have_lz4} + BZIP2: ${have_bzip2} + ACL: ${have_acl} + GCRYPT: ${have_gcrypt} + QRENCODE: ${have_qrencode} + MICROHTTPD: ${have_microhttpd} + GNUTLS: ${have_gnutls} + libcurl: ${have_libcurl} + libidn: ${have_libidn} + libiptc: ${have_libiptc} + ELFUTILS: ${have_elfutils} + binfmt: ${have_binfmt} + vconsole: ${have_vconsole} + quotacheck: ${have_quotacheck} + tmpfiles: ${have_tmpfiles} + sysusers: ${have_sysusers} + firstboot: ${have_firstboot} + randomseed: ${have_randomseed} + backlight: ${have_backlight} + rfkill: ${have_rfkill} + logind: ${have_logind} + Default KillUserProcesses setting: ${KILL_USER_PROCESSES} + machined: ${have_machined} + importd: ${have_importd} + hostnamed: ${have_hostnamed} + timedated: ${have_timedated} + timesyncd: ${have_timesyncd} + Default NTP servers: ${NTP_SERVERS} + time epoch: ${TIME_EPOCH} + localed: ${have_localed} + networkd: ${have_networkd} + resolved: ${have_resolved} + Default DNS servers: ${DNS_SERVERS} + Default DNSSEC mode: ${DEFAULT_DNSSEC_MODE} + 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} + hwdb: ${enable_hwdb} + tpm: ${have_tpm} + kdbus: ${have_kdbus} + Python: ${have_python} + man pages: ${have_manpages} + test coverage: ${have_coverage} + Split /usr: ${enable_split_usr} + SysV compatibility: ${SYSTEM_SYSV_COMPAT} + utmp/wtmp support: ${have_utmp} + ldconfig support: ${enable_ldconfig} + hibernate support: ${enable_hibernate} + extra debugging: ${enable_debug} + tests: ${enable_tests} + + prefix: ${prefix} + rootprefix: ${with_rootprefix} + sysconf dir: ${sysconfdir} + datarootdir: ${datarootdir} + includedir: ${includedir} + lib dir: ${libdir} + rootlib dir: ${with_rootlibdir} + SysV init scripts: ${SYSTEM_SYSVINIT_PATH} + SysV rc?.d directories: ${SYSTEM_SYSVRCND_PATH} + Build Python: ${PYTHON} + PAM modules dir: ${with_pamlibdir} + PAM configuration dir: ${with_pamconfdir} + D-Bus policy dir: ${with_dbuspolicydir} + D-Bus session dir: ${with_dbussessionservicedir} + D-Bus system dir: ${with_dbussystemservicedir} + Bash completions dir: ${with_bashcompletiondir} + Zsh completions dir: ${with_zshcompletiondir} + Extra start script: ${RC_LOCAL_SCRIPT_PATH_START} + Extra stop script: ${RC_LOCAL_SCRIPT_PATH_STOP} + Wheel group: ${have_wheel_group} + Debug shell: ${SUSHELL} @ ${DEBUGTTY} + TTY GID: ${TTY_GID} + Maximum System UID: ${SYSTEM_UID_MAX} + Maximum System GID: ${SYSTEM_GID_MAX} + Certificate root: ${CERTIFICATEROOT} + + CFLAGS: ${OUR_CFLAGS} ${CFLAGS} + CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} + LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS} ]) diff --git a/src/login/.gitignore b/src/login/.gitignore index 39088ec252..3a8ba497c1 100644 --- a/src/login/.gitignore +++ b/src/login/.gitignore @@ -1,4 +1,5 @@ /logind-gperf.c +/logind.conf /org.freedesktop.login1.policy /71-seat.rules /73-seat-late.rules diff --git a/src/login/logind.c b/src/login/logind.c index 616346799a..a48e2fc61e 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -64,7 +64,7 @@ static void manager_reset_config(Manager *m) { m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ m->user_tasks_max = UINT64_C(12288); - m->kill_user_processes = true; + m->kill_user_processes = KILL_USER_PROCESSES; m->kill_only_users = strv_free(m->kill_only_users); m->kill_exclude_users = strv_free(m->kill_exclude_users); diff --git a/src/login/logind.conf b/src/login/logind.conf deleted file mode 100644 index 8316bb4d74..0000000000 --- a/src/login/logind.conf +++ /dev/null @@ -1,35 +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. -# -# 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. - -[Login] -#NAutoVTs=6 -#ReserveVT=6 -#KillUserProcesses=yes -#KillOnlyUsers= -#KillExcludeUsers=root -#InhibitDelayMaxSec=5 -#HandlePowerKey=poweroff -#HandleSuspendKey=suspend -#HandleHibernateKey=hibernate -#HandleLidSwitch=suspend -#HandleLidSwitchDocked=ignore -#PowerKeyIgnoreInhibited=no -#SuspendKeyIgnoreInhibited=no -#HibernateKeyIgnoreInhibited=no -#LidSwitchIgnoreInhibited=yes -#HoldoffTimeoutSec=30s -#IdleAction=ignore -#IdleActionSec=30min -#RuntimeDirectorySize=10% -#RemoveIPC=yes -#UserTasksMax=12288 diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in new file mode 100644 index 0000000000..3c96def45d --- /dev/null +++ b/src/login/logind.conf.in @@ -0,0 +1,35 @@ +# 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. +# +# 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. + +[Login] +#NAutoVTs=6 +#ReserveVT=6 +#KillUserProcesses=@KILL_USER_PROCESSES@ +#KillOnlyUsers= +#KillExcludeUsers=root +#InhibitDelayMaxSec=5 +#HandlePowerKey=poweroff +#HandleSuspendKey=suspend +#HandleHibernateKey=hibernate +#HandleLidSwitch=suspend +#HandleLidSwitchDocked=ignore +#PowerKeyIgnoreInhibited=no +#SuspendKeyIgnoreInhibited=no +#HibernateKeyIgnoreInhibited=no +#LidSwitchIgnoreInhibited=yes +#HoldoffTimeoutSec=30s +#IdleAction=ignore +#IdleActionSec=30min +#RuntimeDirectorySize=10% +#RemoveIPC=yes +#UserTasksMax=12288 -- cgit v1.2.3-54-g00ecf From 921f831d3e2e27a0da16d93ad3dc468263a63320 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 12 Apr 2016 23:52:41 -0400 Subject: logind: make KillOnlyUsers override KillUserProcesses Instead of KillOnlyUsers being a filter for KillUserProcesses, it can now be used to specify users to kill, independently of the KillUserProcesses setting. Having the settings orthogonal seems to make more sense. It also makes KillOnlyUsers symmetrical to KillExcludeUsers. --- man/logind.conf.xml | 25 +++++++++++++------------ src/login/logind-core.c | 9 +++------ 2 files changed, 16 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 6e587c3561..3217ece21a 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -124,7 +124,9 @@ corresponding to the session and all processes inside that scope will be terminated. If false, the scope is "abandonded", see systemd.scope5, - and processes are not killed. Defaults to yes. + and processes are not killed. Defaults to yes, + but see the options KillOnlyUsers= and + KillExcludeUsers= below. In addition to session processes, user process may run under the user manager unit user@.service. Depending on the linger @@ -147,17 +149,16 @@ KillOnlyUsers= KillExcludeUsers= - These settings take space-separated lists of usernames that - determine to which users the KillUserProcesses= setting - applies. A user name may be added to KillExcludeUsers= to - exclude the processes in the session scopes of that user from being killed even if - KillUserProcesses=yes is set. If - KillExcludeUsers= is not set, the root user - is excluded by default. KillExcludeUsers= may be set to an - empty value to override this default. If a user is not excluded, - KillOnlyUsers= is checked next. A list of user names may be - specified in KillOnlyUsers=, to only include those - users. Otherwise, all users are included. + These settings take space-separated lists of usernames that override + the KillUserProcesses= setting. A user name may be added to + KillExcludeUsers= to exclude the processes in the session scopes of + that user from being killed even if KillUserProcesses=yes is set. If + KillExcludeUsers= is not set, the root user is + excluded by default. KillExcludeUsers= may be set to an empty value + to override this default. If a user is not excluded, KillOnlyUsers= + is checked next. If this setting is specified, only the session scopes of those users + will be killed. Otherwise, users are subject to the + KillUserProcesses=yes setting. diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 73075274e0..cbf8d757fe 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -364,19 +364,16 @@ bool manager_shall_kill(Manager *m, const char *user) { assert(m); assert(user); - if (!m->kill_user_processes) - return false; - if (!m->kill_exclude_users && streq(user, "root")) return false; if (strv_contains(m->kill_exclude_users, user)) return false; - if (strv_isempty(m->kill_only_users)) - return true; + if (!strv_isempty(m->kill_only_users)) + return strv_contains(m->kill_only_users, user); - return strv_contains(m->kill_only_users, user); + return m->kill_user_processes; } static int vt_is_busy(unsigned int vtnr) { -- cgit v1.2.3-54-g00ecf From 152199f2d705effdcddacff63b3ca88671b1290f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 12 Apr 2016 22:52:28 -0400 Subject: logind: allow any user to request lingering We enable lingering for anyone who wants this. It is still disabled by default to avoid keeping long-running processes accidentally. Admins might want to customize this policy on multi-user sites. --- NEWS | 5 +++-- src/login/logind-dbus.c | 8 +++++--- src/login/org.freedesktop.login1.policy.in | 8 ++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index 7199a67201..3924264e6f 100644 --- a/NEWS +++ b/NEWS @@ -40,8 +40,9 @@ CHANGES WITH 230 in spe: After the user logs out of all sessions, user@.service will be terminated too, by default, unless the user has "lingering" enabled. To effectively allow users to run long-term tasks even if they are - logged out, lingering must be enabled for them. See loginctl(1) - for details. + logged out, lingering must be enabled for them. See loginctl(1) for + details. The default polkit policy was modified to allow users to + set lingering for themselves without authentication. Previous defaults can be restored at compile time by the --without-kill-user-processes option. diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 1d3133ee25..a281f99a34 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1077,11 +1077,11 @@ static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus 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; + int r, b, interactive; struct passwd *pw; const char *path; uint32_t uid; - int interactive; + bool self = false; assert(message); assert(m); @@ -1102,6 +1102,8 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; + self = true; + } else if (!uid_is_valid(uid)) return -EINVAL; @@ -1113,7 +1115,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, - "org.freedesktop.login1.set-user-linger", + self ? "org.freedesktop.login1.set-self-linger" : "org.freedesktop.login1.set-user-linger", NULL, interactive, UID_INVALID, diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in index 23326bb79f..1fa6441629 100644 --- a/src/login/org.freedesktop.login1.policy.in +++ b/src/login/org.freedesktop.login1.policy.in @@ -111,6 +111,14 @@ + + <_description>Allow non-logged-in user to run programs + <_message>Explicit request is required to run programs as a non-logged-in user. + + yes + + + <_description>Allow non-logged-in users to run programs <_message>Authentication is required to run programs as a non-logged-in user. -- cgit v1.2.3-54-g00ecf From 26e00f0e6a27d20c9d2da61cb46cb241fe0642a1 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 12 Apr 2016 23:35:45 -0400 Subject: loginctl: show linger status in user-status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zbyszek (1002) Since: Tue 2016-04-12 23:11:46 EDT; 23min ago State: active Sessions: *3 Linger: yes Unit: user-1002.slice ├─user@1002.service │ └─init.scope │ ├─38 /usr/lib/systemd/systemd --user │ └─39 (sd-pam) └─session-3.scope ├─ 31 login -- zbyszek ├─ 44 -bash ├─15076 loginctl user-status zbyszek └─15077 less --- src/login/loginctl.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 01f6fa5db0..8b23135edd 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -293,6 +293,7 @@ typedef struct SessionStatusInfo { typedef struct UserStatusInfo { uid_t uid; + bool linger; char *name; struct dual_timestamp timestamp; char *state; @@ -551,6 +552,7 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) static const struct bus_properties_map map[] = { { "Name", "s", NULL, offsetof(UserStatusInfo, name) }, + { "Linger", "b", NULL, offsetof(UserStatusInfo, linger) }, { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) }, { "State", "s", NULL, offsetof(UserStatusInfo, state) }, { "UID", "u", NULL, offsetof(UserStatusInfo, uid) }, @@ -595,16 +597,16 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) char **l; printf("\tSessions:"); - STRV_FOREACH(l, i.sessions) { - if (streq_ptr(*l, i.display)) - printf(" *%s", *l); - else - printf(" %s", *l); - } + STRV_FOREACH(l, i.sessions) + printf(" %s%s", + streq_ptr(*l, i.display) ? "*" : "", + *l); printf("\n"); } + printf("\t Linger: %s\n", yes_no(i.linger)); + if (i.slice) { printf("\t Unit: %s\n", i.slice); show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0); -- cgit v1.2.3-54-g00ecf From 42fbdf45864b46f3eb62a3738b81e687685eb9bd Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 12 Apr 2016 23:36:37 -0400 Subject: shared/logs-show: fix memleak in add_matches_for_unit --- src/shared/logs-show.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index e2d2931c51..38a55525c0 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -1073,7 +1073,7 @@ int add_matches_for_unit(sd_journal *j, const char *unit) { ); if (r == 0 && endswith(unit, ".slice")) { - char *m5 = strappend("_SYSTEMD_SLICE=", unit); + const char *m5 = strjoina("_SYSTEMD_SLICE=", unit); /* Show all messages belonging to a slice */ (void)( -- cgit v1.2.3-54-g00ecf From 48062f072c7ba679667a309a76f71d595f0287e7 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Thu, 21 Apr 2016 12:13:08 +0200 Subject: build: fix test-nss.c build failure with --disable-{resolved,myhostname} (#3081) When building without resolved and/or myhostname, test-nss.c failed to build with src/test/test-nss.c: In function 'main': src/test/test-nss.c:417:32: error: 'MODULE1' undeclared (first use in this function) NULSTR_FOREACH(module, MODULE1 MODULE2 MODULE3 MODULE4) { ^ Ensure that all MODULEx are always defined, and empty if the module is not available (so that it will be a no-op in the string concatenation). --- src/test/test-nss.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/test/test-nss.c b/src/test/test-nss.c index 9c13288d2e..55af592287 100644 --- a/src/test/test-nss.c +++ b/src/test/test-nss.c @@ -381,12 +381,18 @@ static void test_byaddr(void *handle, #ifdef HAVE_MYHOSTNAME # define MODULE1 "myhostname\0" +#else +# define MODULE1 #endif #ifdef HAVE_RESOLVED # define MODULE2 "resolve\0" +#else +# define MODULE2 #endif #ifdef HAVE_MACHINED # define MODULE3 "mymachines\0" +#else +# define MODULE3 #endif #define MODULE4 "dns\0" -- cgit v1.2.3-54-g00ecf From 0c241a378d9fdb0a1f462829e1e2ba9e8b036c06 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 21 Apr 2016 19:38:07 +0530 Subject: networkd: When link gets dirty mark manager dirty too (#3080) If we not marking manager dirty when link is dirty then the state file is not updated. This is a side effect of issue 2850 setting CriticalConnection=yes timesyncd NTP servers given by DHCP server are ignored. --- src/network/networkd-link.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 0fb3aa6c43..5cdf123652 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -299,7 +299,6 @@ void link_update_operstate(Link *link) { link->operstate = operstate; link_send_changed(link, "OperationalState", NULL); link_dirty(link); - manager_dirty(link->manager); } } @@ -3228,14 +3227,17 @@ void link_dirty(Link *link) { assert(link); + /* mark manager dirty as link is dirty */ + manager_dirty(link->manager); + r = set_ensure_allocated(&link->manager->dirty_links, NULL); if (r < 0) /* allocation errors are ignored */ return; r = set_put(link->manager->dirty_links, link); - if (r < 0) - /* allocation errors are ignored */ + if (r <= 0) + /* don't take another ref if the link was already dirty */ return; link_ref(link); -- cgit v1.2.3-54-g00ecf From 7d782f265dda805f9e6a533410e17a94b79012e0 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 21 Apr 2016 00:57:50 -0400 Subject: shared/install: nicer error message is symlinking chokes on an existing file Fixes #1892. Previously: Failed to enable unit: Invalid argument Now: Failed to enable unit, file /etc/systemd/system/ssh.service already exists. It would be nice to include the unit name in the message too. I looked into this, but it would require major surgery on the whole installation logic, because we first create a list of things to change, and then try to apply them in a loop. To transfer the knowledge which unit was the source of each change, the data structures would have to be extended to carry the unit name over into the second loop. So I'm skipping this for now. --- src/shared/install.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 71012eafb4..7a98c2d298 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -370,8 +370,14 @@ static int create_symlink( } r = readlink_malloc(new_path, &dest); - if (r < 0) + if (r < 0) { + /* translate EINVAL (non-symlink exists) to EEXIST */ + if (r == -EINVAL) + r = -EEXIST; + + unit_file_changes_add(changes, n_changes, r, new_path, NULL); return r; + } if (path_equal(dest, old_path)) return 0; @@ -382,8 +388,10 @@ static int create_symlink( } r = symlink_atomic(old_path, new_path); - if (r < 0) + if (r < 0) { + unit_file_changes_add(changes, n_changes, r, new_path, NULL); return r; + } 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); -- cgit v1.2.3-54-g00ecf From 9a7c402b2a30dbe759f839b8ad88f57f9e74a105 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 21 Apr 2016 09:23:18 -0400 Subject: core/dbus-manager: drop unused param from installation functions --- src/core/dbus-manager.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index d48b0ca69d..0c86791fe3 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1666,7 +1666,6 @@ static int install_error( static int method_enable_unit_files_generic( sd_bus_message *message, Manager *m, - const char *verb, int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes), bool carries_install_info, sd_bus_error *error) { @@ -1701,15 +1700,15 @@ static int method_enable_unit_files_generic( } 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); + return method_enable_unit_files_generic(message, userdata, unit_file_enable, 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); + return method_enable_unit_files_generic(message, userdata, unit_file_reenable, true, 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); + return method_enable_unit_files_generic(message, userdata, 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) { @@ -1717,11 +1716,11 @@ static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, cons } 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); + return method_enable_unit_files_generic(message, userdata, unit_file_preset_without_mode, true, 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); + return method_enable_unit_files_generic(message, userdata, unit_file_mask, false, error); } static int method_preset_unit_files_with_mode(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -1769,7 +1768,6 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use static int method_disable_unit_files_generic( sd_bus_message *message, Manager *m, - const char *verb, int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), sd_bus_error *error) { @@ -1803,11 +1801,11 @@ static int method_disable_unit_files_generic( } 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); + return method_disable_unit_files_generic(message, userdata, unit_file_disable, 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); + return method_disable_unit_files_generic(message, userdata, unit_file_unmask, error); } static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { -- cgit v1.2.3-54-g00ecf From 12bf0ae4c6c338603bd11bac9002d73339aedae4 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 21 Apr 2016 09:53:48 -0400 Subject: shared/install: rewrite unit_file_changes_add() path_kill_slashes was applied to the wrong arg... --- src/shared/install.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 7a98c2d298..63cb76f21b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -222,8 +222,8 @@ int unit_file_changes_add( const char *path, const char *source) { + _cleanup_free_ char *p = NULL, *s = NULL; UnitFileChange *c; - unsigned i; assert(path); assert(!changes == !n_changes); @@ -234,29 +234,22 @@ int unit_file_changes_add( 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); + p = strdup(path); + if (source) + s = strdup(source); - if (source) { - c[i].source = strdup(source); - if (!c[i].source) { - free(c[i].path); - return -ENOMEM; - } + if (!p || (source && !s)) + return -ENOMEM; - path_kill_slashes(c[i].path); - } else - c[i].source = NULL; + path_kill_slashes(p); + if (s) + path_kill_slashes(s); - *n_changes = i+1; + c[*n_changes] = (UnitFileChange) { type, p, s }; + p = s = NULL; + (*n_changes) ++; return 0; } @@ -265,9 +258,6 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { assert(changes || n_changes == 0); - if (!changes) - return; - for (i = 0; i < n_changes; i++) { free(changes[i].path); free(changes[i].source); @@ -529,8 +519,8 @@ static int remove_marked_symlinks_fd( unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); - /* Now, remember the full path (but with the root prefix removed) of the symlink we just - * removed, and remove any symlinks to it, too */ + /* Now, remember the full path (but with the root prefix removed) of + * the symlink we just removed, and remove any symlinks to it, too. */ rp = skip_root(lp, p); q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p); -- cgit v1.2.3-54-g00ecf From 39207373dd638e548019ddb49929f15795b8b404 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 21 Apr 2016 20:04:21 -0400 Subject: systemctl,pid1: do not warn about missing install info with "preset" When "preset" was executed for a unit without install info, we'd warn similarly as for "enable" and "disable". But "preset" is usually called for all units, because the preset files are provided by the distribution, and the units are under control of individual programs, and it's reasonable to call "preset" for all units rather then try to do it only for the ones that can be installed. We also don't warn about missing info for "preset-all". Thus it seems reasonable to silently ignore units w/o install info when presetting. (In addition, when more than one unit was specified, we'd issue the warning only if none of them had install info. But this is probably something to fix for enable/disable too.) --- man/systemctl.xml | 26 +++++++++++++------------- src/systemctl/systemctl.c | 7 ++++--- 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/man/systemctl.xml b/man/systemctl.xml index 5f624243f7..991e9bafaf 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1084,22 +1084,22 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service preset NAME... - Reset one or more unit files, as specified on the - command line, to the defaults configured in the preset - policy files. This has the same effect as - disable or enable, - depending how the unit is listed in the preset files. + Reset the enable/disable status one or more unit files, as specified on + the command line, to the defaults configured in the preset policy files. This + has the same effect as disable or + enable, depending how the unit is listed in the preset + files. - Use to control - whether units shall be enabled and disabled, or only - enabled, or only disabled. + Use to control whether units shall be + enabled and disabled, or only enabled, or only disabled. + + If the unit carries no install information, it will be silently ignored + by this command. - For more information on the preset policy format, - see + For more information on the preset policy format, see systemd.preset5. - For more information on the concept of presets, please - consult the Preset + For more information on the concept of presets, please consult the + Preset document. diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 059e985463..04205411dd 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5390,6 +5390,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { UnitFileChange *changes = NULL; unsigned n_changes = 0; int carries_install_info = -1; + bool ignore_carries_install_info = false; int r; if (!argv[1]) @@ -5420,7 +5421,6 @@ static int enable_unit(int argc, char *argv[], void *userdata) { r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); else if (streq(verb, "preset")) { r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes); - carries_install_info = r; } else if (streq(verb, "mask")) r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); else if (streq(verb, "unmask")) @@ -5437,7 +5437,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - int expect_carries_install_info = false; + bool expect_carries_install_info = false; bool send_runtime = true, send_force = true, send_preset_mode = false; const char *method; sd_bus *bus; @@ -5468,6 +5468,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { method = "PresetUnitFiles"; expect_carries_install_info = true; + ignore_carries_install_info = true; } else if (streq(verb, "mask")) method = "MaskUnitFiles"; else if (streq(verb, "unmask")) { @@ -5532,7 +5533,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { r = 0; } - if (carries_install_info == 0) + if (carries_install_info == 0 && !ignore_carries_install_info) log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n" "settings in the [Install] section, and DefaultInstance for template units).\n" "This means they are not meant to be enabled using systemctl.\n" -- cgit v1.2.3-54-g00ecf From 29380daff549b117873f4543a649569be84bd950 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 21 Apr 2016 21:11:15 -0400 Subject: shared/install: always overwrite symlinks in .wants and .requires Before: $ systemctl preset getty@.service Failed to preset unit, file /etc/systemd/system/getty.target.wants/getty@tty1.service already exists and is a symlink to ../../../../usr/lib/systemd/system/getty@.service. After: $ systemctl preset getty@.service Created symlink /etc/systemd/system/getty.target.wants/getty@tty1.service, pointing to /usr/lib/systemd/system/getty@.service. We don't really care where the symlink points to. For example, it might point to /usr/lib or /etc, and systemd will always load the unit from /etc in preference to /usr/lib. In fact, if we make a symlink like /etc/systemd/system/multi-user.target.wants/b.service -> ../a.service, pid1 will still start b.service. The name of the symlink is the only thing that matters, as far as systemd is concerned. For humans it's confusing when the symlinks points to anything else than the actual unit file. At the very least, the symlink is supposed to point to a file with the same name in some other directory. Since we don't care where the symlink points, we can always replace an existing symlink. Another option I considered would be to simply leave an existing symlink in place. That would work too, but replacing the symlink with the expected value seems more intuitive. Of course those considerations only apply to .wants and .requires. Symlinks created with "link" and "alias" are a separate matter. Fixes #3056. --- src/shared/install.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 63cb76f21b..e97721b79e 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1390,7 +1390,6 @@ static int install_info_symlink_wants( const char *config_path, char **list, const char *suffix, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1438,7 +1437,7 @@ static int install_info_symlink_wants( rp = skip_root(paths, i->path); - q = create_symlink(rp ?: i->path, path, force, changes, n_changes); + q = create_symlink(rp ?: i->path, path, true, changes, n_changes); if (r == 0) r = q; } @@ -1497,11 +1496,11 @@ static int install_info_apply( r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes); - q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", force, changes, n_changes); + q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes); if (r == 0) r = q; - q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", force, changes, n_changes); + q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes); if (r == 0) r = q; -- cgit v1.2.3-54-g00ecf From ccddd104fc95e0e769142af6e1fe1edec5be70a6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 21 Apr 2016 22:57:06 -0400 Subject: tree-wide: use mdash instead of a two minuses --- NEWS | 50 ++++++++++++++++---------------- TODO | 2 +- man/daemon.xml | 2 +- man/sd_event_source_set_priority.xml | 2 +- man/sd_journal_get_data.xml | 2 +- man/systemd-ask-password.xml | 2 +- man/systemd-journal-gatewayd.service.xml | 2 +- man/systemd-nspawn.xml | 2 +- man/systemd.special.xml | 2 +- src/core/ima-setup.c | 2 +- src/core/ima-setup.h | 2 +- src/core/unit.c | 2 +- src/journal/journald-server.c | 2 +- src/libsystemd/sd-device/sd-device.c | 6 ++-- src/libsystemd/sd-resolve/test-resolve.c | 2 +- src/network/test-network-tables.c | 2 +- src/nspawn/nspawn.c | 2 +- src/resolve/RFCs | 2 +- src/resolve/resolved-link.c | 2 +- src/udev/udev-builtin-net_id.c | 28 +++++++++--------- 20 files changed, 59 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index f697599a8f..16ea7b7290 100644 --- a/NEWS +++ b/NEWS @@ -311,7 +311,7 @@ CHANGES WITH 229: Andersen, Tom Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Vito Caputo, WaLyong Cho, Yu Watanabe, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2016-02-11 + — Berlin, 2016-02-11 CHANGES WITH 228: @@ -512,7 +512,7 @@ CHANGES WITH 228: Tom Gundersen, Torstein Husebø, Vito Caputo, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-11-18 + — Berlin, 2015-11-18 CHANGES WITH 227: @@ -716,7 +716,7 @@ CHANGES WITH 227: Andersen, Tom Gundersen, Tom Lyon, Viktar Vauchkevich, Zbigniew Jędrzejewski-Szmek, Марко М. Костић - -- Berlin, 2015-10-07 + — Berlin, 2015-10-07 CHANGES WITH 226: @@ -836,7 +836,7 @@ CHANGES WITH 226: Hack, Susant Sahani, Sylvain Pasche, Thomas Hindoe Paaboel Andersen, Tom Gundersen, Torstein Husebø - -- Berlin, 2015-09-08 + — Berlin, 2015-09-08 CHANGES WITH 225: @@ -909,7 +909,7 @@ CHANGES WITH 225: Paaboel Andersen, Thomas Meyer, Tom Gundersen, Vincent Batts, WaLyong Cho, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-08-27 + — Berlin, 2015-08-27 CHANGES WITH 224: @@ -924,7 +924,7 @@ CHANGES WITH 224: Herrmann, Herman Fries, Johannes Nixdorf, Kay Sievers, Lennart Poettering, Peter Hutterer, Susant Sahani, Tom Gundersen - -- Berlin, 2015-07-31 + — Berlin, 2015-07-31 CHANGES WITH 223: @@ -989,7 +989,7 @@ CHANGES WITH 223: Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Vito Caputo, Vivenzio Pagliari, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-07-29 + — Berlin, 2015-07-29 CHANGES WITH 222: @@ -1029,7 +1029,7 @@ CHANGES WITH 222: Susant Sahani, Thomas Hindoe Paaboel Andersen, Tom Gundersen, Torstein Husebø, Vedran Miletić, WaLyong Cho, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-07-07 + — Berlin, 2015-07-07 CHANGES WITH 221: @@ -1107,7 +1107,7 @@ CHANGES WITH 221: Husebø, Umut Tezduyar Lindskog, Viktar Vauchkevich, Werner Fink, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-06-19 + — Berlin, 2015-06-19 CHANGES WITH 220: @@ -1336,7 +1336,7 @@ CHANGES WITH 220: Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Will Woods, Zachary Cook, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-05-22 + — Berlin, 2015-05-22 CHANGES WITH 219: @@ -1660,7 +1660,7 @@ CHANGES WITH 219: Lindskog, Veres Lajos, Vincent Batts, WaLyong Cho, Wieland Hoffmann, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-02-16 + — Berlin, 2015-02-16 CHANGES WITH 218: @@ -1862,7 +1862,7 @@ CHANGES WITH 218: Torstein Husebø, Umut Tezduyar Lindskog, Vicente Olivert Riera, WaLyong Cho, Wesley Dawson, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-12-10 + — Berlin, 2014-12-10 CHANGES WITH 217: @@ -2074,7 +2074,7 @@ CHANGES WITH 217: Husebø, Umut Tezduyar Lindskog, WaLyong Cho, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-10-28 + — Berlin, 2014-10-28 CHANGES WITH 216: @@ -2276,7 +2276,7 @@ CHANGES WITH 216: Tobias Geerinckx-Rice, Tomasz Torcz, Tom Gundersen, Umut Tezduyar Lindskog, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-08-19 + — Berlin, 2014-08-19 CHANGES WITH 215: @@ -2510,7 +2510,7 @@ CHANGES WITH 215: Paaboel Andersen, Tom Gundersen, Tom Hirst, Umut Tezduyar Lindskog, Uoti Urpala, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-07-03 + — Berlin, 2014-07-03 CHANGES WITH 214: @@ -2704,7 +2704,7 @@ CHANGES WITH 214: Andersen, Tom Gundersen, Umut Tezduyar Lindskog, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-06-11 + — Berlin, 2014-06-11 CHANGES WITH 213: @@ -2836,7 +2836,7 @@ CHANGES WITH 213: Lindskog, WaLyong Cho, Will Woods, Zbigniew Jędrzejewski-Szmek - -- Beijing, 2014-05-28 + — Beijing, 2014-05-28 CHANGES WITH 212: @@ -2985,7 +2985,7 @@ CHANGES WITH 212: Umut Tezduyar Lindskog, Wieland Hoffmann, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-03-25 + — Berlin, 2014-03-25 CHANGES WITH 211: @@ -3109,7 +3109,7 @@ CHANGES WITH 211: Gundersen, Umut Tezduyar Lindskog, Uoti Urpala, Zachary Cook, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-03-12 + — Berlin, 2014-03-12 CHANGES WITH 210: @@ -3214,7 +3214,7 @@ CHANGES WITH 210: Paaboel Andersen, Tom Gundersen, Umut Tezduyar Lindskog, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-02-24 + — Berlin, 2014-02-24 CHANGES WITH 209: @@ -3670,7 +3670,7 @@ CHANGES WITH 209: Pavlín, Vincent Batts, WaLyong Cho, William Giokas, Yang Zhiyong, Yin Kangkai, Yuxuan Shui, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2014-02-20 + — Berlin, 2014-02-20 CHANGES WITH 208: @@ -3757,7 +3757,7 @@ CHANGES WITH 208: Michael Scherer, Michał Górny, Mike Gilbert, Patrick McCarty, Sebastian Ott, Tom Gundersen, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2013-10-02 + — Berlin, 2013-10-02 CHANGES WITH 207: @@ -3857,7 +3857,7 @@ CHANGES WITH 207: Paaboel Andersen, Tom Gundersen, Umut Tezduyar, WANG Chao, William Giokas, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2013-09-13 + — Berlin, 2013-09-13 CHANGES WITH 206: @@ -3956,14 +3956,14 @@ CHANGES WITH 206: Thomas H.P. Andersen, Tom Gundersen, Tomasz Torcz, William Giokas, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2013-07-23 + — Berlin, 2013-07-23 CHANGES WITH 205: * Two new unit types have been introduced: Scope units are very similar to service units, however, are - created out of pre-existing processes -- instead of PID 1 + created out of pre-existing processes — instead of PID 1 forking off the processes. By using scope units it is possible for system services and applications to group their own child processes (worker processes) in a powerful way diff --git a/TODO b/TODO index 4d8161cadf..c94729a027 100644 --- a/TODO +++ b/TODO @@ -384,7 +384,7 @@ Features: * systemd-inhibit: make taking delay locks useful: support sending SIGINT or SIGTERM on PrepareForSleep() -* remove any syslog support from log.c -- we probably cannot do this before split-off udev is gone for good +* remove any syslog support from log.c — we probably cannot do this before split-off udev is gone for good * shutdown logging: store to EFI var, and store to USB stick? diff --git a/man/daemon.xml b/man/daemon.xml index b6125cb5c7..fed1ca1f49 100644 --- a/man/daemon.xml +++ b/man/daemon.xml @@ -234,7 +234,7 @@ bus-activatable by supplying a D-Bus service activation configuration file. This has multiple advantages: your daemon may be started lazily on-demand; it may be started in parallel - to other daemons requiring it -- which maximizes + to other daemons requiring it — which maximizes parallelization and boot-up speed; your daemon can be restarted on failure without losing any bus requests, as the bus queues requests for activatable services. See below for diff --git a/man/sd_event_source_set_priority.xml b/man/sd_event_source_set_priority.xml index 9234f4233e..8c9b39fe5e 100644 --- a/man/sd_event_source_set_priority.xml +++ b/man/sd_event_source_set_priority.xml @@ -97,7 +97,7 @@ SD_EVENT_PRIORITY_IDLE (100) may be used to indicate event sources that shall be dispatched early, normally or late. It is recommended to specify priorities based on these - definitions, and relative to them -- however, the full 64bit + definitions, and relative to them — however, the full 64bit signed integer range is available for ordering event sources. diff --git a/man/sd_journal_get_data.xml b/man/sd_journal_get_data.xml index 1f25d068d7..908ee7db16 100644 --- a/man/sd_journal_get_data.xml +++ b/man/sd_journal_get_data.xml @@ -148,7 +148,7 @@ sd_journal_enumerate_unique(). This threshold is a hint only: it indicates that the client program is interested only in the initial parts of the data fields, up to the threshold - in size -- but the library might still return larger data objects. + in size — but the library might still return larger data objects. That means applications should not rely exclusively on this setting to limit the size of the data fields returned, but need to apply a explicit size limit on the returned data as well. This diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml index e84a15c554..2b6fb5a82f 100644 --- a/man/systemd-ask-password.xml +++ b/man/systemd-ask-password.xml @@ -67,7 +67,7 @@ processes. The purpose of this tool is to query system-wide passwords - -- that is passwords not attached to a specific user account. + — that is passwords not attached to a specific user account. Examples include: unlocking encrypted hard disks when they are plugged in or at boot, entering an SSL certificate passphrase for web and VPN servers. diff --git a/man/systemd-journal-gatewayd.service.xml b/man/systemd-journal-gatewayd.service.xml index e32ac26850..9ed85c3950 100644 --- a/man/systemd-journal-gatewayd.service.xml +++ b/man/systemd-journal-gatewayd.service.xml @@ -262,7 +262,7 @@ boot Limit events to the current boot of the system - (like journalctl --this--boot). + (like journalctl --this-boot). diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 6732b9d7be..a0376ed3e0 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -502,7 +502,7 @@ host interface name and container interface name. The latter may be omitted in which case the container and host sides will be assigned the same name. This switch is independent of - , and -- in contrast -- may be + , and — in contrast — may be used multiple times, and allows configuration of the network interface names. Note that has no effect on interfaces created with diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 80c15b700d..14998b9647 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -742,7 +742,7 @@ defined what that is supposed to mean, with one exception: at shutdown, a unit that is ordered after network.target will be stopped before - the network -- to whatever level it might be set up then -- + the network — to whatever level it might be set up then — is shut down. It is hence useful when writing service files that require network access on shutdown, which should order themselves after this target, but not pull it in. Also see diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c index ff7558d500..d1b0ce76ef 100644 --- a/src/core/ima-setup.c +++ b/src/core/ima-setup.c @@ -3,7 +3,7 @@ Copyright 2010 Lennart Poettering Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy - TORSEC group -- http://security.polito.it + TORSEC group — http://security.polito.it 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 diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h index 3bad74b246..472b58cb00 100644 --- a/src/core/ima-setup.h +++ b/src/core/ima-setup.h @@ -5,7 +5,7 @@ Copyright 2010 Lennart Poettering Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy - TORSEC group -- http://security.polito.it + TORSEC group — http://security.polito.it 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 diff --git a/src/core/unit.c b/src/core/unit.c index c60ae2be9d..1f57293a0b 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3600,7 +3600,7 @@ int unit_kill_context( * cases. It doesn't work at all in * containers, and outside of containers it * can be confused easily by left-over - * directories in the cgroup -- which however + * directories in the cgroup — which however * should not exist in non-delegated units. On * the unified hierarchy that's different, * there we get proper events. Hence rely on diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index b1d1bf9e14..8089bb5883 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1660,7 +1660,7 @@ static int server_connect_notify(Server *s) { it. Specifically: given that PID 1 might block on dbus-daemon during IPC, and dbus-daemon is logging to us, and might hence block on us, we might end up in a deadlock - if we block on sending PID 1 notification messages -- by + if we block on sending PID 1 notification messages — by generating a full blocking circle. To avoid this, let's create a non-blocking socket, and connect it to the notification socket, and then wait for POLLOUT before we diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index e787cb69d3..b1c3d5f228 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -1212,19 +1212,19 @@ int device_get_id_filename(sd_device *device, const char **ret) { if (major(devnum) > 0) { assert(subsystem); - /* use dev_t -- b259:131072, c254:0 */ + /* 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 */ + /* use netdev ifindex — n3 */ r = asprintf(&id, "n%u", ifindex); if (r < 0) return -ENOMEM; } else { - /* use $subsys:$sysname -- pci:0000:00:1f.2 + /* use $subsys:$sysname — pci:0000:00:1f.2 * sysname() has '!' translated, get it from devpath */ const char *sysname; diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c index 33ef6fc0f7..1be1a7f8a7 100644 --- a/src/libsystemd/sd-resolve/test-resolve.c +++ b/src/libsystemd/sd-resolve/test-resolve.c @@ -63,7 +63,7 @@ static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, c return 0; } - printf("Host: %s -- Serv: %s\n", strna(host), strna(serv)); + printf("Host: %s — Serv: %s\n", strna(host), strna(serv)); return 0; } diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c index ecbbe6c3c9..adbe09a5e1 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -9,7 +9,7 @@ int main(int argc, char **argv) { test_table(bond_mode, NETDEV_BOND_MODE); - /* test_table(link_state, LINK_STATE); -- not a reversible mapping */ + /* test_table(link_state, LINK_STATE); — not a reversible mapping */ test_table(link_operstate, LINK_OPERSTATE); test_table(address_family_boolean, ADDRESS_FAMILY_BOOLEAN); test_table(netdev_kind, NETDEV_KIND); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index a07f148ef6..44dce471e7 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1481,7 +1481,7 @@ static int setup_journal(const char *directory) { } if (arg_link_journal == LINK_HOST) { - /* don't create parents here -- if the host doesn't have + /* don't create parents here — if the host doesn't have * permanent journal set up, don't force it here */ if (mkdir(p, 0755) < 0 && errno != EEXIST) { diff --git a/src/resolve/RFCs b/src/resolve/RFCs index 22004a00cd..09c85f9518 100644 --- a/src/resolve/RFCs +++ b/src/resolve/RFCs @@ -8,7 +8,7 @@ D = Comprehensively Implemented, by a dependency of resolved Y https://tools.ietf.org/html/rfc1034 → DOMAIN NAMES - CONCEPTS AND FACILITIES Y https://tools.ietf.org/html/rfc1035 → DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION ? https://tools.ietf.org/html/rfc1101 → DNS Encoding of Network Names and Other Types -Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts -- Application and Support +Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts — Application and Support ~ https://tools.ietf.org/html/rfc1464 → Using the Domain Name System To Store Arbitrary String Attributes Y https://tools.ietf.org/html/rfc1536 → Common DNS Implementation Errors and Suggested Fixes Y https://tools.ietf.org/html/rfc1876 → A Means for Expressing Location Information in the Domain Name System diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index c5863b3aa2..b0dc65036d 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -468,7 +468,7 @@ static void link_read_settings(Link *l) { } if (r > 0) { - /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */ + /* If this link used to be managed, but is now unmanaged, flush all our settings — but only once. */ if (l->is_managed) link_flush_settings(l); diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 8b1bcefe2d..a7be2a4eed 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -27,21 +27,21 @@ * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames * * Two character prefixes based on the type of interface: - * en -- Ethernet - * sl -- serial line IP (slip) - * wl -- wlan - * ww -- wwan + * en — Ethernet + * sl — serial line IP (slip) + * wl — wlan + * ww — wwan * * Type of names: - * b -- BCMA bus core number - * c -- CCW bus group name, without leading zeros [s390] - * o[d] -- on-board device index number - * s[f][d] -- hotplug slot index number - * x -- MAC address + * b — BCMA bus core number + * c — CCW bus group name, without leading zeros [s390] + * o[d] — on-board device index number + * s[f][d] — hotplug slot index number + * x — MAC address * [P]ps[f][d] - * -- PCI geographical location + * — PCI geographical location * [P]ps[f][u][..][c][i] - * -- USB port number chain + * — USB port number chain * * All multi-function PCI devices will carry the [f] number in the * device name, including the function 0 device. @@ -140,9 +140,9 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { const char *attr; int idx; - /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ + /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */ attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index"); - /* SMBIOS type 41 -- Onboard Devices Extended Information */ + /* SMBIOS type 41 — Onboard Devices Extended Information */ if (!attr) attr = udev_device_get_sysattr_value(names->pcidev, "index"); if (!attr) @@ -230,7 +230,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { if (l == 0) names->pci_path[0] = '\0'; - /* ACPI _SUN -- slot user number */ + /* ACPI _SUN — slot user number */ pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); if (!pci) { err = -ENOENT; -- cgit v1.2.3-54-g00ecf From 4f25723c149ba87bb88cb069f88196b70c8012af Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Fri, 22 Apr 2016 14:18:05 +0200 Subject: treewide: fix typos (#3092) --- man/logind.conf.xml | 2 +- man/systemd.network.xml | 2 +- src/shared/install.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 3217ece21a..6ba35414be 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -122,7 +122,7 @@ Takes a boolean argument. Configures whether the processes of a user should be killed when the user logs out. If true, the scope unit corresponding to the session and all processes inside that scope will be - terminated. If false, the scope is "abandonded", see + terminated. If false, the scope is "abandoned", see systemd.scope5, and processes are not killed. Defaults to yes, but see the options KillOnlyUsers= and diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 8ae384185d..9bf1b198ad 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -217,7 +217,7 @@ Note that an interface without any static IPv6 addresses configured, and neither DHCPv6 nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be automatically disabled for that interface by writing "1" to - /proc/sys/net/ipv6/conf/ifname/disable_ipv6. + /proc/sys/net/ipv6/conf/ifname/disable_ipv6. diff --git a/src/shared/install.c b/src/shared/install.c index e97721b79e..b74ff6de22 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1861,7 +1861,7 @@ int unit_file_revert( * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in * "config", but not in "transient" or "control" or even "generated"). * - * We remove all that in both the runtime and the persistant directories, if that applies. + * We remove all that in both the runtime and the persistent directories, if that applies. */ r = lookup_paths_init(&paths, scope, 0, root_dir); -- cgit v1.2.3-54-g00ecf From 2b45d88163b29f04bf784385f4a490b2cf206861 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 15:22:46 +0200 Subject: shared: fix minor memory leak in log display code --- src/shared/logs-show.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 38a55525c0..15c818ccf1 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -1040,8 +1040,8 @@ static int show_journal(FILE *f, } int add_matches_for_unit(sd_journal *j, const char *unit) { + const char *m1, *m2, *m3, *m4; int r; - char *m1, *m2, *m3, *m4; assert(j); assert(unit); @@ -1073,7 +1073,9 @@ int add_matches_for_unit(sd_journal *j, const char *unit) { ); if (r == 0 && endswith(unit, ".slice")) { - const char *m5 = strjoina("_SYSTEMD_SLICE=", unit); + const char *m5; + + m5 = strjoina("_SYSTEMD_SLICE=", unit); /* Show all messages belonging to a slice */ (void)( @@ -1123,7 +1125,9 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) { ); if (r == 0 && endswith(unit, ".slice")) { - char *m5 = strappend("_SYSTEMD_SLICE=", unit); + const char *m5; + + m5 = strjoina("_SYSTEMD_SLICE=", unit); /* Show all messages belonging to a slice */ (void)( -- cgit v1.2.3-54-g00ecf From 291d565a04263452c03beaf537773ade4f0b1617 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 15:28:28 +0200 Subject: core,systemctl: add bus API to retrieve processes of a unit This adds a new GetProcesses() bus call to the Unit object which returns an array consisting of all PIDs, their process names, as well as their full cgroup paths. This is then used by "systemctl status" to show the per-unit process tree. This has the benefit that the client-side no longer needs to access the cgroupfs directly to show the process tree of a unit. Instead, it now uses this new API, which means it also works if -H or -M are used correctly, as the information from the specific host is used, and not the one from the local system. Fixes: #2945 --- Makefile.am | 2 + src/basic/process-util.c | 12 + src/basic/process-util.h | 2 + src/core/busname.c | 10 + src/core/dbus-manager.c | 25 ++ src/core/dbus-unit.c | 143 +++++++++++ src/core/dbus-unit.h | 1 + src/core/mount.c | 10 + src/core/org.freedesktop.systemd1.conf | 4 + src/core/service.c | 19 ++ src/core/socket.c | 10 + src/core/swap.c | 10 + src/core/unit.c | 18 ++ src/core/unit.h | 9 + src/shared/bus-unit-util.c | 446 +++++++++++++++++++++++++++++++++ src/shared/bus-unit-util.h | 27 ++ src/shared/cgroup-show.c | 70 ++++-- src/systemctl/systemctl.c | 35 +-- 18 files changed, 819 insertions(+), 34 deletions(-) create mode 100644 src/shared/bus-unit-util.c create mode 100644 src/shared/bus-unit-util.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index f2ef83b0c7..b0118fd9a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1037,6 +1037,8 @@ libshared_la_SOURCES = \ src/shared/machine-pool.h \ src/shared/resolve-util.c \ src/shared/resolve-util.h \ + src/shared/bus-unit-util.c \ + src/shared/bus-unit-util.h \ src/shared/tests.h \ src/shared/tests.c diff --git a/src/basic/process-util.c b/src/basic/process-util.c index ae3f6109ad..f2cea01979 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -731,6 +731,18 @@ void valgrind_summary_hack(void) { #endif } +int pid_compare_func(const void *a, const void *b) { + const pid_t *p = a, *q = b; + + /* Suitable for usage in qsort() */ + + if (*p < *q) + return -1; + if (*p > *q) + return 1; + return 0; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index f5d193e762..ffd4bcb0ff 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -101,3 +101,5 @@ int sched_policy_from_string(const char *s); #define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) void valgrind_summary_hack(void); + +int pid_compare_func(const void *a, const void *b); diff --git a/src/core/busname.c b/src/core/busname.c index bbe61af4f0..f4f433340c 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -999,6 +999,14 @@ static bool busname_supported(void) { return supported; } +static int busname_control_pid(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + + return n->control_pid; +} + static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { [BUSNAME_SUCCESS] = "success", [BUSNAME_FAILURE_RESOURCES] = "resources", @@ -1052,6 +1060,8 @@ const UnitVTable busname_vtable = { .supported = busname_supported, + .control_pid = busname_control_pid, + .bus_vtable = bus_busname_vtable, .status_message_formats = { diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 0c86791fe3..d2eb388f7c 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -642,6 +642,30 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s return bus_unit_method_set_properties(message, u, error); } +static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = bus_unit_check_load_state(u, error); + if (r < 0) + return r; + + return bus_unit_method_get_processes(message, u, error); +} + static int transient_unit_from_message( Manager *m, sd_bus_message *message, @@ -2042,6 +2066,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, 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, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index c507265070..ed207f15b9 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -24,8 +24,10 @@ #include "cgroup-util.h" #include "dbus-unit.h" #include "dbus.h" +#include "fd-util.h" #include "locale-util.h" #include "log.h" +#include "process-util.h" #include "selinux-access.h" #include "signal-util.h" #include "special.h" @@ -841,6 +843,146 @@ static int property_get_cgroup( return sd_bus_message_append(reply, "s", t); } +static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) { + _cleanup_free_ char *buf = NULL, *cmdline = NULL; + int r; + + assert(reply); + assert(pid > 0); + + r = set_put(pids, PID_TO_PTR(pid)); + if (r == -EEXIST || r == 0) + return 0; + if (r < 0) + return r; + + if (!p) { + r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf); + if (r == -ESRCH) + return 0; + if (r < 0) + return r; + + p = buf; + } + + (void) get_process_cmdline(pid, 0, true, &cmdline); + + return sd_bus_message_append(reply, + "(sus)", + p, + (uint32_t) pid, + cmdline); +} + +static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) { + _cleanup_closedir_ DIR *d = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(reply); + assert(p); + + r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f); + if (r == ENOENT) + return 0; + if (r < 0) + return r; + + for (;;) { + pid_t pid; + + r = cg_read_pid(f, &pid); + if (r < 0) + return r; + if (r == 0) + break; + + if (is_kernel_thread(pid) > 0) + continue; + + r = append_process(reply, p, pid, pids); + if (r < 0) + return r; + } + + r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; + + for (;;) { + _cleanup_free_ char *g = NULL, *j = NULL; + + r = cg_read_subgroup(d, &g); + if (r < 0) + return r; + if (r == 0) + break; + + j = strjoin(p, "/", g, NULL); + if (!j) + return -ENOMEM; + + r = append_cgroup(reply, j, pids); + if (r < 0) + return r; + } + + return 0; +} + +int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(set_freep) Set *pids = NULL; + _cleanup_free_ char *p = NULL; + Unit *u = userdata; + pid_t pid; + int r; + + assert(message); + + pids = set_new(NULL); + if (!pids) + return -ENOMEM; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(sus)"); + if (r < 0) + return r; + + if (u->cgroup_path) { + r = append_cgroup(reply, u->cgroup_path, pids); + if (r < 0) + return r; + } + + /* The main and control pids might live outside of the cgroup, hence fetch them separately */ + pid = unit_main_pid(u); + if (pid > 0) { + r = append_process(reply, NULL, pid, pids); + if (r < 0) + return r; + } + + pid = unit_control_pid(u); + if (pid > 0) { + r = append_process(reply, NULL, pid, pids); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + const sd_bus_vtable bus_unit_cgroup_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0), @@ -848,6 +990,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = { SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0), SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0), SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0), + SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index 07948b9cd0..4db88dbebc 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -36,5 +36,6 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus 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_message *message, void *userdata, sd_bus_error *error); +int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_unit_check_load_state(Unit *u, sd_bus_error *error); diff --git a/src/core/mount.c b/src/core/mount.c index 632c5c824c..188fb0aa40 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1790,6 +1790,14 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error); } +static int mount_control_pid(Unit *u) { + Mount *m = MOUNT(u); + + assert(m); + + return m->control_pid; +} + static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { [MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", @@ -1851,6 +1859,8 @@ const UnitVTable mount_vtable = { .reset_failed = mount_reset_failed, + .control_pid = mount_control_pid, + .bus_vtable = bus_mount_vtable, .bus_set_property = bus_mount_set_property, .bus_commit_properties = bus_mount_commit_properties, diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index f78eedbd6e..b732501364 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -76,6 +76,10 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="GetUnitFileState"/> + + diff --git a/src/core/service.c b/src/core/service.c index 58084e2f82..b46dd8bcdd 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -3195,6 +3195,22 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error); } +static int service_main_pid(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + return s->main_pid; +} + +static int service_control_pid(Unit *u) { + Service *s = SERVICE(u); + + assert(s); + + return s->control_pid; +} + static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { [SERVICE_RESTART_NO] = "no", [SERVICE_RESTART_ON_SUCCESS] = "on-success", @@ -3303,6 +3319,9 @@ const UnitVTable service_vtable = { .notify_cgroup_empty = service_notify_cgroup_empty_event, .notify_message = service_notify_message, + .main_pid = service_main_pid, + .control_pid = service_control_pid, + .bus_name_owner_change = service_bus_name_owner_change, .bus_vtable = bus_service_vtable, diff --git a/src/core/socket.c b/src/core/socket.c index 65da0e3c5e..a9fff9c259 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2781,6 +2781,14 @@ char *socket_fdname(Socket *s) { return UNIT(s)->id; } +static int socket_control_pid(Unit *u) { + Socket *s = SOCKET(u); + + assert(s); + + return s->control_pid; +} + static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { [SOCKET_EXEC_START_PRE] = "StartPre", [SOCKET_EXEC_START_CHOWN] = "StartChown", @@ -2846,6 +2854,8 @@ const UnitVTable socket_vtable = { .reset_failed = socket_reset_failed, + .control_pid = socket_control_pid, + .bus_vtable = bus_socket_vtable, .bus_set_property = bus_socket_set_property, .bus_commit_properties = bus_socket_commit_properties, diff --git a/src/core/swap.c b/src/core/swap.c index c6502eb821..d8802470d2 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1426,6 +1426,14 @@ static bool swap_supported(void) { return supported; } +static int swap_control_pid(Unit *u) { + Swap *s = SWAP(u); + + assert(s); + + return s->control_pid; +} + static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { [SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", @@ -1487,6 +1495,8 @@ const UnitVTable swap_vtable = { .reset_failed = swap_reset_failed, + .control_pid = swap_control_pid, + .bus_vtable = bus_swap_vtable, .bus_set_property = bus_swap_set_property, .bus_commit_properties = bus_swap_commit_properties, diff --git a/src/core/unit.c b/src/core/unit.c index 1f57293a0b..cb79c7c6b1 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3801,3 +3801,21 @@ bool unit_is_pristine(Unit *u) { u->job || u->merged_into); } + +pid_t unit_control_pid(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->control_pid) + return UNIT_VTABLE(u)->control_pid(u); + + return 0; +} + +pid_t unit_main_pid(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->main_pid) + return UNIT_VTABLE(u)->main_pid(u); + + return 0; +} diff --git a/src/core/unit.h b/src/core/unit.h index cfdac852a5..5909652976 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -390,6 +390,12 @@ struct UnitVTable { /* Returns the next timeout of a unit */ int (*get_timeout)(Unit *u, usec_t *timeout); + /* Returns the main PID if there is any defined, or 0. */ + pid_t (*main_pid)(Unit *u); + + /* Returns the main PID if there is any defined, or 0. */ + pid_t (*control_pid)(Unit *u); + /* This is called for each unit type and should be used to * enumerate existing devices and load them. However, * everything that is loaded here should still stay in @@ -601,6 +607,9 @@ bool unit_type_supported(UnitType t); bool unit_is_pristine(Unit *u); +pid_t unit_control_pid(Unit *u); +pid_t unit_main_pid(Unit *u); + static inline bool unit_supported(Unit *u) { return unit_type_supported(u->type); } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c new file mode 100644 index 0000000000..25ecbd3df3 --- /dev/null +++ b/src/shared/bus-unit-util.c @@ -0,0 +1,446 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "alloc-util.h" +#include "bus-internal.h" +#include "bus-unit-util.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "env-util.h" +#include "escape.h" +#include "hashmap.h" +#include "list.h" +#include "locale-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "process-util.h" +#include "rlimit-util.h" +#include "signal-util.h" +#include "string-util.h" +#include "syslog-util.h" +#include "terminal-util.h" +#include "utf8.h" +#include "util.h" + +struct CGroupInfo { + char *cgroup_path; + bool is_const; /* If false, cgroup_path should be free()'d */ + + Hashmap *pids; /* PID → process name */ + bool done; + + struct CGroupInfo *parent; + LIST_FIELDS(struct CGroupInfo, siblings); + LIST_HEAD(struct CGroupInfo, children); + size_t n_children; +}; + +static bool IS_ROOT(const char *p) { + return isempty(p) || streq(p, "/"); +} + +static int add_cgroup(Hashmap *cgroups, const char *path, bool is_const, struct CGroupInfo **ret) { + struct CGroupInfo *parent = NULL, *cg; + int r; + + assert(cgroups); + assert(ret); + + if (IS_ROOT(path)) + path = "/"; + + cg = hashmap_get(cgroups, path); + if (cg) { + *ret = cg; + return 0; + } + + if (!IS_ROOT(path)) { + const char *e, *pp; + + e = strrchr(path, '/'); + if (!e) + return -EINVAL; + + pp = strndupa(path, e - path); + if (!pp) + return -ENOMEM; + + r = add_cgroup(cgroups, pp, false, &parent); + if (r < 0) + return r; + } + + cg = new0(struct CGroupInfo, 1); + if (!cg) + return -ENOMEM; + + if (is_const) + cg->cgroup_path = (char*) path; + else { + cg->cgroup_path = strdup(path); + if (!cg->cgroup_path) { + free(cg); + return -ENOMEM; + } + } + + cg->is_const = is_const; + cg->parent = parent; + + r = hashmap_put(cgroups, cg->cgroup_path, cg); + if (r < 0) { + if (!is_const) + free(cg->cgroup_path); + free(cg); + return r; + } + + if (parent) { + LIST_PREPEND(siblings, parent->children, cg); + parent->n_children++; + } + + *ret = cg; + return 1; +} + +static int add_process( + Hashmap *cgroups, + const char *path, + pid_t pid, + const char *name) { + + struct CGroupInfo *cg; + int r; + + assert(cgroups); + assert(name); + assert(pid > 0); + + r = add_cgroup(cgroups, path, true, &cg); + if (r < 0) + return r; + + r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops); + if (r < 0) + return r; + + return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name); +} + +static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) { + assert(cgroups); + assert(cg); + + while (cg->children) + remove_cgroup(cgroups, cg->children); + + hashmap_remove(cgroups, cg->cgroup_path); + + if (!cg->is_const) + free(cg->cgroup_path); + + hashmap_free(cg->pids); + + if (cg->parent) + LIST_REMOVE(siblings, cg->parent->children, cg); + + free(cg); +} + +static int cgroup_info_compare_func(const void *a, const void *b) { + const struct CGroupInfo *x = *(const struct CGroupInfo* const*) a, *y = *(const struct CGroupInfo* const*) b; + + assert(x); + assert(y); + + return strcmp(x->cgroup_path, y->cgroup_path); +} + +static int dump_processes( + Hashmap *cgroups, + const char *cgroup_path, + const char *prefix, + unsigned n_columns, + OutputFlags flags) { + + struct CGroupInfo *cg; + int r; + + assert(prefix); + + if (IS_ROOT(cgroup_path)) + cgroup_path = "/"; + + cg = hashmap_get(cgroups, cgroup_path); + if (!cg) + return 0; + + if (!hashmap_isempty(cg->pids)) { + const char *name; + size_t n = 0, i; + pid_t *pids; + void *pidp; + Iterator j; + int width; + + /* Order processes by their PID */ + pids = newa(pid_t, hashmap_size(cg->pids)); + + HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) + pids[n++] = PTR_TO_PID(pidp); + + assert(n == hashmap_size(cg->pids)); + qsort_safe(pids, n, sizeof(pid_t), pid_compare_func); + + width = DECIMAL_STR_WIDTH(pids[n-1]); + + for (i = 0; i < n; i++) { + _cleanup_free_ char *e = NULL; + const char *special; + bool more; + + name = hashmap_get(cg->pids, PID_TO_PTR(pids[i])); + assert(name); + + if (n_columns != 0) { + unsigned k; + + k = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U); + + e = ellipsize(name, k, 100); + if (e) + name = e; + } + + more = i+1 < n || cg->children; + special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT); + + fprintf(stdout, "%s%s%*"PID_PRI" %s\n", + prefix, + special, + width, pids[i], + name); + } + } + + if (cg->children) { + struct CGroupInfo **children, *child; + size_t n = 0, i; + + /* Order subcgroups by their name */ + children = newa(struct CGroupInfo*, cg->n_children); + LIST_FOREACH(siblings, child, cg->children) + children[n++] = child; + assert(n == cg->n_children); + qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func); + + n_columns = MAX(LESS_BY(n_columns, 2U), 20U); + + for (i = 0; i < n; i++) { + _cleanup_free_ char *pp = NULL; + const char *name, *special; + bool more; + + child = children[i]; + + name = strrchr(child->cgroup_path, '/'); + if (!name) + return -EINVAL; + name++; + + more = i+1 < n; + special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT); + + fputs(prefix, stdout); + fputs(special, stdout); + fputs(name, stdout); + fputc('\n', stdout); + + special = draw_special_char(more ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE); + + pp = strappend(prefix, special); + if (!pp) + return -ENOMEM; + + r = dump_processes(cgroups, child->cgroup_path, pp, n_columns, flags); + if (r < 0) + return r; + } + } + + cg->done = true; + return 0; +} + +static int dump_extra_processes( + Hashmap *cgroups, + const char *prefix, + unsigned n_columns, + OutputFlags flags) { + + _cleanup_free_ pid_t *pids = NULL; + _cleanup_hashmap_free_ Hashmap *names = NULL; + struct CGroupInfo *cg; + size_t n_allocated = 0, n = 0, k; + Iterator i; + int width, r; + + /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as + * combined, sorted, linear list. */ + + HASHMAP_FOREACH(cg, cgroups, i) { + const char *name; + void *pidp; + Iterator j; + + if (cg->done) + continue; + + if (hashmap_isempty(cg->pids)) + continue; + + r = hashmap_ensure_allocated(&names, &trivial_hash_ops); + if (r < 0) + return r; + + if (!GREEDY_REALLOC(pids, n_allocated, n + hashmap_size(cg->pids))) + return -ENOMEM; + + HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) { + pids[n++] = PTR_TO_PID(pidp); + + r = hashmap_put(names, pidp, (void*) name); + if (r < 0) + return r; + } + } + + if (n == 0) + return 0; + + qsort_safe(pids, n, sizeof(pid_t), pid_compare_func); + width = DECIMAL_STR_WIDTH(pids[n-1]); + + for (k = 0; k < n; k++) { + _cleanup_free_ char *e = NULL; + const char *name; + + name = hashmap_get(names, PID_TO_PTR(pids[k])); + assert(name); + + if (n_columns != 0) { + unsigned z; + + z = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U); + + e = ellipsize(name, z, 100); + if (e) + name = e; + } + + fprintf(stdout, "%s%s %*" PID_PRI " %s\n", + prefix, + draw_special_char(DRAW_TRIANGULAR_BULLET), + width, pids[k], + name); + } + + return 0; +} + +int unit_show_processes( + sd_bus *bus, + const char *unit, + const char *cgroup_path, + const char *prefix, + unsigned n_columns, + OutputFlags flags, + sd_bus_error *error) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + Hashmap *cgroups = NULL; + struct CGroupInfo *cg; + int r; + + assert(bus); + assert(unit); + + if (flags & OUTPUT_FULL_WIDTH) + n_columns = 0; + else if (n_columns <= 0) + n_columns = columns(); + + prefix = strempty(prefix); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitProcesses", + error, + &reply, + "s", + unit); + if (r < 0) + return r; + + cgroups = hashmap_new(&string_hash_ops); + if (!cgroups) + return -ENOMEM; + + r = sd_bus_message_enter_container(reply, 'a', "(sus)"); + if (r < 0) + goto finish; + + for (;;) { + const char *path = NULL, *name = NULL; + uint32_t pid; + + r = sd_bus_message_read(reply, "(sus)", &path, &pid, &name); + if (r < 0) + goto finish; + if (r == 0) + break; + + r = add_process(cgroups, path, pid, name); + if (r < 0) + goto finish; + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + goto finish; + + r = dump_processes(cgroups, cgroup_path, prefix, n_columns, flags); + if (r < 0) + goto finish; + + r = dump_extra_processes(cgroups, prefix, n_columns, flags); + +finish: + while ((cg = hashmap_first(cgroups))) + remove_cgroup(cgroups, cg); + + hashmap_free(cgroups); + + return r; +} diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h new file mode 100644 index 0000000000..55486f82ee --- /dev/null +++ b/src/shared/bus-unit-util.h @@ -0,0 +1,27 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "sd-bus.h" + +#include "output-mode.h" +#include "install.h" + +int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index f3039b23f7..65a2c554d5 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -37,23 +37,13 @@ #include "string-util.h" #include "terminal-util.h" -static int compare(const void *a, const void *b) { - const pid_t *p = a, *q = b; - - if (*p < *q) - return -1; - if (*p > *q) - return 1; - return 0; -} - static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) { unsigned i, j, pid_width; if (n_pids == 0) return; - qsort(pids, n_pids, sizeof(pid_t), compare); + qsort(pids, n_pids, sizeof(pid_t), pid_compare_func); /* Filter duplicates */ for (j = 0, i = 1; i < n_pids; i++) { @@ -86,8 +76,14 @@ static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, un } } +static int show_cgroup_one_by_path( + const char *path, + const char *prefix, + unsigned n_columns, + bool more, + bool kernel_threads, + OutputFlags flags) { -static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) { char *fn; _cleanup_fclose_ FILE *f = NULL; size_t n = 0, n_allocated = 0; @@ -125,7 +121,13 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne return 0; } -int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) { +int show_cgroup_by_path( + const char *path, + const char *prefix, + unsigned n_columns, + bool kernel_threads, + OutputFlags flags) { + _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL; _cleanup_closedir_ DIR *d = NULL; char *gn = NULL; @@ -137,8 +139,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns if (n_columns <= 0) n_columns = columns(); - if (!prefix) - prefix = ""; + prefix = strempty(prefix); r = cg_mangle_path(path, &fn); if (r < 0) @@ -202,7 +203,13 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns return 0; } -int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) { +int show_cgroup(const char *controller, + const char *path, + const char *prefix, + unsigned n_columns, + bool kernel_threads, + + OutputFlags flags) { _cleanup_free_ char *p = NULL; int r; @@ -215,7 +222,15 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags); } -static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids, OutputFlags flags) { +static int show_extra_pids( + const char *controller, + const char *path, + const char *prefix, + unsigned n_columns, + const pid_t pids[], + unsigned n_pids, + OutputFlags flags) { + _cleanup_free_ pid_t *copy = NULL; unsigned i, j; int r; @@ -252,7 +267,16 @@ static int show_extra_pids(const char *controller, const char *path, const char return 0; } -int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) { +int show_cgroup_and_extra( + const char *controller, + const char *path, + const char *prefix, + unsigned n_columns, + bool kernel_threads, + const pid_t extra_pids[], + unsigned n_extra_pids, + OutputFlags flags) { + int r; assert(path); @@ -264,7 +288,15 @@ int show_cgroup_and_extra(const char *controller, const char *path, const char * return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags); } -int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) { +int show_cgroup_and_extra_by_spec( + const char *spec, + const char *prefix, + unsigned n_columns, + bool kernel_threads, + const pid_t extra_pids[], + unsigned n_extra_pids, + OutputFlags flags) { + _cleanup_free_ char *controller = NULL, *path = NULL; int r; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 04205411dd..c74fc11ca6 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -39,6 +39,7 @@ #include "bus-common-errors.h" #include "bus-error.h" #include "bus-message.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "cgroup-show.h" #include "cgroup-util.h" @@ -3434,6 +3435,7 @@ typedef struct UnitStatusInfo { } UnitStatusInfo; static void print_status_info( + sd_bus *bus, UnitStatusInfo *i, bool *ellipsized) { @@ -3444,6 +3446,7 @@ static void print_status_info( char since2[FORMAT_TIMESTAMP_MAX], *s2; const char *path; char **t, **t2; + int r; assert(i); @@ -3716,25 +3719,26 @@ static void print_status_info( 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 || - (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) { + if (i->control_group) + printf(" CGroup: %s\n", i->control_group); + + { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + static const char prefix[] = " "; unsigned c; - printf(" CGroup: %s\n", i->control_group); + c = columns(); + if (c > sizeof(prefix) - 1) + c -= sizeof(prefix) - 1; + else + c = 0; - if (IN_SET(arg_transport, - BUS_TRANSPORT_LOCAL, - BUS_TRANSPORT_MACHINE)) { + r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error); + if (r == -EBADR) { unsigned k = 0; pid_t extra[2]; - static const char prefix[] = " "; - c = columns(); - if (c > sizeof(prefix) - 1) - c -= sizeof(prefix) - 1; - else - c = 0; + /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */ if (i->main_pid > 0) extra[k++] = i->main_pid; @@ -3743,7 +3747,8 @@ static void print_status_info( extra[k++] = i->control_pid; show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags()); - } + } else if (r < 0) + log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r)); } if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) @@ -4504,7 +4509,7 @@ static int show_one( if (streq(verb, "help")) show_unit_help(&info); else - print_status_info(&info, ellipsized); + print_status_info(bus, &info, ellipsized); } strv_free(info.documentation); -- cgit v1.2.3-54-g00ecf From fa7099927c87b91804c6cc5ec3a3d8f8b6ba9ada Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 15:32:24 +0200 Subject: networkd: consider various IPv6 features as disabled if IPv6 is not available in the kernel --- src/network/networkd-link.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5cdf123652..5101d553d5 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -42,6 +42,9 @@ static bool link_dhcp6_enabled(Link *link) { assert(link); + if (!socket_ipv6_is_supported()) + return false; + if (link->flags & IFF_LOOPBACK) return false; @@ -90,6 +93,9 @@ static bool link_ipv4ll_enabled(Link *link) { static bool link_ipv6ll_enabled(Link *link) { assert(link); + if (!socket_ipv6_is_supported()) + return false; + if (link->flags & IFF_LOOPBACK) return false; @@ -192,6 +198,9 @@ static bool link_proxy_arp_enabled(Link *link) { static bool link_ipv6_accept_ra_enabled(Link *link) { assert(link); + if (!socket_ipv6_is_supported()) + return false; + if (link->flags & IFF_LOOPBACK) return false; @@ -214,6 +223,7 @@ static bool link_ipv6_accept_ra_enabled(Link *link) { } static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) { + assert(link); if (!socket_ipv6_is_supported()) return _IPV6_PRIVACY_EXTENSIONS_INVALID; -- cgit v1.2.3-54-g00ecf From a0e270198a9d58b58dff44a6504843f19458facd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 15:51:33 +0200 Subject: loginctl,machinectl: also make use of new GetProcesses() bus call This ports over machinectl and loginctl to also use the new GetProcesses() bus call to show the process tree of a container or login session. This is similar to how systemctl already has been ported over in a previous commit. --- src/login/loginctl.c | 35 +++++++++++++++++++++++------------ src/machine/machinectl.c | 30 ++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 8b23135edd..7c6d2a1b0c 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -27,6 +27,7 @@ #include "alloc-util.h" #include "bus-error.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "cgroup-show.h" #include "cgroup-util.h" @@ -227,18 +228,15 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; const char *cgroup; - int r; unsigned c; + int r; assert(bus); assert(unit); - if (arg_transport != BUS_TRANSPORT_LOCAL) - return 0; - path = unit_dbus_path_from_name(unit); if (!path) - return -ENOMEM; + return log_oom(); r = sd_bus_get_property( bus, @@ -246,27 +244,40 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit path, interface, "ControlGroup", - &error, &reply, "s"); + &error, + &reply, + "s"); if (r < 0) - return r; + return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &cgroup); if (r < 0) - return r; + return bus_log_parse_error(r); if (isempty(cgroup)) return 0; - if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) - return 0; - c = columns(); if (c > 18) c -= 18; else c = 0; - show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); + r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error); + if (r == -EBADR) { + + if (arg_transport == BUS_TRANSPORT_REMOTE) + return 0; + + /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */ + + if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) + return 0; + + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); + } else if (r < 0) + return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r)); + return 0; } diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index c370ed57ec..f47752fce2 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -33,6 +33,7 @@ #include "alloc-util.h" #include "bus-error.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "cgroup-show.h" #include "cgroup-util.h" @@ -331,8 +332,8 @@ static int list_images(int argc, char *argv[], void *userdata) { } static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; const char *cgroup; int r; @@ -341,9 +342,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { assert(bus); assert(unit); - if (arg_transport == BUS_TRANSPORT_REMOTE) - return 0; - path = unit_dbus_path_from_name(unit); if (!path) return log_oom(); @@ -357,16 +355,14 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { &error, &reply, "s"); - if (r < 0) { - log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &cgroup); if (r < 0) return bus_log_parse_error(r); - if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) + if (isempty(cgroup)) return 0; c = columns(); @@ -375,7 +371,21 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { else c = 0; - show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); + r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error); + if (r == -EBADR) { + + if (arg_transport == BUS_TRANSPORT_REMOTE) + return 0; + + /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */ + + if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) + return 0; + + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); + } else if (r < 0) + return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r)); + return 0; } -- cgit v1.2.3-54-g00ecf From 0ff308c8dea9a589ddbc437c097edc3fb26360d7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 16:06:58 +0200 Subject: shared: drop kernel_thread bool from cgroups show code Make this an output flag instead, so that our function prototypes can lose one parameter --- src/cgls/cgls.c | 11 ++++++----- src/login/loginctl.c | 2 +- src/machine/machinectl.c | 2 +- src/shared/cgroup-show.c | 36 +++++++++++++++++++----------------- src/shared/cgroup-show.h | 8 ++++---- src/shared/output-mode.h | 4 ++++ src/systemctl/systemctl.c | 4 ++-- 7 files changed, 37 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index d6fb10cac5..dcb5912b83 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -191,7 +191,8 @@ int main(int argc, char *argv[]) { output_flags = arg_all * OUTPUT_SHOW_ALL | - (arg_full > 0) * OUTPUT_FULL_WIDTH; + (arg_full > 0) * OUTPUT_FULL_WIDTH | + arg_kernel_threads * OUTPUT_KERNEL_THREADS; if (optind < argc) { _cleanup_free_ char *root = NULL; @@ -209,7 +210,7 @@ int main(int argc, char *argv[]) { printf("Directory %s:\n", argv[i]); fflush(stdout); - q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags); + q = show_cgroup_by_path(argv[i], NULL, 0, output_flags); } else { _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL; const char *controller, *path; @@ -235,7 +236,7 @@ int main(int argc, char *argv[]) { show_cg_info(controller, path); - q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags); + q = show_cgroup(controller, path, NULL, 0, output_flags); } if (q < 0) @@ -258,7 +259,7 @@ int main(int argc, char *argv[]) { printf("Working directory %s:\n", cwd); fflush(stdout); - r = show_cgroup_by_path(cwd, NULL, 0, arg_kernel_threads, output_flags); + r = show_cgroup_by_path(cwd, NULL, 0, output_flags); done = true; } } @@ -273,7 +274,7 @@ int main(int argc, char *argv[]) { show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root); printf("-.slice\n"); - r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags); + r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags); } } diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 7c6d2a1b0c..1c75565636 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -274,7 +274,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) return 0; - show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags()); } else if (r < 0) return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r)); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index f47752fce2..7b1ede7116 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -382,7 +382,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0) return 0; - show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags()); } else if (r < 0) return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r)); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 65a2c554d5..7539891bf2 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -37,7 +37,15 @@ #include "string-util.h" #include "terminal-util.h" -static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) { +static void show_pid_array( + pid_t pids[], + unsigned n_pids, + const char *prefix, + unsigned n_columns, + bool extra, + bool more, + OutputFlags flags) { + unsigned i, j, pid_width; if (n_pids == 0) @@ -81,7 +89,6 @@ static int show_cgroup_one_by_path( const char *prefix, unsigned n_columns, bool more, - bool kernel_threads, OutputFlags flags) { char *fn; @@ -103,7 +110,7 @@ static int show_cgroup_one_by_path( while ((r = cg_read_pid(f, &pid)) > 0) { - if (!kernel_threads && is_kernel_thread(pid) > 0) + if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0) continue; if (!GREEDY_REALLOC(pids, n_allocated, n + 1)) @@ -116,7 +123,7 @@ static int show_cgroup_one_by_path( if (r < 0) return r; - show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags); + show_pid_array(pids, n, prefix, n_columns, false, more, flags); return 0; } @@ -125,7 +132,6 @@ int show_cgroup_by_path( const char *path, const char *prefix, unsigned n_columns, - bool kernel_threads, OutputFlags flags) { _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL; @@ -161,7 +167,7 @@ int show_cgroup_by_path( continue; if (!shown_pids) { - show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags); + show_cgroup_one_by_path(path, prefix, n_columns, true, flags); shown_pids = true; } @@ -174,7 +180,7 @@ int show_cgroup_by_path( return -ENOMEM; } - show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags); + show_cgroup_by_path(last, p1, n_columns-2, flags); free(last); } @@ -186,7 +192,7 @@ int show_cgroup_by_path( return r; if (!shown_pids) - show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags); + show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags); if (last) { printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last))); @@ -197,7 +203,7 @@ int show_cgroup_by_path( return -ENOMEM; } - show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags); + show_cgroup_by_path(last, p2, n_columns-2, flags); } return 0; @@ -207,8 +213,6 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, - bool kernel_threads, - OutputFlags flags) { _cleanup_free_ char *p = NULL; int r; @@ -219,7 +223,7 @@ int show_cgroup(const char *controller, if (r < 0) return r; - return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags); + return show_cgroup_by_path(p, prefix, n_columns, flags); } static int show_extra_pids( @@ -262,7 +266,7 @@ static int show_extra_pids( copy[j++] = pids[i]; } - show_pid_array(copy, j, prefix, n_columns, true, false, false, flags); + show_pid_array(copy, j, prefix, n_columns, true, false, flags); return 0; } @@ -272,7 +276,6 @@ int show_cgroup_and_extra( const char *path, const char *prefix, unsigned n_columns, - bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) { @@ -281,7 +284,7 @@ int show_cgroup_and_extra( assert(path); - r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags); + r = show_cgroup(controller, path, prefix, n_columns, flags); if (r < 0) return r; @@ -292,7 +295,6 @@ int show_cgroup_and_extra_by_spec( const char *spec, const char *prefix, unsigned n_columns, - bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) { @@ -306,5 +308,5 @@ int show_cgroup_and_extra_by_spec( if (r < 0) return r; - return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags); + return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags); } diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h index 3ab7dfb33c..5c1d6e6d98 100644 --- a/src/shared/cgroup-show.h +++ b/src/shared/cgroup-show.h @@ -25,8 +25,8 @@ #include "logs-show.h" #include "output-mode.h" -int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags); -int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags); +int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, OutputFlags flags); +int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, OutputFlags flags); -int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags); -int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags); +int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags); +int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags); diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h index c5470e7c1b..e2b26e04d3 100644 --- a/src/shared/output-mode.h +++ b/src/shared/output-mode.h @@ -34,6 +34,9 @@ typedef enum OutputMode { _OUTPUT_MODE_INVALID = -1 } OutputMode; +/* The output flags definitions are shared by the logs and process tree output. Some apply to both, some only to the + * logs output, others only to the process tree output. */ + typedef enum OutputFlags { OUTPUT_SHOW_ALL = 1 << 0, OUTPUT_FOLLOW = 1 << 1, @@ -43,4 +46,5 @@ typedef enum OutputFlags { OUTPUT_CATALOG = 1 << 5, OUTPUT_BEGIN_NEWLINE = 1 << 6, OUTPUT_UTC = 1 << 7, + OUTPUT_KERNEL_THREADS = 1 << 8, } OutputFlags; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c74fc11ca6..9c59fcf610 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3746,7 +3746,7 @@ static void print_status_info( if (i->control_pid > 0) extra[k++] = i->control_pid; - show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags()); + show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags()); } else if (r < 0) log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r)); } @@ -4663,7 +4663,7 @@ static int show_system_status(sd_bus *bus) { else c = 0; - show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags()); + show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags()); } return 0; -- cgit v1.2.3-54-g00ecf From 20b1644140c02b436d5efb203f40c9b80a4579a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 17:43:13 +0200 Subject: shared: move unit-specific code from bus-util.h to bus-unit-util.h Previously we'd have generally useful sd-bus utilities in bust-util.h, intermixed with code that is specifically for writing clients for PID 1, wrapping job and unit handling. Let's split the latter out and move it into bus-unit-util.c, to make the sources a bit short and easier to grok. --- src/analyze/analyze.c | 1 + src/nspawn/nspawn-register.c | 1 + src/run/run.c | 1 + src/shared/bus-unit-util.c | 841 ++++++++++++++++++++++++++++++++++++++++++ src/shared/bus-unit-util.h | 30 ++ src/shared/bus-util.c | 859 ------------------------------------------- src/shared/bus-util.h | 33 -- 7 files changed, 874 insertions(+), 892 deletions(-) (limited to 'src') diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 5e03c0c5e0..a790ccd33e 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -28,6 +28,7 @@ #include "alloc-util.h" #include "analyze-verify.h" #include "bus-error.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "glob-util.h" #include "hashmap.h" diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index 760861089d..20103c5e88 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -20,6 +20,7 @@ #include "sd-bus.h" #include "bus-error.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "nspawn-register.h" #include "stat-util.h" diff --git a/src/run/run.c b/src/run/run.c index 1993a424ca..4a0143d4e6 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -25,6 +25,7 @@ #include "alloc-util.h" #include "bus-error.h" +#include "bus-unit-util.h" #include "bus-util.h" #include "calendarspec.h" #include "env-util.h" diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 25ecbd3df3..da479aec8d 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -38,6 +38,847 @@ #include "utf8.h" #include "util.h" +int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { + assert(message); + assert(u); + + u->machine = NULL; + + return sd_bus_message_read( + message, + "(ssssssouso)", + &u->id, + &u->description, + &u->load_state, + &u->active_state, + &u->sub_state, + &u->following, + &u->unit_path, + &u->job_id, + &u->job_type, + &u->job_path); +} + +int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) { + const char *eq, *field; + int r, rl; + + assert(m); + assert(assignment); + + eq = strchr(assignment, '='); + if (!eq) { + log_error("Not an assignment: %s", assignment); + return -EINVAL; + } + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + field = strndupa(assignment, eq - assignment); + eq++; + + if (streq(field, "CPUQuota")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); + else if (endswith(eq, "%")) { + double percent; + + if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) { + log_error("CPU quota '%s' invalid.", eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100); + } else { + log_error("CPU quota needs to be in percent."); + return -EINVAL; + } + + goto finish; + + } else if (streq(field, "EnvironmentFile")) { + + r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1, + eq[0] == '-' ? eq + 1 : eq, + eq[0] == '-'); + goto finish; + + } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) { + char *n; + usec_t t; + size_t l; + r = parse_sec(eq, &t); + if (r < 0) + return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); + + l = strlen(field); + n = newa(char, l + 2); + if (!n) + return log_oom(); + + /* Change suffix Sec → USec */ + strcpy(mempcpy(n, field, l - 3), "USec"); + r = sd_bus_message_append(m, "sv", n, "t", t); + goto finish; + } + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + rl = rlimit_from_string(field); + if (rl >= 0) { + const char *sn; + struct rlimit l; + + r = rlimit_parse(rl, eq, &l); + if (r < 0) + return log_error_errno(r, "Failed to parse resource limit: %s", eq); + + r = sd_bus_message_append(m, "v", "t", l.rlim_max); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + sn = strjoina(field, "Soft"); + r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur); + + } else if (STR_IN_SET(field, + "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting", + "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", + "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", + "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", + "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) { + + r = parse_boolean(eq); + if (r < 0) + return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment); + + r = sd_bus_message_append(m, "v", "b", r); + + } else if (streq(field, "MemoryLimit")) { + uint64_t bytes; + + if (isempty(eq) || streq(eq, "infinity")) + bytes = (uint64_t) -1; + else { + r = parse_size(eq, 1024, &bytes); + if (r < 0) { + log_error("Failed to parse bytes specification %s", assignment); + return -EINVAL; + } + } + + r = sd_bus_message_append(m, "v", "t", bytes); + + } else if (streq(field, "TasksMax")) { + uint64_t n; + + if (isempty(eq) || streq(eq, "infinity")) + n = (uint64_t) -1; + else { + r = safe_atou64(eq, &n); + if (r < 0) { + log_error("Failed to parse maximum tasks specification %s", assignment); + return -EINVAL; + } + } + + r = sd_bus_message_append(m, "v", "t", n); + + } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { + uint64_t u; + + r = cg_cpu_shares_parse(eq, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", u); + + } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) { + uint64_t u; + + r = cg_cpu_shares_parse(eq, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", u); + + } else if (STR_IN_SET(field, + "User", "Group", "DevicePolicy", "KillMode", + "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath", + "StandardInput", "StandardOutput", "StandardError", + "Description", "Slice", "Type", "WorkingDirectory", + "RootDirectory", "SyslogIdentifier", "ProtectSystem", + "ProtectHome")) + r = sd_bus_message_append(m, "v", "s", eq); + + else if (streq(field, "SyslogLevel")) { + int level; + + level = log_level_from_string(eq); + if (level < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", level); + + } else if (streq(field, "SyslogFacility")) { + int facility; + + facility = log_facility_unshifted_from_string(eq); + if (facility < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", facility); + + } else if (streq(field, "DeviceAllow")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "v", "a(ss)", 0); + else { + const char *path, *rwm, *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + rwm = e+1; + } else { + path = eq; + rwm = ""; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm); + } + + } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "v", "a(st)", 0); + else { + const char *path, *bandwidth, *e; + uint64_t bytes; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + bandwidth = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = parse_size(bandwidth, 1000, &bytes); + if (r < 0) { + log_error("Failed to parse byte value %s.", bandwidth); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes); + } + + } else if (streq(field, "BlockIODeviceWeight")) { + + if (isempty(eq)) + r = sd_bus_message_append(m, "v", "a(st)", 0); + else { + const char *path, *weight, *e; + uint64_t u; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + weight = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = safe_atou64(weight, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, weight); + return -EINVAL; + } + r = sd_bus_message_append(m, "v", "a(st)", path, u); + } + + } else if (streq(field, "Nice")) { + int32_t i; + + r = safe_atoi32(eq, &i); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", i); + + } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + 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); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); + if (r < 0) { + log_error("Failed to parse Environment value %s", eq); + return -EINVAL; + } + if (r == 0) + break; + + if (streq(field, "Environment")) { + if (!env_assignment_is_valid(word)) { + log_error("Invalid environment assignment: %s", word); + return -EINVAL; + } + } else { /* PassEnvironment */ + if (!env_name_is_valid(word)) { + log_error("Invalid environment variable name: %s", word); + return -EINVAL; + } + } + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + + } else if (streq(field, "KillSignal")) { + int sig; + + sig = signal_from_string_try_harder(eq); + if (sig < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", sig); + + } else if (streq(field, "TimerSlackNSec")) { + nsec_t n; + + r = parse_nsec(eq, &n); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", n); + } else if (streq(field, "OOMScoreAdjust")) { + int oa; + + r = safe_atoi(eq, &oa); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + if (!oom_score_adjust_is_valid(oa)) { + log_error("OOM score adjust value out of range"); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", oa); + } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + 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); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + int offset; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + if (r == 0) + break; + + if (!utf8_is_valid(word)) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + offset = word[0] == '-'; + if (!path_is_absolute(word + offset)) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + path_kill_slashes(word + offset); + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + + } else if (streq(field, "RuntimeDirectory")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + 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); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s", field, eq); + + if (r == 0) + break; + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + + } else { + log_error("Unknown assignment %s.", assignment); + return -EINVAL; + } + +finish: + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 0; +} + +typedef struct BusWaitForJobs { + sd_bus *bus; + Set *jobs; + + char *name; + char *result; + + sd_bus_slot *slot_job_removed; + sd_bus_slot *slot_disconnected; +} BusWaitForJobs; + +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(sd_bus_message_get_bus(m)); + + return 0; +} + +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(m); + assert(d); + + r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result); + if (r < 0) { + bus_log_parse_error(r); + return 0; + } + + found = set_remove(d->jobs, (char*) path); + if (!found) + return 0; + + free(found); + + if (!isempty(result)) + d->result = strdup(result); + + if (!isempty(unit)) + d->name = strdup(unit); + + return 0; +} + +void bus_wait_for_jobs_free(BusWaitForJobs *d) { + if (!d) + return; + + set_free_free(d->jobs); + + sd_bus_slot_unref(d->slot_disconnected); + sd_bus_slot_unref(d->slot_job_removed); + + sd_bus_unref(d->bus); + + free(d->name); + free(d->result); + + free(d); +} + +int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) { + _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL; + int r; + + assert(bus); + assert(ret); + + d = new0(BusWaitForJobs, 1); + if (!d) + return -ENOMEM; + + d->bus = sd_bus_ref(bus); + + /* When we are a bus client we match by sender. Direct + * connections OTOH have no initialized sender field, and + * hence we ignore the sender then */ + r = sd_bus_add_match( + bus, + &d->slot_job_removed, + bus->bus_client ? + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='JobRemoved'," + "path='/org/freedesktop/systemd1'" : + "type='signal'," + "interface='org.freedesktop.systemd1.Manager'," + "member='JobRemoved'," + "path='/org/freedesktop/systemd1'", + match_job_removed, d); + if (r < 0) + return r; + + r = sd_bus_add_match( + bus, + &d->slot_disconnected, + "type='signal'," + "sender='org.freedesktop.DBus.Local'," + "interface='org.freedesktop.DBus.Local'," + "member='Disconnected'", + match_disconnected, d); + if (r < 0) + return r; + + *ret = d; + d = NULL; + + return 0; +} + +static int bus_process_wait(sd_bus *bus) { + int r; + + for (;;) { + r = sd_bus_process(bus, NULL); + if (r < 0) + return r; + if (r > 0) + return 0; + + r = sd_bus_wait(bus, (uint64_t) -1); + if (r < 0) + return r; + } +} + +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, const char* const* extra_args) { + _cleanup_free_ char *service_shell_quoted = NULL; + const char *systemctl = "systemctl", *journalctl = "journalctl"; + + assert(service); + + service_shell_quoted = shell_maybe_quote(service); + + if (extra_args && extra_args[1]) { + _cleanup_free_ char *t; + + t = strv_join((char**) extra_args, " "); + systemctl = strjoina("systemctl ", t ? : ""); + journalctl = strjoina("journalctl ", t ? : ""); + } + + 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.\n" + "See \"%s status %s\" and \"%s -xe\" for details.\n", + service, + explanations[i].explanation, + systemctl, + service_shell_quoted ?: "", + journalctl); + goto finish; + } + } + + log_error("Job for %s failed.\n" + "See \"%s status %s\" and \"%s -xe\" for details.\n", + service, + systemctl, + service_shell_quoted ?: "", + journalctl); + +finish: + /* For some results maybe additional explanation is required */ + if (streq_ptr(result, "start-limit")) + log_info("To force a start use \"%1$s reset-failed %2$s\"\n" + "followed by \"%1$s start %2$s\" again.", + systemctl, + service_shell_quoted ?: ""); +} + +static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) { + int r = 0; + + assert(d->result); + + if (!quiet) { + if (streq(d->result, "canceled")) + log_error("Job for %s canceled.", strna(d->name)); + else if (streq(d->result, "timeout")) + log_error("Job for %s timed out.", strna(d->name)); + else if (streq(d->result, "dependency")) + log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name)); + else if (streq(d->result, "invalid")) + log_error("%s is not active, cannot reload.", strna(d->name)); + else if (streq(d->result, "assert")) + log_error("Assertion failed on job for %s.", strna(d->name)); + else if (streq(d->result, "unsupported")) + 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) { + int q; + _cleanup_free_ char *result = NULL; + + 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_job_error_with_service_result(d->name, result, extra_args); + } else + log_error("Job failed. See \"journalctl -xe\" for details."); + } + } + + if (streq(d->result, "canceled")) + r = -ECANCELED; + else if (streq(d->result, "timeout")) + r = -ETIME; + else if (streq(d->result, "dependency")) + r = -EIO; + else if (streq(d->result, "invalid")) + r = -ENOEXEC; + else if (streq(d->result, "assert")) + r = -EPROTO; + else if (streq(d->result, "unsupported")) + r = -EOPNOTSUPP; + else if (!streq(d->result, "done") && !streq(d->result, "skipped")) + r = -EIO; + + return r; +} + +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) { + int r = 0; + + assert(d); + + while (!set_isempty(d->jobs)) { + int q; + + q = bus_process_wait(d->bus); + if (q < 0) + return log_error_errno(q, "Failed to wait for response: %m"); + + if (d->result) { + q = check_wait_response(d, quiet, extra_args); + /* Return the first error as it is most likely to be + * meaningful. */ + if (q < 0 && r == 0) + r = q; + + log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name)); + } + + d->name = mfree(d->name); + d->result = mfree(d->result); + } + + return r; +} + +int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) { + int r; + + assert(d); + + r = set_ensure_allocated(&d->jobs, &string_hash_ops); + if (r < 0) + return r; + + return set_put_strdup(d->jobs, path); +} + +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, NULL); +} + +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; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) { + /* We expect only "success" changes to be sent over the bus. + Hence, reject anything negative. */ + UnitFileChangeType ch = unit_file_change_type_from_string(type); + + if (ch < 0) { + log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path); + continue; + } + + r = unit_file_changes_add(changes, n_changes, ch, path, source); + if (r < 0) + return r; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return bus_log_parse_error(r); + + unit_file_dump_changes(0, NULL, *changes, *n_changes, false); + return 0; +} + struct CGroupInfo { char *cgroup_path; bool is_const; /* If false, cgroup_path should be free()'d */ diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h index 55486f82ee..c0c172f336 100644 --- a/src/shared/bus-unit-util.h +++ b/src/shared/bus-unit-util.h @@ -24,4 +24,34 @@ #include "output-mode.h" #include "install.h" +typedef struct UnitInfo { + const char *machine; + const char *id; + const char *description; + const char *load_state; + const char *active_state; + const char *sub_state; + const char *following; + const char *unit_path; + uint32_t job_id; + const char *job_type; + const char *job_path; +} UnitInfo; + +int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); + +int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment); + +typedef struct BusWaitForJobs BusWaitForJobs; + +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, const char* const* extra_args); +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, UnitFileChange **changes, unsigned *n_changes); + int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error); diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 6a1877d8aa..4efbf3710f 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -39,34 +39,16 @@ #include "bus-label.h" #include "bus-message.h" #include "bus-util.h" -#include "cgroup-util.h" #include "def.h" -#include "env-util.h" #include "escape.h" -#include "extract-word.h" #include "fd-util.h" -#include "hashmap.h" -#include "install.h" -#include "kdbus.h" -#include "log.h" -#include "macro.h" #include "missing.h" #include "parse-util.h" -#include "path-util.h" #include "proc-cmdline.h" -#include "process-util.h" #include "rlimit-util.h" -#include "set.h" -#include "signal-util.h" #include "stdio-util.h" -#include "string-util.h" #include "strv.h" -#include "syslog-util.h" -#include "time-util.h" -#include "unit-name.h" #include "user-util.h" -#include "utf8.h" -#include "util.h" static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { sd_event *e = userdata; @@ -1383,847 +1365,6 @@ int bus_log_create_error(int r) { return log_error_errno(r, "Failed to create bus message: %m"); } -int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { - assert(message); - assert(u); - - u->machine = NULL; - - return sd_bus_message_read( - message, - "(ssssssouso)", - &u->id, - &u->description, - &u->load_state, - &u->active_state, - &u->sub_state, - &u->following, - &u->unit_path, - &u->job_id, - &u->job_type, - &u->job_path); -} - -int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) { - const char *eq, *field; - int r, rl; - - assert(m); - assert(assignment); - - eq = strchr(assignment, '='); - if (!eq) { - log_error("Not an assignment: %s", assignment); - return -EINVAL; - } - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - field = strndupa(assignment, eq - assignment); - eq++; - - if (streq(field, "CPUQuota")) { - - if (isempty(eq)) - r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); - else if (endswith(eq, "%")) { - double percent; - - if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) { - log_error("CPU quota '%s' invalid.", eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100); - } else { - log_error("CPU quota needs to be in percent."); - return -EINVAL; - } - - goto finish; - - } else if (streq(field, "EnvironmentFile")) { - - r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1, - eq[0] == '-' ? eq + 1 : eq, - eq[0] == '-'); - goto finish; - - } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) { - char *n; - usec_t t; - size_t l; - r = parse_sec(eq, &t); - if (r < 0) - return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); - - l = strlen(field); - n = newa(char, l + 2); - if (!n) - return log_oom(); - - /* Change suffix Sec → USec */ - strcpy(mempcpy(n, field, l - 3), "USec"); - r = sd_bus_message_append(m, "sv", n, "t", t); - goto finish; - } - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); - if (r < 0) - return bus_log_create_error(r); - - rl = rlimit_from_string(field); - if (rl >= 0) { - const char *sn; - struct rlimit l; - - r = rlimit_parse(rl, eq, &l); - if (r < 0) - return log_error_errno(r, "Failed to parse resource limit: %s", eq); - - r = sd_bus_message_append(m, "v", "t", l.rlim_max); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - - sn = strjoina(field, "Soft"); - r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur); - - } else if (STR_IN_SET(field, - "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting", - "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", - "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", - "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", - "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) { - - r = parse_boolean(eq); - if (r < 0) - return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment); - - r = sd_bus_message_append(m, "v", "b", r); - - } else if (streq(field, "MemoryLimit")) { - uint64_t bytes; - - if (isempty(eq) || streq(eq, "infinity")) - bytes = (uint64_t) -1; - else { - r = parse_size(eq, 1024, &bytes); - if (r < 0) { - log_error("Failed to parse bytes specification %s", assignment); - return -EINVAL; - } - } - - r = sd_bus_message_append(m, "v", "t", bytes); - - } else if (streq(field, "TasksMax")) { - uint64_t n; - - if (isempty(eq) || streq(eq, "infinity")) - n = (uint64_t) -1; - else { - r = safe_atou64(eq, &n); - if (r < 0) { - log_error("Failed to parse maximum tasks specification %s", assignment); - return -EINVAL; - } - } - - r = sd_bus_message_append(m, "v", "t", n); - - } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { - uint64_t u; - - r = cg_cpu_shares_parse(eq, &u); - if (r < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "t", u); - - } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) { - uint64_t u; - - r = cg_cpu_shares_parse(eq, &u); - if (r < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "t", u); - - } else if (STR_IN_SET(field, - "User", "Group", "DevicePolicy", "KillMode", - "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath", - "StandardInput", "StandardOutput", "StandardError", - "Description", "Slice", "Type", "WorkingDirectory", - "RootDirectory", "SyslogIdentifier", "ProtectSystem", - "ProtectHome")) - r = sd_bus_message_append(m, "v", "s", eq); - - else if (streq(field, "SyslogLevel")) { - int level; - - level = log_level_from_string(eq); - if (level < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", level); - - } else if (streq(field, "SyslogFacility")) { - int facility; - - facility = log_facility_unshifted_from_string(eq); - if (facility < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", facility); - - } else if (streq(field, "DeviceAllow")) { - - if (isempty(eq)) - r = sd_bus_message_append(m, "v", "a(ss)", 0); - else { - const char *path, *rwm, *e; - - e = strchr(eq, ' '); - if (e) { - path = strndupa(eq, e - eq); - rwm = e+1; - } else { - path = eq; - rwm = ""; - } - - if (!path_startswith(path, "/dev")) { - log_error("%s is not a device file in /dev.", path); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm); - } - - } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { - - if (isempty(eq)) - r = sd_bus_message_append(m, "v", "a(st)", 0); - else { - const char *path, *bandwidth, *e; - uint64_t bytes; - - e = strchr(eq, ' '); - if (e) { - path = strndupa(eq, e - eq); - bandwidth = e+1; - } else { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - if (!path_startswith(path, "/dev")) { - log_error("%s is not a device file in /dev.", path); - return -EINVAL; - } - - r = parse_size(bandwidth, 1000, &bytes); - if (r < 0) { - log_error("Failed to parse byte value %s.", bandwidth); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes); - } - - } else if (streq(field, "BlockIODeviceWeight")) { - - if (isempty(eq)) - r = sd_bus_message_append(m, "v", "a(st)", 0); - else { - const char *path, *weight, *e; - uint64_t u; - - e = strchr(eq, ' '); - if (e) { - path = strndupa(eq, e - eq); - weight = e+1; - } else { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - if (!path_startswith(path, "/dev")) { - log_error("%s is not a device file in /dev.", path); - return -EINVAL; - } - - r = safe_atou64(weight, &u); - if (r < 0) { - log_error("Failed to parse %s value %s.", field, weight); - return -EINVAL; - } - r = sd_bus_message_append(m, "v", "a(st)", path, u); - } - - } else if (streq(field, "Nice")) { - int32_t i; - - r = safe_atoi32(eq, &i); - if (r < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", i); - - } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - 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); - - p = eq; - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); - if (r < 0) { - log_error("Failed to parse Environment value %s", eq); - return -EINVAL; - } - if (r == 0) - break; - - if (streq(field, "Environment")) { - if (!env_assignment_is_valid(word)) { - log_error("Invalid environment assignment: %s", word); - return -EINVAL; - } - } else { /* PassEnvironment */ - if (!env_name_is_valid(word)) { - log_error("Invalid environment variable name: %s", word); - return -EINVAL; - } - } - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else if (streq(field, "KillSignal")) { - int sig; - - sig = signal_from_string_try_harder(eq); - if (sig < 0) { - log_error("Failed to parse %s value %s.", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", sig); - - } else if (streq(field, "TimerSlackNSec")) { - nsec_t n; - - r = parse_nsec(eq, &n); - if (r < 0) { - log_error("Failed to parse %s value %s", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "t", n); - } else if (streq(field, "OOMScoreAdjust")) { - int oa; - - r = safe_atoi(eq, &oa); - if (r < 0) { - log_error("Failed to parse %s value %s", field, eq); - return -EINVAL; - } - - if (!oom_score_adjust_is_valid(oa)) { - log_error("OOM score adjust value out of range"); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "i", oa); - } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - 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); - - p = eq; - - for (;;) { - _cleanup_free_ char *word = NULL; - int offset; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) { - log_error("Failed to parse %s value %s", field, eq); - return -EINVAL; - } - if (r == 0) - break; - - if (!utf8_is_valid(word)) { - log_error("Failed to parse %s value %s", field, eq); - return -EINVAL; - } - - offset = word[0] == '-'; - if (!path_is_absolute(word + offset)) { - log_error("Failed to parse %s value %s", field, eq); - return -EINVAL; - } - - path_kill_slashes(word + offset); - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else if (streq(field, "RuntimeDirectory")) { - const char *p; - - r = sd_bus_message_open_container(m, 'v', "as"); - 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); - - p = eq; - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse %s value %s", field, eq); - - if (r == 0) - break; - - r = sd_bus_message_append_basic(m, 's', word); - if (r < 0) - return bus_log_create_error(r); - } - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - - } else { - log_error("Unknown assignment %s.", assignment); - return -EINVAL; - } - -finish: - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); - - return 0; -} - -typedef struct BusWaitForJobs { - sd_bus *bus; - Set *jobs; - - char *name; - char *result; - - sd_bus_slot *slot_job_removed; - sd_bus_slot *slot_disconnected; -} BusWaitForJobs; - -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(sd_bus_message_get_bus(m)); - - return 0; -} - -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(m); - assert(d); - - r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result); - if (r < 0) { - bus_log_parse_error(r); - return 0; - } - - found = set_remove(d->jobs, (char*) path); - if (!found) - return 0; - - free(found); - - if (!isempty(result)) - d->result = strdup(result); - - if (!isempty(unit)) - d->name = strdup(unit); - - return 0; -} - -void bus_wait_for_jobs_free(BusWaitForJobs *d) { - if (!d) - return; - - set_free_free(d->jobs); - - sd_bus_slot_unref(d->slot_disconnected); - sd_bus_slot_unref(d->slot_job_removed); - - sd_bus_unref(d->bus); - - free(d->name); - free(d->result); - - free(d); -} - -int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) { - _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL; - int r; - - assert(bus); - assert(ret); - - d = new0(BusWaitForJobs, 1); - if (!d) - return -ENOMEM; - - d->bus = sd_bus_ref(bus); - - /* When we are a bus client we match by sender. Direct - * connections OTOH have no initialized sender field, and - * hence we ignore the sender then */ - r = sd_bus_add_match( - bus, - &d->slot_job_removed, - bus->bus_client ? - "type='signal'," - "sender='org.freedesktop.systemd1'," - "interface='org.freedesktop.systemd1.Manager'," - "member='JobRemoved'," - "path='/org/freedesktop/systemd1'" : - "type='signal'," - "interface='org.freedesktop.systemd1.Manager'," - "member='JobRemoved'," - "path='/org/freedesktop/systemd1'", - match_job_removed, d); - if (r < 0) - return r; - - r = sd_bus_add_match( - bus, - &d->slot_disconnected, - "type='signal'," - "sender='org.freedesktop.DBus.Local'," - "interface='org.freedesktop.DBus.Local'," - "member='Disconnected'", - match_disconnected, d); - if (r < 0) - return r; - - *ret = d; - d = NULL; - - return 0; -} - -static int bus_process_wait(sd_bus *bus) { - int r; - - for (;;) { - r = sd_bus_process(bus, NULL); - if (r < 0) - return r; - if (r > 0) - return 0; - - r = sd_bus_wait(bus, (uint64_t) -1); - if (r < 0) - return r; - } -} - -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, const char* const* extra_args) { - _cleanup_free_ char *service_shell_quoted = NULL; - const char *systemctl = "systemctl", *journalctl = "journalctl"; - - assert(service); - - service_shell_quoted = shell_maybe_quote(service); - - if (extra_args && extra_args[1]) { - _cleanup_free_ char *t; - - t = strv_join((char**) extra_args, " "); - systemctl = strjoina("systemctl ", t ? : ""); - journalctl = strjoina("journalctl ", t ? : ""); - } - - 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.\n" - "See \"%s status %s\" and \"%s -xe\" for details.\n", - service, - explanations[i].explanation, - systemctl, - service_shell_quoted ?: "", - journalctl); - goto finish; - } - } - - log_error("Job for %s failed.\n" - "See \"%s status %s\" and \"%s -xe\" for details.\n", - service, - systemctl, - service_shell_quoted ?: "", - journalctl); - -finish: - /* For some results maybe additional explanation is required */ - if (streq_ptr(result, "start-limit")) - log_info("To force a start use \"%1$s reset-failed %2$s\"\n" - "followed by \"%1$s start %2$s\" again.", - systemctl, - service_shell_quoted ?: ""); -} - -static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) { - int r = 0; - - assert(d->result); - - if (!quiet) { - if (streq(d->result, "canceled")) - log_error("Job for %s canceled.", strna(d->name)); - else if (streq(d->result, "timeout")) - log_error("Job for %s timed out.", strna(d->name)); - else if (streq(d->result, "dependency")) - log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name)); - else if (streq(d->result, "invalid")) - log_error("%s is not active, cannot reload.", strna(d->name)); - else if (streq(d->result, "assert")) - log_error("Assertion failed on job for %s.", strna(d->name)); - else if (streq(d->result, "unsupported")) - 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) { - int q; - _cleanup_free_ char *result = NULL; - - 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_job_error_with_service_result(d->name, result, extra_args); - } else - log_error("Job failed. See \"journalctl -xe\" for details."); - } - } - - if (streq(d->result, "canceled")) - r = -ECANCELED; - else if (streq(d->result, "timeout")) - r = -ETIME; - else if (streq(d->result, "dependency")) - r = -EIO; - else if (streq(d->result, "invalid")) - r = -ENOEXEC; - else if (streq(d->result, "assert")) - r = -EPROTO; - else if (streq(d->result, "unsupported")) - r = -EOPNOTSUPP; - else if (!streq(d->result, "done") && !streq(d->result, "skipped")) - r = -EIO; - - return r; -} - -int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) { - int r = 0; - - assert(d); - - while (!set_isempty(d->jobs)) { - int q; - - q = bus_process_wait(d->bus); - if (q < 0) - return log_error_errno(q, "Failed to wait for response: %m"); - - if (d->result) { - q = check_wait_response(d, quiet, extra_args); - /* Return the first error as it is most likely to be - * meaningful. */ - if (q < 0 && r == 0) - r = q; - - log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name)); - } - - d->name = mfree(d->name); - d->result = mfree(d->result); - } - - return r; -} - -int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) { - int r; - - assert(d); - - r = set_ensure_allocated(&d->jobs, &string_hash_ops); - if (r < 0) - return r; - - return set_put_strdup(d->jobs, path); -} - -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, NULL); -} - -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; - - r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); - if (r < 0) - return bus_log_parse_error(r); - - while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) { - /* We expect only "success" changes to be sent over the bus. - Hence, reject anything negative. */ - UnitFileChangeType ch = unit_file_change_type_from_string(type); - - if (ch < 0) { - log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path); - continue; - } - - r = unit_file_changes_add(changes, n_changes, ch, path, source); - if (r < 0) - return r; - } - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(m); - if (r < 0) - return bus_log_parse_error(r); - - unit_file_dump_changes(0, NULL, *changes, *n_changes, false); - return 0; -} - /** * bus_path_encode_unique() - encode unique object path * @b: bus connection or NULL diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 1a0841ce81..d792258ecd 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -24,15 +24,12 @@ #include #include -#include "sd-bus-vtable.h" #include "sd-bus.h" #include "sd-event.h" #include "hashmap.h" -#include "install.h" #include "macro.h" #include "string-util.h" -#include "time-util.h" typedef enum BusTransport { BUS_TRANSPORT_LOCAL, @@ -126,22 +123,6 @@ assert_cc(sizeof(mode_t) == sizeof(uint32_t)); int bus_log_parse_error(int r); int bus_log_create_error(int r); -typedef struct UnitInfo { - const char *machine; - const char *id; - const char *description; - const char *load_state; - const char *active_state; - const char *sub_state; - const char *following; - const char *unit_path; - uint32_t job_id; - const char *job_type; - const char *job_path; -} UnitInfo; - -int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); - #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \ int function(sd_bus *bus, \ const char *path, \ @@ -173,20 +154,6 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \ SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags)) -int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment); - -typedef struct BusWaitForJobs BusWaitForJobs; - -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, const char* const* extra_args); -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, 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); -- cgit v1.2.3-54-g00ecf From f53d86c9295d9ac20981ca26beb6b83ad1f4296d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 17:49:31 +0200 Subject: machine-id-setup: explicitly fsync() the machine ID after writing As discussed here: https://github.com/systemd/systemd/issues/2619#issuecomment-184670042 Explicitly syncing /etc/machine-id after writing it, is probably a good idea, since it has a strong "commit" character and is generally a one-time thing. Fixes #2619. --- src/core/machine-id-setup.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 9de528b6cf..0145fe2894 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -101,14 +101,23 @@ static int read_machine_id(int fd, char id[34]) { return 0; } -static int write_machine_id(int fd, char id[34]) { +static int write_machine_id(int fd, const char id[34]) { + int r; + assert(fd >= 0); assert(id); if (lseek(fd, 0, SEEK_SET) < 0) return -errno; - return loop_write(fd, id, 33, false); + r = loop_write(fd, id, 33, false); + if (r < 0) + return r; + + if (fsync(fd) < 0) + return -errno; + + return 0; } static int generate_machine_id(char id[34], const char *root) { -- cgit v1.2.3-54-g00ecf From 3411372e35fd199d46910b79b8017e9e4ffc8da8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 18:12:57 +0200 Subject: tree-wide: don't assume CLOCK_BOOTIME is generally available Before we invoke now(CLOCK_BOOTTIME), let's make sure we actually have that clock, since now() will otherwise hit an assert. Specifically, let's refuse CLOCK_BOOTTIME early in sd-event if the kernel doesn't actually support it. This is a follow-up for #3037, and specifically: https://github.com/systemd/systemd/pull/3037#issuecomment-210199167 --- src/basic/time-util.c | 37 ++++++++++++++++++++++-------------- src/basic/time-util.h | 1 + src/core/timer.c | 2 +- src/libsystemd/sd-event/sd-event.c | 10 +++++++++- src/libsystemd/sd-event/test-event.c | 12 ++++++++---- 5 files changed, 42 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 7ca764abeb..edd9179cb8 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -1080,22 +1080,31 @@ bool timezone_is_valid(const char *name) { return true; } -clockid_t clock_boottime_or_monotonic(void) { - static clockid_t clock = -1; - int fd; - - if (clock != -1) - return clock; - - fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); - if (fd < 0) - clock = CLOCK_MONOTONIC; - else { - safe_close(fd); - clock = CLOCK_BOOTTIME; +bool clock_boottime_supported(void) { + static int supported = -1; + + /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */ + + if (supported < 0) { + int fd; + + fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) + supported = false; + else { + safe_close(fd); + supported = true; + } } - return clock; + return supported; +} + +clockid_t clock_boottime_or_monotonic(void) { + if (clock_boottime_supported()) + return CLOCK_BOOTTIME; + else + return CLOCK_MONOTONIC; } int get_timezone(char **tz) { diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 77e3cd08d4..a5e3f567ec 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -112,6 +112,7 @@ bool ntp_synced(void); int get_timezones(char ***l); bool timezone_is_valid(const char *name); +bool clock_boottime_supported(void); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) \ diff --git a/src/core/timer.c b/src/core/timer.c index b286b714fa..f8f5f4b2e4 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -373,7 +373,7 @@ static void timer_enter_waiting(Timer *t, bool initial) { * rather than the monotonic clock. */ ts_realtime = now(CLOCK_REALTIME); - ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC); + ts_monotonic = now(t->wake_system ? clock_boottime_or_monotonic() : CLOCK_MONOTONIC); t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0; LIST_FOREACH(value, v, t->values) { diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 79b98c293c..7ba6527f63 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -1072,6 +1072,10 @@ _public_ int sd_event_add_time( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && + !clock_boottime_supported()) + return -EOPNOTSUPP; + if (!callback) callback = time_exit_callback; @@ -2527,7 +2531,8 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { } dual_timestamp_get(&e->timestamp); - e->timestamp_boottime = now(clock_boottime_or_monotonic()); + if (clock_boottime_supported()) + e->timestamp_boottime = now(CLOCK_BOOTTIME); for (i = 0; i < m; i++) { @@ -2761,6 +2766,9 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP); + if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported()) + return -EOPNOTSUPP; + if (!dual_timestamp_is_set(&e->timestamp)) { /* Implicitly fall back to now() if we never ran * before and thus have no cached time. */ diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index fd31588b8f..289114490c 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -270,8 +270,10 @@ static void test_sd_event_now(void) { assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0); - assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0); - assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0); + if (clock_boottime_supported()) { + assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0); + assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0); + } assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP); assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP); @@ -280,8 +282,10 @@ static void test_sd_event_now(void) { assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0); assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0); assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0); - assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0); - assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0); + if (clock_boottime_supported()) { + assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0); + assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0); + } assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP); assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP); } -- cgit v1.2.3-54-g00ecf From 8f1e0ad415dab8f3e5d301129fe2bb25c420e66f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 18:20:51 +0200 Subject: path-lookup: optimize a common strv copy operation away Follow-up for: https://github.com/systemd/systemd/pull/3033#discussion_r59689398 --- src/shared/path-lookup.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 80a2ea7940..ca593b6963 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -586,9 +586,16 @@ int lookup_paths_init( if (!add) return -ENOMEM; - r = strv_extend_strv(&paths, add, true); - if (r < 0) + if (paths) { + r = strv_extend_strv(&paths, add, true); + if (r < 0) return r; + } else { + /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it, + * and don't have to copy anything */ + paths = add; + add = NULL; + } } r = patch_root_prefix(&persistent_config, root); -- cgit v1.2.3-54-g00ecf From f8591ee1b6c152055feed7a872159e67859fd83d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 18:28:32 +0200 Subject: systemctl: add two minor assert()s --- src/systemctl/systemctl.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9c59fcf610..595d6853c6 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -325,6 +325,8 @@ static int compare_unit_info(const void *a, const void *b) { } static bool output_show_unit(const UnitInfo *u, char **patterns) { + assert(u); + if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE)) return false; @@ -1281,6 +1283,8 @@ static int compare_unit_file_list(const void *a, const void *b) { } static bool output_show_unit_file(const UnitFileList *u, char **patterns) { + assert(u); + if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE)) return false; -- cgit v1.2.3-54-g00ecf From 03532f0ae0fae40f9f04091340e2bf156d0ec21a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 19:27:32 +0200 Subject: coredump,basic: generalize O_TMPFILE handling a bit This moves the O_TMPFILE handling from the coredumping code into common library code, and generalizes it as open_tmpfile_linkable() + link_tmpfile(). The existing open_tmpfile() function (which creates an unlinked temporary file that cannot be linked into the fs) is renamed to open_tmpfile_unlinkable(), to make the distinction clear. Thus, code may now choose between: a) open_tmpfile_linkable() + link_tmpfile() b) open_tmpfile_unlinkable() Depending on whether they want a file that may be linked back into the fs later on or not. In a later commit we should probably convert fopen_temporary() to make use of open_tmpfile_linkable(). Followup for: #3065 --- src/basic/fileio.c | 124 +++++++++++++++++++++++++++------- src/basic/fileio.h | 6 +- src/core/manager.c | 2 +- src/coredump/coredump.c | 54 +++------------ src/journal-remote/journal-gatewayd.c | 4 +- src/journal/journal-send.c | 2 +- src/journal/journal-verify.c | 6 +- src/test/test-tmpfiles.c | 26 +++++-- 8 files changed, 146 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 69590941e5..2a9b6e46ad 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1083,30 +1083,6 @@ int mkostemp_safe(char *pattern, int flags) { return fd; } -int open_tmpfile(const char *path, int flags) { - char *p; - int fd; - - assert(path); - -#ifdef O_TMPFILE - /* Try O_TMPFILE first, if it is supported */ - fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); - if (fd >= 0) - return fd; -#endif - - /* Fall back to unguessable name + unlinking */ - p = strjoina(path, "/systemd-tmp-XXXXXX"); - - fd = mkostemp_safe(p, flags); - if (fd < 0) - return fd; - - unlink(p); - return fd; -} - int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { const char *fn; char *t; @@ -1278,3 +1254,103 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) return fputs(s, f); } + +int open_tmpfile_unlinkable(const char *directory, int flags) { + char *p; + int fd; + + assert(directory); + + /* Returns an unlinked temporary file that cannot be linked into the file system anymore */ + +#ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ + fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + + /* Fall back to unguessable name + unlinking */ + p = strjoina(directory, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, flags); + if (fd < 0) + return fd; + + (void) unlink(p); + + return fd; +} + +int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { + _cleanup_free_ char *tmp = NULL; + int r, fd; + + assert(target); + assert(ret_path); + + /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */ + assert((flags & O_EXCL) == 0); + + /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in + * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in + * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */ + +#ifdef O_TMPFILE + { + _cleanup_free_ char *dn = NULL; + + dn = dirname_malloc(target); + if (!dn) + return -ENOMEM; + + fd = open(dn, O_TMPFILE|flags, 0640); + if (fd >= 0) { + *ret_path = NULL; + return fd; + } + + log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn); + } +#endif + + r = tempfn_random(target, NULL, &tmp); + if (r < 0) + return r; + + fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640); + if (fd < 0) + return -errno; + + *ret_path = tmp; + tmp = NULL; + + return fd; +} + +int link_tmpfile(int fd, const char *path, const char *target) { + + assert(fd >= 0); + assert(target); + + /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd + * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported + * on the directory, and renameat2() is used instead. + * + * Note that in both cases we will not replace existing files. This is because linkat() dos not support this + * operation currently (renameat2() does), and there is no nice way to emulate this. */ + + if (path) { + if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0) + return -errno; + } else { + char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; + + xsprintf(proc_fd_path, "/proc/self/fd/%i", fd); + + if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0) + return -errno; + } + + return 0; +} diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 8084895ff3..58dbc80c24 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -72,7 +72,6 @@ int fflush_and_check(FILE *f); int fopen_temporary(const char *path, FILE **_f, char **_temp_path); int mkostemp_safe(char *pattern, int flags); -int open_tmpfile(const char *path, int flags); int tempfn_xxxxxx(const char *p, const char *extra, char **ret); int tempfn_random(const char *p, const char *extra, char **ret); @@ -82,3 +81,8 @@ int write_timestamp_file_atomic(const char *fn, usec_t n); int read_timestamp_file(const char *fn, usec_t *ret); int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space); + +int open_tmpfile_unlinkable(const char *directory, int flags); +int open_tmpfile_linkable(const char *target, int flags, char **ret_path); + +int link_tmpfile(int fd, const char *path, const char *target); diff --git a/src/core/manager.c b/src/core/manager.c index 5601770670..bd00c224f4 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2191,7 +2191,7 @@ int manager_open_serialization(Manager *m, FILE **_f) { assert(_f); path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp"; - fd = open_tmpfile(path, O_RDWR|O_CLOEXEC); + fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC); if (fd < 0) return -errno; diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 2bbb958861..41fc1993d5 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -224,6 +224,8 @@ static int fix_permissions( const char *context[_CONTEXT_MAX], uid_t uid) { + int r; + assert(fd >= 0); assert(target); assert(context); @@ -236,18 +238,9 @@ static int fix_permissions( if (fsync(fd) < 0) return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename)); - if (filename) { - if (rename(filename, target) < 0) - return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target); - } else { - _cleanup_free_ char *proc_fd_path = NULL; - - if (asprintf(&proc_fd_path, "/proc/self/fd/%d", fd) < 0) - return log_oom(); - - if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0) - return log_error_errno(errno, "Failed to create coredump %s: %m", target); - } + r = link_tmpfile(fd, filename, target); + if (r < 0) + return log_error_errno(r, "Failed to move coredump %s into place: %m", target); return 0; } @@ -308,33 +301,6 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { return 0; } -static int open_coredump_tmpfile(const char *target, char **ret_filename) { - _cleanup_free_ char *tmp = NULL; - int fd; - int r; - - assert(target); - assert(ret_filename); - - fd = open("/var/lib/systemd/coredump", O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0640); - if (fd < 0) { - log_debug_errno(errno, "Failed to use O_TMPFILE: %m"); - - r = tempfn_random(target, NULL, &tmp); - if (r < 0) - return log_error_errno(r, "Failed to determine temporary file name: %m"); - - fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640); - if (fd < 0) - return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp); - } - - *ret_filename = tmp; - tmp = NULL; - - return fd; -} - static int save_external_coredump( const char *context[_CONTEXT_MAX], int input_fd, @@ -378,9 +344,9 @@ static int save_external_coredump( mkdir_p_label("/var/lib/systemd/coredump", 0755); - fd = open_coredump_tmpfile(fn, &tmp); + fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp); if (fd < 0) - return fd; + return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn); r = copy_bytes(input_fd, fd, max_size, false); if (r == -EFBIG) { @@ -418,9 +384,11 @@ static int save_external_coredump( goto uncompressed; } - fd_compressed = open_coredump_tmpfile(fn_compressed, &tmp_compressed); - if (fd_compressed < 0) + fd_compressed = open_tmpfile_linkable(fn_compressed, O_RDWR|O_CLOEXEC, &tmp_compressed); + if (fd_compressed < 0) { + log_error_errno(fd_compressed, "Failed to create temporary file for coredump %s: %m", fn_compressed); goto uncompressed; + } r = compress_stream(fd, fd_compressed, -1); if (r < 0) { diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 60d897758b..4ad9184993 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -122,12 +122,14 @@ static int open_journal(RequestMeta *m) { } static int request_meta_ensure_tmp(RequestMeta *m) { + assert(m); + if (m->tmp) rewind(m->tmp); else { int fd; - fd = open_tmpfile("/tmp", O_RDWR|O_CLOEXEC); + fd = open_tmpfile_unlinkable("/tmp", O_RDWR|O_CLOEXEC); if (fd < 0) return fd; diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index a79846146a..f0959b6237 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -316,7 +316,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { buffer_fd = memfd_new(NULL); if (buffer_fd < 0) { if (buffer_fd == -ENOSYS) { - buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC); + buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC); if (buffer_fd < 0) return buffer_fd; diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index a1241c9bcf..26572ddd76 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -838,19 +838,19 @@ int journal_file_verify( } else if (f->seal) return -ENOKEY; - data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); + data_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC); if (data_fd < 0) { r = log_error_errno(data_fd, "Failed to create data file: %m"); goto fail; } - entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); + entry_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_fd < 0) { r = log_error_errno(entry_fd, "Failed to create entry file: %m"); goto fail; } - entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); + entry_array_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_array_fd < 0) { r = log_error_errno(entry_array_fd, "Failed to create entry array file: %m"); diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index d7223dd2bf..8fda0904f3 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -32,15 +32,17 @@ #include "util.h" int main(int argc, char** argv) { + _cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL; + _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; const char *p = argv[1] ?: "/tmp"; - char *pattern = strjoina(p, "/systemd-test-XXXXXX"); - _cleanup_close_ int fd, fd2; - _cleanup_free_ char *cmd, *cmd2, *ans, *ans2; + char *pattern; log_set_max_level(LOG_DEBUG); log_parse_environment(); - fd = open_tmpfile(p, O_RDWR|O_CLOEXEC); + pattern = strjoina(p, "/systemd-test-XXXXXX"); + + fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0); @@ -59,5 +61,21 @@ int main(int argc, char** argv) { log_debug("link2: %s", ans2); assert_se(endswith(ans2, " (deleted)")); + pattern = strjoina(p, "/tmpfiles-test"); + assert_se(tempfn_random(pattern, NULL, &d) >= 0); + + fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp); + assert_se(fd >= 0); + assert_se(write(fd, "foobar\n", 7) == 7); + + assert_se(touch(d) >= 0); + assert_se(link_tmpfile(fd, tmp, d) == -EEXIST); + assert_se(unlink(d) >= 0); + assert_se(link_tmpfile(fd, tmp, d) >= 0); + + assert_se(read_one_line_file(d, &line) >= 0); + assert_se(streq(line, "foobar")); + assert_se(unlink(d) >= 0); + return 0; } -- cgit v1.2.3-54-g00ecf From 766cd081525575875dd1291d4de0e65bcb5e1a89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 19:37:46 +0200 Subject: shared: move output_mode_to_string() into output-mode.c After all, the enum definition is in output-mode.h --- Makefile.am | 1 + src/shared/logs-show.c | 15 --------------- src/shared/logs-show.h | 3 --- src/shared/output-mode.c | 36 ++++++++++++++++++++++++++++++++++++ src/shared/output-mode.h | 5 +++++ 5 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 src/shared/output-mode.c (limited to 'src') diff --git a/Makefile.am b/Makefile.am index b0118fd9a5..0f475c6d09 100644 --- a/Makefile.am +++ b/Makefile.am @@ -962,6 +962,7 @@ noinst_LTLIBRARIES += \ libshared_la_SOURCES = \ src/shared/output-mode.h \ + src/shared/output-mode.c \ src/shared/gpt.h \ src/shared/udev-util.h \ src/shared/linux/auto_dev-ioctl.h \ diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 15c818ccf1..895223a4d9 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -1292,18 +1292,3 @@ int show_journal_by_unit( return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized); } - -static const char *const output_mode_table[_OUTPUT_MODE_MAX] = { - [OUTPUT_SHORT] = "short", - [OUTPUT_SHORT_ISO] = "short-iso", - [OUTPUT_SHORT_PRECISE] = "short-precise", - [OUTPUT_SHORT_MONOTONIC] = "short-monotonic", - [OUTPUT_VERBOSE] = "verbose", - [OUTPUT_EXPORT] = "export", - [OUTPUT_JSON] = "json", - [OUTPUT_JSON_PRETTY] = "json-pretty", - [OUTPUT_JSON_SSE] = "json-sse", - [OUTPUT_CAT] = "cat" -}; - -DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode); diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h index 9765a24ff2..6643440881 100644 --- a/src/shared/logs-show.h +++ b/src/shared/logs-show.h @@ -68,6 +68,3 @@ void json_escape( const char* p, size_t l, OutputFlags flags); - -const char* output_mode_to_string(OutputMode m) _const_; -OutputMode output_mode_from_string(const char *s) _pure_; diff --git a/src/shared/output-mode.c b/src/shared/output-mode.c new file mode 100644 index 0000000000..be6281bd3f --- /dev/null +++ b/src/shared/output-mode.c @@ -0,0 +1,36 @@ +/*** + 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 . +***/ + +#include "output-mode.h" +#include "string-table.h" + +static const char *const output_mode_table[_OUTPUT_MODE_MAX] = { + [OUTPUT_SHORT] = "short", + [OUTPUT_SHORT_ISO] = "short-iso", + [OUTPUT_SHORT_PRECISE] = "short-precise", + [OUTPUT_SHORT_MONOTONIC] = "short-monotonic", + [OUTPUT_VERBOSE] = "verbose", + [OUTPUT_EXPORT] = "export", + [OUTPUT_JSON] = "json", + [OUTPUT_JSON_PRETTY] = "json-pretty", + [OUTPUT_JSON_SSE] = "json-sse", + [OUTPUT_CAT] = "cat" +}; + +DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode); diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h index e2b26e04d3..ea2e95f06b 100644 --- a/src/shared/output-mode.h +++ b/src/shared/output-mode.h @@ -19,6 +19,8 @@ along with systemd; If not, see . ***/ +#include "macro.h" + typedef enum OutputMode { OUTPUT_SHORT, OUTPUT_SHORT_ISO, @@ -48,3 +50,6 @@ typedef enum OutputFlags { OUTPUT_UTC = 1 << 7, OUTPUT_KERNEL_THREADS = 1 << 8, } OutputFlags; + +const char* output_mode_to_string(OutputMode m) _const_; +OutputMode output_mode_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From bb321ed9a33d6c90e2529db86ffabd913805088a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 19:46:37 +0200 Subject: journalctl: add output mode where time is shown in seconds since 1st Jan 1970 UTC aka "UNIX time". Fixes: #2120 --- man/journalctl.xml | 10 ++++++++++ src/shared/logs-show.c | 13 ++++++++++--- src/shared/output-mode.c | 1 + src/shared/output-mode.h | 1 + 4 files changed, 22 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/man/journalctl.xml b/man/journalctl.xml index 7a634879cc..c448e0771b 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -270,6 +270,16 @@ + + + + + + is very similar, but shows seconds passed since January 1st 1970 UTC instead of wallclock + timestamps ("UNIX time"). The time is shown with microsecond accuracy. + + + diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 895223a4d9..5cfa455e05 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -344,16 +344,22 @@ static int output_short( t = (time_t) (x / USEC_PER_SEC); - switch(mode) { + switch (mode) { + + case OUTPUT_SHORT_UNIX: + r = snprintf(buf, sizeof(buf), "%10llu.%06llu", (unsigned long long) t, (unsigned long long) (x % USEC_PER_SEC)); + break; + case OUTPUT_SHORT_ISO: r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)); break; + case OUTPUT_SHORT_PRECISE: r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)); if (r > 0) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - ".%06llu", (unsigned long long) (x % USEC_PER_SEC)); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%06llu", (unsigned long long) (x % USEC_PER_SEC)); break; + default: r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)); } @@ -894,6 +900,7 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])( [OUTPUT_SHORT_ISO] = output_short, [OUTPUT_SHORT_PRECISE] = output_short, [OUTPUT_SHORT_MONOTONIC] = output_short, + [OUTPUT_SHORT_UNIX] = output_short, [OUTPUT_VERBOSE] = output_verbose, [OUTPUT_EXPORT] = output_export, [OUTPUT_JSON] = output_json, diff --git a/src/shared/output-mode.c b/src/shared/output-mode.c index be6281bd3f..bec53ee0ae 100644 --- a/src/shared/output-mode.c +++ b/src/shared/output-mode.c @@ -25,6 +25,7 @@ static const char *const output_mode_table[_OUTPUT_MODE_MAX] = { [OUTPUT_SHORT_ISO] = "short-iso", [OUTPUT_SHORT_PRECISE] = "short-precise", [OUTPUT_SHORT_MONOTONIC] = "short-monotonic", + [OUTPUT_SHORT_UNIX] = "short-unix", [OUTPUT_VERBOSE] = "verbose", [OUTPUT_EXPORT] = "export", [OUTPUT_JSON] = "json", diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h index ea2e95f06b..56fd3ba8e3 100644 --- a/src/shared/output-mode.h +++ b/src/shared/output-mode.h @@ -26,6 +26,7 @@ typedef enum OutputMode { OUTPUT_SHORT_ISO, OUTPUT_SHORT_PRECISE, OUTPUT_SHORT_MONOTONIC, + OUTPUT_SHORT_UNIX, OUTPUT_VERBOSE, OUTPUT_EXPORT, OUTPUT_JSON, -- cgit v1.2.3-54-g00ecf From 991e274b61f489e625274254138567c9c81b4c4b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 20:09:57 +0200 Subject: journalctl: add --no-hostname switch This suppresses output of the hostname for messages from the local system. Fixes: #2342 --- man/journalctl.xml | 7 +++++++ src/journal/journalctl.c | 11 ++++++++++- src/shared/logs-show.c | 6 ++++++ src/shared/output-mode.h | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/man/journalctl.xml b/man/journalctl.xml index c448e0771b..3efe6ef62a 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -359,6 +359,13 @@ (UTC). + + + + Don't show the hostname field of log messages originating from the local host. This switch only + has an effect on the family of output modes (see above). + + diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index fd2cb99410..c9a2c3812d 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -95,6 +95,7 @@ static bool arg_boot = false; static sd_id128_t arg_boot_id = {}; static int arg_boot_offset = 0; static bool arg_dmesg = false; +static bool arg_no_hostname = false; static const char *arg_cursor = NULL; static const char *arg_after_cursor = NULL; static bool arg_show_cursor = false; @@ -304,6 +305,7 @@ static void help(void) { " -a --all Show all fields, including long and unprintable\n" " -q --quiet Do not show info messages and privilege warning\n" " --no-pager Do not pipe output into a pager\n" + " --no-hostname Suppress output of hostname field\n" " -m --merge Show entries from all available journals\n" " -D --directory=PATH Show journal files from directory\n" " --file=PATH Show journal file\n" @@ -370,6 +372,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VACUUM_SIZE, ARG_VACUUM_FILES, ARG_VACUUM_TIME, + ARG_NO_HOSTNAME, }; static const struct option options[] = { @@ -427,6 +430,7 @@ static int parse_argv(int argc, char *argv[]) { { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME }, + { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME }, {} }; @@ -780,6 +784,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_LIST_FIELD_NAMES; break; + case ARG_NO_HOSTNAME: + arg_no_hostname = true; + break; + case 'x': arg_catalog = true; break; @@ -2444,7 +2452,8 @@ int main(int argc, char *argv[]) { arg_full * OUTPUT_FULL_WIDTH | colors_enabled() * OUTPUT_COLOR | arg_catalog * OUTPUT_CATALOG | - arg_utc * OUTPUT_UTC; + arg_utc * OUTPUT_UTC | + arg_no_hostname * OUTPUT_NO_HOSTNAME; r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized); need_seek = true; diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 5cfa455e05..cd3d53669c 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -373,6 +373,12 @@ static int output_short( n += strlen(buf); } + if (hostname && (flags & OUTPUT_NO_HOSTNAME)) { + /* Suppress display of the hostname if this is requested. */ + hostname = NULL; + hostname_len = 0; + } + if (hostname && shall_print(hostname, hostname_len, flags)) { fprintf(f, " %.*s", (int) hostname_len, hostname); n += hostname_len + 1; diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h index 56fd3ba8e3..f37189e57f 100644 --- a/src/shared/output-mode.h +++ b/src/shared/output-mode.h @@ -50,6 +50,7 @@ typedef enum OutputFlags { OUTPUT_BEGIN_NEWLINE = 1 << 6, OUTPUT_UTC = 1 << 7, OUTPUT_KERNEL_THREADS = 1 << 8, + OUTPUT_NO_HOSTNAME = 1 << 9, } OutputFlags; const char* output_mode_to_string(OutputMode m) _const_; -- cgit v1.2.3-54-g00ecf From 5bda1f47b3f4b91e55df2f5a773fc83d3e7bf4fd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 17:14:30 +0200 Subject: machinectl: fix misplaced newline in --help output --- src/machine/machinectl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index c370ed57ec..c9d41268c6 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2439,8 +2439,8 @@ static int help(int argc, char *argv[], void *userdata) { " rename NAME NAME Rename an image\n" " read-only NAME [BOOL] Mark or unmark image read-only\n" " remove NAME... Remove an image\n" - " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n" - " clean Remove hidden (or all) images\n" + " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n" + " clean Remove hidden (or all) images\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" -- cgit v1.2.3-54-g00ecf From aea529e5b2c864d536941ee18220abcc1a9015a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 17:30:08 +0200 Subject: core: don't dispatch load queue when setting Slice= for transient units Let's be more careful when setting up the Slice= property of transient units: let's use manager_load_unit_prepare() instead of manager_load_unit(), so that the load queue isn't dispatched right away, because our own transient unit is in it, and we don#t want to have it loaded until we finished initializing it. --- src/core/dbus-unit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index c507265070..1f0bc3a386 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1099,7 +1099,10 @@ static int bus_unit_set_transient_property( if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s); - r = manager_load_unit(u->manager, s, NULL, error, &slice); + /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be + * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare() + * instead of manager_load_unit() on purpose, here. */ + r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 37e605f934892bf7458eecaeb01fc682e33cc2ad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 17:31:40 +0200 Subject: run: make --slice= work in conjunction with --scope Fixes: #2991 --- src/run/run.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/run/run.c b/src/run/run.c index 1993a424ca..ff94ac7b11 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -620,6 +620,10 @@ static int transient_scope_set_properties(sd_bus_message *m) { if (r < 0) return r; + r = transient_cgroup_set_properties(m); + if (r < 0) + return r; + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid()); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 9ba37525d0ef3d144a50ed5fd4710573e92b7ec1 Mon Sep 17 00:00:00 2001 From: Klearchos Chaloulos Date: Fri, 22 Apr 2016 21:04:17 +0300 Subject: journal-remote : Ensure reallocation of source->buf does not result in source->size < source->filled (#3086) While the function journal-remote-parse.c:get_line() enforces an assertion that source->filled <= source->size, in function journal-remote-parse.c:process_source() there is a chance that source->size will be decreased to a lower value than source->filled, when source->buf is reallocated. Therefore a check is added that ensures that source->buf is reallocated only when source->filled is smaller than target / 2. --- src/journal-remote/journal-remote-parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c index 3864647eb7..9ba9ee3fc0 100644 --- a/src/journal-remote/journal-remote-parse.c +++ b/src/journal-remote/journal-remote-parse.c @@ -485,7 +485,7 @@ int process_source(RemoteSource *source, bool compress, bool seal) { } target = source->size; - while (target > 16 * LINE_CHUNK && remain < target / 2) + while (target > 16 * LINE_CHUNK && source->filled < target / 2) target /= 2; if (target < source->size) { char *tmp; -- cgit v1.2.3-54-g00ecf From 0f5e13822d5b89fd36103093daf69af952bf0703 Mon Sep 17 00:00:00 2001 From: "Thomas H. P. Andersen" Date: Sat, 23 Apr 2016 02:49:07 +0200 Subject: tree-wide: remove unused variables (#3098) --- src/core/dbus-unit.c | 1 - src/nspawn/nspawn.c | 2 +- src/test/test-tmpfiles.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 5c9d32438c..abe30413c3 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -936,7 +936,6 @@ static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) { int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(set_freep) Set *pids = NULL; - _cleanup_free_ char *p = NULL; Unit *u = userdata; pid_t pid; int r; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 44dce471e7..e1d37d383a 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1376,7 +1376,7 @@ static int setup_hostname(void) { static int setup_journal(const char *directory) { sd_id128_t this_id; - _cleanup_free_ char *b = NULL, *d = NULL; + _cleanup_free_ char *d = NULL; const char *p, *q; bool try; char id[33]; diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index 8fda0904f3..b34ebeefb2 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -33,7 +33,7 @@ int main(int argc, char** argv) { _cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL; - _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; + _cleanup_close_ int fd = -1, fd2 = -1; const char *p = argv[1] ?: "/tmp"; char *pattern; -- cgit v1.2.3-54-g00ecf From 368d264387879f486593d1f3e157f5456893d889 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 23 Apr 2016 03:01:55 +0200 Subject: machinectl: don't parse command line switches after "shell" verb (#3095) Fixes: #2420 --- src/machine/machinectl.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 1ce23f1c1d..b03198bbf1 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2509,12 +2509,39 @@ static int parse_argv(int argc, char *argv[]) { {} }; + bool reorder = false; int c, r; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0) + for (;;) { + const char *option_string; + + if (reorder) + option_string = "hp:als:H:M:qn:o:"; + else + option_string = "+hp:als:H:M:qn:o:"; + + c = getopt_long(argc, argv, option_string, options, NULL); + if (c < 0) { + /* We generally are fine with the fact that getopt_long() reorders the command line, and looks + * for switches after the main verb. However, for "shell" we really don't want that, since we + * want that switches passed after that are passed to the program to execute, and not processed + * by us. To make this possible, we'll first invoke getopt_long() with reordering disabled + * (i.e. with the "+" prefix in the option string), and as soon as we hit the end (i.e. the + * verb) we check if that's "shell". If it is, we exit the loop, since we don't want any + * further options processed. However, if it is anything else, we process the same argument + * again, but this time allow reordering. */ + + if (!reorder && optind < argc && !streq(argv[optind], "shell")) { + reorder = true; + optind--; + continue; + } + + break; + } switch (c) { @@ -2650,6 +2677,7 @@ static int parse_argv(int argc, char *argv[]) { default: assert_not_reached("Unhandled option"); } + } return 1; } -- cgit v1.2.3-54-g00ecf From cacc1dbf17e839a8a10ee3c43c2bb2bf8bda7642 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Mon, 25 Apr 2016 12:37:10 +0530 Subject: networkd: Fix route properties. We are not able to add multiple properties. wlp3s0.network: [Match] Name=wlp3s0 [Route] Gateway=10.68.5.26 Metric=10 sudo ./systemd-networkd Failed to parse file '/usr/lib/systemd/network/wlp3s0.network': File exists Could not load configuration files: File exists This patch fixes it. --- src/network/networkd-route.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index ab9b777d9a..bda2707e6d 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -68,15 +68,15 @@ int route_new_static(Network *network, unsigned section, Route **ret) { route->protocol = RTPROT_STATIC; if (section) { + route->section = section; + r = hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route); if (r < 0) return r; - - route->section = section; } - LIST_PREPEND(routes, network->static_routes, route); route->network = network; + LIST_PREPEND(routes, network->static_routes, route); *ret = route; route = NULL; -- cgit v1.2.3-54-g00ecf From 5215524dbe4d64ddbfdce52ca9d1b24b7d34dc5b Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Mon, 25 Apr 2016 12:38:56 +0530 Subject: networkd: Address- initialize the node before adding to list. It make more sense to initalize the node first then we add to the list. --- src/network/networkd-address.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 7f9a7268cc..429319da6b 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -67,16 +67,15 @@ int address_new_static(Network *network, unsigned section, Address **ret) { if (r < 0) return r; - address->network = network; - - LIST_APPEND(addresses, network->static_addresses, address); - if (section) { address->section = section; hashmap_put(network->addresses_by_section, UINT_TO_PTR(address->section), address); } + address->network = network; + LIST_APPEND(addresses, network->static_addresses, address); + *ret = address; address = NULL; -- cgit v1.2.3-54-g00ecf From 430fbf8e7ff4368f6d43a8f86e0bc6494b0a979c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 00:18:27 +0200 Subject: journal: add inotify watches by-fd instead of by-path This is slightly nicer, since we actually watch the directories we opened and enumerate. However, primarily this is preparation for adding support for opening journal files by fd without specifying any path, to be added in a later commit. --- src/basic/fs-util.c | 15 +++++++++++++++ src/basic/fs-util.h | 2 ++ src/journal/sd-journal.c | 10 +++++----- 3 files changed, 22 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 51268828af..e24e7036f7 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -38,6 +38,7 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -493,3 +494,17 @@ int get_files_in_directory(const char *path, char ***list) { return n; } + +int inotify_add_watch_fd(int fd, int what, uint32_t mask) { + char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + int r; + + /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */ + xsprintf(path, "/proc/self/fd/%i", what); + + r = inotify_add_watch(fd, path, mask); + if (r < 0) + return -errno; + + return r; +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 0d23f8635f..517b599d6f 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -72,3 +72,5 @@ union inotify_event_buffer { struct inotify_event ev; uint8_t raw[INOTIFY_EVENT_MAX]; }; + +int inotify_add_watch_fd(int fd, int what, uint32_t mask); diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 3c21d4129e..7ae8941a5e 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1420,10 +1420,10 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) if (m->wd <= 0 && j->inotify_fd >= 0) { - m->wd = inotify_add_watch(j->inotify_fd, m->path, - IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| - IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM| - IN_ONLYDIR); + m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d), + IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| + IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM| + IN_ONLYDIR); if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0) inotify_rm_watch(j->inotify_fd, m->wd); @@ -1505,7 +1505,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { if (m->wd <= 0 && j->inotify_fd >= 0) { - m->wd = inotify_add_watch(j->inotify_fd, m->path, + m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d), IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| IN_ONLYDIR); -- cgit v1.2.3-54-g00ecf From f63772613098f57fdeeef603791e9d5faa4f0790 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 00:23:45 +0200 Subject: sd-journal: properly collect errors from readdir() Let's also collect errors returned by readdir() into our set of errors, like we do this for all other errors from journal files. --- src/journal/sd-journal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 7ae8941a5e..44bf8ab511 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1429,7 +1429,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) inotify_rm_watch(j->inotify_fd, m->wd); } - FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { + FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) { if (dirent_is_file_with_suffix(de, ".journal") || dirent_is_file_with_suffix(de, ".journal~")) @@ -1516,7 +1516,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { if (j->no_new_files) return 0; - FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { + FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) { sd_id128_t id; if (dirent_is_file_with_suffix(de, ".journal") || -- cgit v1.2.3-54-g00ecf From 0f7488722d9ef97cb5d036575f4c312a00bb702f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 00:25:04 +0200 Subject: journalctl: improve error message when we have trouble reading journal files Let's output the actual error code encountered, and let's not claim this was purely triggered by files, because it can also be triggered by directories. --- src/journal/journalctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index c9a2c3812d..dcd709bd79 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1847,7 +1847,7 @@ static int access_check(sd_journal *j) { break; default: - log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path); + log_warning_errno(err, "An error was encountered while opening journal file or directory %s, ignoring file: %m", path); break; } } -- cgit v1.2.3-54-g00ecf From cb306f5d500b6cf8e4367a847aa96ff764ad3aff Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 00:26:41 +0200 Subject: sd-journal: minor simplification --- src/journal/sd-journal.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 44bf8ab511..5104bc3e01 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1614,13 +1614,7 @@ static int allocate_inotify(sd_journal *j) { return -errno; } - if (!j->directories_by_wd) { - j->directories_by_wd = hashmap_new(NULL); - if (!j->directories_by_wd) - return -ENOMEM; - } - - return 0; + return hashmap_ensure_allocated(&j->directories_by_wd, NULL); } static sd_journal *journal_new(int flags, const char *path) { -- cgit v1.2.3-54-g00ecf From 6402d5c628f1872a4874508bbe975aaac1cc747b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Apr 2016 12:47:36 +0200 Subject: util: copy_file_range() returns EBADF when used on a tty In nspawn we invoke copy_bytes() on a TTY fd. copy_file_range() returns EBADF on a TTY and this error is considered fatal by copy_bytes() so far. Correct that, so that nspawn's copy_bytes() operation works again. This is a follow-up for a44202e98b638024c45e50ad404c7069c7835c04. --- src/basic/copy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index e2db4be9ff..03487a6878 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -102,7 +102,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { if (try_cfr) { n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u); if (n < 0) { - if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV)) + if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF)) return n; try_cfr = false; -- cgit v1.2.3-54-g00ecf From 7336138eedf1c9b09b432428c4cccc2da25ab9e0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Apr 2016 22:53:39 +0200 Subject: nspawn: optionally fix up OS tree uid/gids for userns This adds a new --private-userns-chown switch that may be used in combination with --private-userns. If it is passed a recursive chmod() operation is run on the OS tree, fixing all file owner UID/GIDs to the right ranges. This should make user namespacing pretty workable, as the OS trees don't need to be prepared manually anymore. --- .gitignore | 1 + Makefile.am | 13 ++ src/nspawn/nspawn-patch-uid.c | 417 ++++++++++++++++++++++++++++++++++++++++++ src/nspawn/nspawn-patch-uid.h | 23 +++ src/nspawn/nspawn.c | 47 ++++- src/nspawn/test-patch-uid.c | 61 ++++++ 6 files changed, 560 insertions(+), 2 deletions(-) create mode 100644 src/nspawn/nspawn-patch-uid.c create mode 100644 src/nspawn/nspawn-patch-uid.h create mode 100644 src/nspawn/test-patch-uid.c (limited to 'src') diff --git a/.gitignore b/.gitignore index 02ba86ef6f..c7eb14452d 100644 --- a/.gitignore +++ b/.gitignore @@ -240,6 +240,7 @@ /test-ns /test-nss /test-parse-util +/test-patch-uid /test-path /test-path-lookup /test-path-util diff --git a/Makefile.am b/Makefile.am index 0f475c6d09..b323de55c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3021,6 +3021,8 @@ systemd_nspawn_SOURCES = \ src/nspawn/nspawn-setuid.h \ src/nspawn/nspawn-stub-pid1.c \ src/nspawn/nspawn-stub-pid1.h \ + src/nspawn/nspawn-patch-uid.c \ + src/nspawn/nspawn-patch-uid.h \ src/core/mount-setup.c \ src/core/mount-setup.h \ src/core/loopback-setup.c \ @@ -3048,6 +3050,17 @@ systemd_nspawn_LDADD += \ libfirewall.la endif +test_patch_uid_SOURCES = \ + src/nspawn/nspawn-patch-uid.c \ + src/nspawn/nspawn-patch-uid.h \ + src/nspawn/test-patch-uid.c + +test_patch_uid_LDADD = \ + libshared.la + +manual_tests += \ + test-patch-uid + # ------------------------------------------------------------------------------ systemd_run_SOURCES = \ src/run/run.c diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c new file mode 100644 index 0000000000..f53164fbbf --- /dev/null +++ b/src/nspawn/nspawn-patch-uid.c @@ -0,0 +1,417 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#ifdef HAVE_ACL +#include +#endif +#include +#include + +#include "acl-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "nspawn-patch-uid.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" + +#ifdef HAVE_ACL + +static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + acl_t acl; + + assert(fd >= 0); + assert(ret); + + if (name) { + _cleanup_close_ int child_fd = -1; + + child_fd = openat(fd, name, O_PATH|O_CLOEXEC|O_NOFOLLOW); + if (child_fd < 0) + return -errno; + + xsprintf(procfs_path, "/proc/self/fd/%i", child_fd); + acl = acl_get_file(procfs_path, type); + } else if (type == ACL_TYPE_ACCESS) + acl = acl_get_fd(fd); + else { + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + acl = acl_get_file(procfs_path, type); + } + if (!acl) + return -errno; + + *ret = acl; + return 0; +} + +static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + int r; + + assert(fd >= 0); + assert(acl); + + if (name) { + _cleanup_close_ int child_fd = -1; + + child_fd = openat(fd, name, O_PATH|O_CLOEXEC|O_NOFOLLOW); + if (child_fd < 0) + return -errno; + + xsprintf(procfs_path, "/proc/self/fd/%i", child_fd); + r = acl_set_file(procfs_path, type, acl); + } else if (type == ACL_TYPE_ACCESS) + r = acl_set_fd(fd, acl); + else { + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + r = acl_set_file(procfs_path, type, acl); + } + if (r < 0) + return -errno; + + return 0; +} + +static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { + _cleanup_(acl_freep) acl_t copy = NULL; + acl_entry_t i; + int r; + + assert(acl); + assert(ret); + + r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + if (r < 0) + return -errno; + while (r > 0) { + uid_t *old_uid, new_uid; + bool modify = false; + acl_tag_t tag; + + if (acl_get_tag_type(i, &tag) < 0) + return -errno; + + if (IN_SET(tag, ACL_USER, ACL_GROUP)) { + + /* We don't distuingish here between uid_t and gid_t, let's make sure the compiler checks that + * this is actually OK */ + assert_cc(sizeof(uid_t) == sizeof(gid_t)); + + old_uid = acl_get_qualifier(i); + if (!old_uid) + return -errno; + + new_uid = shift | (*old_uid & UINT32_C(0xFFFF)); + if (!uid_is_valid(new_uid)) + return -EINVAL; + + modify = new_uid != *old_uid; + if (modify && !copy) { + int n; + + /* There's no copy of the ACL yet? if so, let's create one, and start the loop from the + * beginning, so that we copy all entries, starting from the first, this time. */ + + n = acl_entries(acl); + if (n < 0) + return -errno; + + copy = acl_init(n); + if (!copy) + return -errno; + + /* Seek back to the beginning */ + r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + if (r < 0) + return -errno; + continue; + } + } + + if (copy) { + acl_entry_t new_entry; + + if (acl_create_entry(©, &new_entry) < 0) + return -errno; + + if (acl_copy_entry(new_entry, i) < 0) + return -errno; + + if (modify) + if (acl_set_qualifier(new_entry, &new_uid) < 0) + return -errno; + } + + r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i); + if (r < 0) + return -errno; + } + + *ret = copy; + copy = NULL; + + return !!*ret; +} + +static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shift) { + _cleanup_(acl_freep) acl_t acl = NULL, shifted = NULL; + bool changed = false; + int r; + + assert(fd >= 0); + assert(st); + + /* ACLs are not supported on symlinks, there's no point in trying */ + if (S_ISLNK(st->st_mode)) + return 0; + + r = get_acl(fd, name, ACL_TYPE_ACCESS, &acl); + if (r == -EOPNOTSUPP) + return 0; + if (r < 0) + return r; + + r = shift_acl(acl, shift, &shifted); + if (r < 0) + return r; + if (r > 0) { + r = set_acl(fd, name, ACL_TYPE_ACCESS, shifted); + if (r < 0) + return r; + + changed = true; + } + + if (S_ISDIR(st->st_mode)) { + acl_free(acl); + acl_free(shifted); + + acl = shifted = NULL; + + r = get_acl(fd, name, ACL_TYPE_DEFAULT, &acl); + if (r < 0) + return r; + + r = shift_acl(acl, shift, &shifted); + if (r < 0) + return r; + if (r > 0) { + r = set_acl(fd, name, ACL_TYPE_DEFAULT, shifted); + if (r < 0) + return r; + + changed = true; + } + } + + return changed; +} + +#else + +static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shift) { + return 0; +} + +#endif + +static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift) { + uid_t new_uid; + gid_t new_gid; + bool changed = false; + int r; + + assert(fd >= 0); + assert(st); + + new_uid = shift | (st->st_uid & UINT32_C(0xFFFF)); + new_gid = (gid_t) shift | (st->st_gid & UINT32_C(0xFFFF)); + + if (!uid_is_valid(new_uid) || !gid_is_valid(new_gid)) + return -EINVAL; + + if (st->st_uid != new_uid || st->st_gid != new_gid) { + if (name) + r = fchownat(fd, name, new_uid, new_gid, AT_SYMLINK_NOFOLLOW); + else + r = fchown(fd, new_uid, new_gid); + if (r < 0) + return -errno; + + /* The Linux kernel alters the mode in some cases of chown(). Let's undo this. */ + if (name && !S_ISLNK(st->st_mode)) + r = fchmodat(fd, name, st->st_mode, 0); + else + r = fchmod(fd, st->st_mode); + if (r < 0) + return -errno; + + changed = true; + } + + r = patch_acls(fd, name, st, shift); + if (r < 0) + return r; + + return r > 0 || changed; +} + +static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift) { + bool changed = false; + int r; + + assert(fd >= 0); + + r = patch_fd(fd, NULL, st, shift); + if (r < 0) + goto finish; + + if (S_ISDIR(st->st_mode)) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + + if (!donate_fd) { + int copy; + + copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (copy < 0) + return -errno; + + fd = copy; + donate_fd = true; + } + + d = fdopendir(fd); + if (!d) { + r = -errno; + goto finish; + } + fd = -1; + + FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) { + struct stat fst; + + if (STR_IN_SET(de->d_name, ".", "..")) + continue; + + if (fstatat(dirfd(d), de->d_name, &fst, AT_SYMLINK_NOFOLLOW) < 0) { + r = -errno; + goto finish; + } + + if (S_ISDIR(fst.st_mode)) { + int subdir_fd; + + subdir_fd = openat(dirfd(d), de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + if (subdir_fd < 0) { + r = -errno; + goto finish; + + } + + r = recurse_fd(subdir_fd, true, &fst, shift); + if (r < 0) + goto finish; + if (r > 0) + changed = true; + + } else { + r = patch_fd(dirfd(d), de->d_name, &fst, shift); + if (r < 0) + goto finish; + if (r > 0) + changed = true; + } + } + } + + r = changed; + +finish: + if (donate_fd) + safe_close(fd); + + return r; +} + +static int fd_patch_uid_internal(int fd, bool donate_fd, uid_t shift, uid_t range) { + struct stat st; + int r; + + assert(fd >= 0); + + /* Recursively adjusts the UID/GIDs of all files of a directory tree. This is used to automatically fix up an + * OS tree to the used user namespace UID range. Note that this automatic adjustment only works for UID ranges + * following the concept that the upper 16bit of a UID identify the container, and the lower 16bit are the actual + * UID within the container. */ + + if ((shift & 0xFFFF) != 0) { + /* We only support containers where the shift starts at a 2^16 boundary */ + r = -EOPNOTSUPP; + goto finish; + } + + if (range != 0x10000) { + /* We only support containers with 16bit UID ranges for the patching logic */ + r = -EOPNOTSUPP; + goto finish; + } + + if (fstat(fd, &st) < 0) { + r = -errno; + goto finish; + } + + if ((uint32_t) st.st_uid >> 16 != (uint32_t) st.st_gid >> 16) { + /* We only support containers where the uid/gid container ID match */ + r = -EBADE; + goto finish; + } + + /* Try to detect if the range is already right. Of course, this a pretty drastic optimization, as we assume + * that if the top-level dir has the right upper 16bit assigned, then everything below will have too... */ + if (((uint32_t) (st.st_uid ^ shift) >> 16) == 0) + return 0; + + return recurse_fd(fd, donate_fd, &st, shift); + +finish: + if (donate_fd) + safe_close(fd); + + return r; +} + +int fd_patch_uid(int fd, uid_t shift, uid_t range) { + return fd_patch_uid_internal(fd, false, shift, range); +} + +int path_patch_uid(const char *path, uid_t shift, uid_t range) { + int fd; + + fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + if (fd < 0) + return -errno; + + return fd_patch_uid_internal(fd, true, shift, range); +} diff --git a/src/nspawn/nspawn-patch-uid.h b/src/nspawn/nspawn-patch-uid.h new file mode 100644 index 0000000000..55d0990016 --- /dev/null +++ b/src/nspawn/nspawn-patch-uid.h @@ -0,0 +1,23 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +int fd_patch_uid(int fd, uid_t shift, uid_t range); +int path_patch_uid(const char *path, uid_t shift, uid_t range); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e1d37d383a..a3190545fa 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -75,6 +75,7 @@ #include "nspawn-expose-ports.h" #include "nspawn-mount.h" #include "nspawn-network.h" +#include "nspawn-patch-uid.h" #include "nspawn-register.h" #include "nspawn-settings.h" #include "nspawn-setuid.h" @@ -175,6 +176,7 @@ 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 bool arg_userns_chown = false; static int arg_kill_signal = 0; static bool arg_unified_cgroup_hierarchy = false; static SettingsMask arg_settings_mask = 0; @@ -204,6 +206,7 @@ static void help(void) { " --property=NAME=VALUE Set scope unit property\n" " --private-users[=UIDBASE[:NUIDS]]\n" " Run within user namespace\n" + " --private-user-chown Adjust OS tree file ownership for private user range\n" " --private-network Disable network in container\n" " --network-interface=INTERFACE\n" " Assign an existing network interface to the\n" @@ -349,6 +352,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_KILL_SIGNAL, ARG_SETTINGS, ARG_CHDIR, + ARG_PRIVATE_USERS_CHOWN, }; static const struct option options[] = { @@ -392,6 +396,7 @@ static int parse_argv(int argc, char *argv[]) { { "port", required_argument, NULL, 'p' }, { "property", required_argument, NULL, ARG_PROPERTY }, { "private-users", optional_argument, NULL, ARG_PRIVATE_USERS }, + { "private-users-chown", optional_argument, NULL, ARG_PRIVATE_USERS_CHOWN}, { "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL }, { "settings", required_argument, NULL, ARG_SETTINGS }, { "chdir", required_argument, NULL, ARG_CHDIR }, @@ -825,6 +830,10 @@ static int parse_argv(int argc, char *argv[]) { arg_userns = true; break; + case ARG_PRIVATE_USERS_CHOWN: + arg_userns_chown = true; + break; + case ARG_KILL_SIGNAL: arg_kill_signal = signal_from_string_try_harder(optarg); if (arg_kill_signal < 0) { @@ -933,8 +942,15 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if (arg_userns && access("/proc/self/uid_map", F_OK) < 0) - return log_error_errno(EOPNOTSUPP, "--private-users= is not supported, kernel compiled without user namespace support."); + if (arg_userns && access("/proc/self/uid_map", F_OK) < 0) { + log_error("--private-users= is not supported, kernel compiled without user namespace support."); + return -EOPNOTSUPP; + } + + if (arg_userns_chown && arg_read_only) { + log_error("--read-only and --private-users-chown may not be combined."); + return -EINVAL; + } if (argc > optind) { arg_parameters = strv_copy(argv + optind); @@ -2218,6 +2234,29 @@ static int setup_machine_id(const char *directory) { return 0; } +static int recursive_chown(const char *directory, uid_t shift, uid_t range) { + int r; + + assert(directory); + + if (!arg_userns || !arg_userns_chown) + return 0; + + r = path_patch_uid(directory, arg_uid_shift, arg_uid_range); + if (r == -EOPNOTSUPP) + return log_error_errno(r, "Automatic UID/GID adjusting is only supported for UID/GID ranges starting at multiples of 2^16 with a range of 2^16."); + if (r == -EBADE) + return log_error_errno(r, "Upper 16 bits of root directory UID and GID do not match."); + if (r < 0) + return log_error_errno(r, "Failed to adjust UID/GID shift of OS tree: %m"); + if (r == 0) + log_debug("Root directory of image is already owned by the right UID/GID range, skipping recursive chown operation."); + else + log_debug("Patched directory tree to match UID/GID range."); + + return r; +} + static int mount_devices( const char *where, const char *root_device, bool root_device_rw, @@ -2763,6 +2802,10 @@ static int outer_child( if (mount(directory, directory, NULL, MS_BIND|MS_REC, NULL) < 0) return log_error_errno(errno, "Failed to make bind mount: %m"); + r = recursive_chown(directory, arg_uid_shift, arg_uid_range); + if (r < 0) + return r; + r = setup_volatile(directory, arg_volatile_mode, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_context); if (r < 0) return r; diff --git a/src/nspawn/test-patch-uid.c b/src/nspawn/test-patch-uid.c new file mode 100644 index 0000000000..11c5321788 --- /dev/null +++ b/src/nspawn/test-patch-uid.c @@ -0,0 +1,61 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +#include "log.h" +#include "nspawn-patch-uid.h" +#include "user-util.h" +#include "util.h" + +int main(int argc, char *argv[]) { + uid_t shift, range; + int r; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + log_open(); + + if (argc != 4) { + log_error("Expected PATH SHIFT RANGE parameters."); + return EXIT_FAILURE; + } + + r = parse_uid(argv[2], &shift); + if (r < 0) { + log_error_errno(r, "Failed to parse UID shift %s.", argv[2]); + return EXIT_FAILURE; + } + + r = parse_gid(argv[3], &range); + if (r < 0) { + log_error_errno(r, "Failed to parse UID range %s.", argv[3]); + return EXIT_FAILURE; + } + + r = path_patch_uid(argv[1], shift, range); + if (r < 0) { + log_error_errno(r, "Failed to patch directory tree: %m"); + return EXIT_FAILURE; + } + + log_info("Changed: %s", yes_no(r)); + + return EXIT_SUCCESS; +} -- cgit v1.2.3-54-g00ecf From 0e7ac7515f2fe0782f4062bb223904e2748b535d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 11:28:09 +0200 Subject: nspawn: optionally, automatically allocate a UID/GID range for userns containers This adds the new value "pick" to --private-users=. When specified a new UID/GID range of 65536 users is automatically and randomly allocated from the host range 0x00080000-0xDFFF0000 and used for the container. The setting implies --private-users-chown, so that container directory is recursively chown()ed to the newly allocated UID/GID range, if that's necessary. As an optimization before picking a randomized UID/GID the UID of the container's root directory is used as starting point and used if currently not used otherwise. To protect against using the same UID/GID range multiple times a few mechanisms are in place: - The first and the last UID and GID of the range are checked with getpwuid() and getgrgid(). If an entry already exists a different range is picked. Note that by "last" UID the user 65534 is used, as 65535 is the 16bit (uid_t) -1. - A lock file for the range is taken in /run/systemd/nspawn-uid/. Since the ranges are taken in a non-overlapping fashion, and always start on 64K boundaries this allows us to maintain a single lock file for each range that can be randomly picked. This protects nspawn from picking the same range in two parallel instances. - If possible the /etc/passwd lock file is taken while a new range is selected until the container is up. This means adduser/addgroup should safely avoid the range as long as nss-mymachines is used, since the allocated range will then show up in the user database. The UID/GID range nspawn picks from is compiled in and not configurable at the moment. That should probably stay that way, since we already provide ways how users can pick their own ranges manually if they don't like the automatic logic. The new --private-users=pick logic makes user namespacing pretty useful now, as it relieves the user from managing UID/GID ranges. --- src/nspawn/nspawn.c | 226 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 189 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index a3190545fa..c330456ff9 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -22,7 +22,9 @@ #endif #include #include +#include #include +#include #include #ifdef HAVE_SECCOMP #include @@ -102,6 +104,11 @@ #include "user-util.h" #include "util.h" +/* Note that devpts's gid= parameter parses GIDs as signed values, hence we stay away from the upper half of the 32bit + * UID range here */ +#define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000)) +#define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000)) + typedef enum ContainerStatus { CONTAINER_TERMINATED, CONTAINER_REBOOTED @@ -174,9 +181,10 @@ static char *arg_image = NULL; static VolatileMode arg_volatile_mode = 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 bool arg_userns_chown = false; +static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U; +static bool arg_uid_shift_pick = false; static int arg_kill_signal = 0; static bool arg_unified_cgroup_hierarchy = false; static SettingsMask arg_settings_mask = 0; @@ -275,9 +283,15 @@ static int custom_mounts_prepare(void) { for (i = 0; i < arg_n_custom_mounts; i++) { CustomMount *m = &arg_custom_mounts[i]; - if (arg_userns && arg_uid_shift == UID_INVALID && path_equal(m->destination, "/")) { - log_error("--private-users with automatic UID shift may not be combined with custom root mounts."); - return -EINVAL; + if (path_equal(m->destination, "/") && arg_userns) { + + if (arg_userns_chown) { + log_error("--private-users-chown may not be combined with custom root mounts."); + return -EINVAL; + } else if (arg_uid_shift == UID_INVALID) { + log_error("--private-users with automatic UID shift may not be combined with custom root mounts."); + return -EINVAL; + } } if (m->type != CUSTOM_MOUNT_OVERLAY) @@ -806,25 +820,37 @@ static int parse_argv(int argc, char *argv[]) { _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); + if (streq(optarg, "pick")) { + arg_uid_shift = UID_INVALID; + arg_uid_range = 0x10000U; + arg_uid_shift_pick = true; + } else { + 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; } - } else - shift = optarg; - if (parse_uid(shift, &arg_uid_shift) < 0) { - log_error("Failed to parse UID: %s", optarg); - return -EINVAL; + arg_uid_shift_pick = false; } + } else { + arg_uid_shift = UID_INVALID; + arg_uid_range = 0x10000U; + arg_uid_shift_pick = false; } arg_userns = true; @@ -902,6 +928,9 @@ static int parse_argv(int argc, char *argv[]) { if (arg_share_system) arg_register = false; + if (arg_uid_shift_pick) + arg_userns_chown = true; + if (arg_start_mode != START_PID1 && arg_share_system) { log_error("--boot and --share-system may not be combined."); return -EINVAL; @@ -2501,7 +2530,6 @@ static int determine_uid_shift(const char *directory) { return -EINVAL; } - log_info("Using user namespaces with base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range); return 0; } @@ -2789,6 +2817,7 @@ static int outer_child( return r; if (arg_userns) { + /* Let the parent know which UID shift we read from the image */ l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL); if (l < 0) return log_error_errno(errno, "Failed to send UID shift: %m"); @@ -2796,6 +2825,22 @@ static int outer_child( log_error("Short write while sending UID shift."); return -EIO; } + + if (arg_uid_shift_pick) { + /* When we are supposed to pick the UID shift, the parent will check now whether the UID shift + * we just read from the image is available. If yes, it will send the UID shift back to us, if + * not it will pick a different one, and send it back to us. */ + + l = recv(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), 0); + if (l < 0) + return log_error_errno(errno, "Failed to recv UID shift: %m"); + if (l != sizeof(arg_uid_shift)) { + log_error("Short read while recieving UID shift."); + return -EIO; + } + } + + log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range); } /* Turn directory into bind mount */ @@ -2925,6 +2970,61 @@ static int outer_child( return 0; } +static int uid_shift_pick(uid_t *shift, LockFile *ret_lock_file) { + unsigned n_tries = 100; + uid_t candidate; + int r; + + assert(shift); + assert(ret_lock_file); + assert(arg_uid_shift_pick); + assert(arg_uid_range == 0x10000U); + + candidate = *shift; + + (void) mkdir("/run/systemd/nspawn-uid", 0755); + + for (;;) { + char lock_path[strlen("/run/systemd/nspawn-uid/") + DECIMAL_STR_MAX(uid_t) + 1]; + _cleanup_release_lock_file_ LockFile lf = LOCK_FILE_INIT; + + if (--n_tries <= 0) + return -EBUSY; + + if (candidate < UID_SHIFT_PICK_MIN || candidate > UID_SHIFT_PICK_MAX) + goto next; + if ((candidate & UINT32_C(0xFFFF)) != 0) + goto next; + + xsprintf(lock_path, "/run/systemd/nspawn-uid/" UID_FMT, candidate); + r = make_lock_file(lock_path, LOCK_EX|LOCK_NB, &lf); + if (r == -EBUSY) /* Range already taken by another nspawn instance */ + goto next; + if (r < 0) + return r; + + /* Make some superficial checks whether the range is currently known in the user database */ + if (getpwuid(candidate)) + goto next; + if (getpwuid(candidate + UINT32_C(0xFFFE))) + goto next; + if (getgrgid(candidate)) + goto next; + if (getgrgid(candidate + UINT32_C(0xFFFE))) + goto next; + + *ret_lock_file = lf; + lf = (struct LockFile) LOCK_FILE_INIT; + *shift = candidate; + return 0; + + next: + random_bytes(&candidate, sizeof(candidate)); + candidate = (candidate % (UID_SHIFT_PICK_MAX - UID_SHIFT_PICK_MIN)) + UID_SHIFT_PICK_MIN; + candidate &= (uid_t) UINT32_C(0xFFFF0000); + } +} + 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; @@ -3394,20 +3494,42 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, - pid_socket_pair[2] = { -1, -1 }, uuid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }; - ContainerStatus container_status; - _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; static const struct sigaction sa = { .sa_handler = nop_signal_handler, .sa_flags = SA_NOCLDSTOP, }; - int ifi = 0; - ssize_t l; + + _cleanup_release_lock_file_ LockFile uid_shift_lock = LOCK_FILE_INIT; + _cleanup_close_ int etc_passwd_lock = -1; + _cleanup_close_pair_ int + kmsg_socket_pair[2] = { -1, -1 }, + rtnl_socket_pair[2] = { -1, -1 }, + pid_socket_pair[2] = { -1, -1 }, + uuid_socket_pair[2] = { -1, -1 }, + uid_shift_socket_pair[2] = { -1, -1 }; + _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + ContainerStatus container_status; char last_char = 0; + int ifi = 0; + ssize_t l; + + if (arg_uid_shift_pick) { + /* When we shall pick the UID/GID range, let's first lock /etc/passwd, so that we can safely + * check with getpwuid() if the specific user already exists. Note that /etc might be + * read-only, in which case this will fail with EROFS. But that's really OK, as in that case we + * can be reasonably sure that no users are going to be added. Note that getpwuid() checks are + * really just an extra safety net. We kinda assume that the UID range we allocate from is + * really ours. */ + + etc_passwd_lock = take_etc_passwd_lock(NULL); + if (etc_passwd_lock < 0 && etc_passwd_lock != -EROFS) { + log_error_errno(r, "Failed to take /etc/passwd lock: %m"); + goto finish; + } + } r = barrier_create(&barrier); if (r < 0) { @@ -3511,6 +3633,43 @@ int main(int argc, char *argv[]) { uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]); uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); + if (arg_userns) { + /* The child just let us know the UID shift it might have read from the image. */ + l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0); + if (l < 0) { + r = log_error_errno(errno, "Failed to read UID shift: %m"); + goto finish; + } + if (l != sizeof(arg_uid_shift)) { + log_error("Short read while reading UID shift."); + r = EIO; + goto finish; + } + + if (arg_uid_shift_pick) { + /* If we are supposed to pick the UID shift, let's try to use the shift read from the + * image, but if that's already in use, pick a new one, and report back to the child, + * which one we now picked. */ + + r = uid_shift_pick(&arg_uid_shift, &uid_shift_lock); + if (r < 0) { + log_error_errno(r, "Failed to pick suitable UID/GID range: %m"); + goto finish; + } + + l = send(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL); + if (l < 0) { + r = log_error_errno(errno, "Failed to send UID shift: %m"); + goto finish; + } + if (l != sizeof(arg_uid_shift)) { + log_error("Short write while writing UID shift."); + r = -EIO; + goto finish; + } + } + } + /* Wait for the outer child. */ r = wait_for_terminate_and_warn("namespace helper", pid, NULL); if (r < 0) @@ -3554,17 +3713,6 @@ int main(int argc, char *argv[]) { goto finish; } - l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0); - if (l < 0) { - r = log_error_errno(errno, "Failed to read UID shift: %m"); - goto finish; - } - if (l != sizeof(arg_uid_shift)) { - log_error("Short read while reading UID shift."); - r = EIO; - goto finish; - } - r = setup_uid_map(pid); if (r < 0) goto finish; @@ -3662,6 +3810,10 @@ int main(int argc, char *argv[]) { goto finish; } + /* At this point we have made use of the UID we picked, and thus nss-mymachines will make them appear + * in getpwuid(), thus we can release the /etc/passwd lock. */ + etc_passwd_lock = safe_close(etc_passwd_lock); + sd_notifyf(false, "READY=1\n" "STATUS=Container running.\n" -- cgit v1.2.3-54-g00ecf From 19aac838fc3b7bcaed272f19a0bec3962eef7418 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 11:47:35 +0200 Subject: nspawn: add -U as shortcut for --private-users=pick Given that user namespacing is pretty useful now, let's add a shortcut command line switch for the logic. --- src/nspawn/nspawn.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index c330456ff9..3e32f59f75 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -212,9 +212,10 @@ static void help(void) { " --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" + " -U --private-users=pick Run within user namespace, pick UID/GID range automatically\n" " --private-users[=UIDBASE[:NUIDS]]\n" - " Run within user namespace\n" - " --private-user-chown Adjust OS tree file ownership for private user range\n" + " Run within user namespace, user configured UID/GID range\n" + " --private-user-chown Adjust OS tree file ownership for private UID/GID range\n" " --private-network Disable network in container\n" " --network-interface=INTERFACE\n" " Assign an existing network interface to the\n" @@ -425,7 +426,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:n", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nU", options, NULL)) >= 0) switch (c) { @@ -860,6 +861,14 @@ static int parse_argv(int argc, char *argv[]) { arg_userns_chown = true; break; + case 'U': + arg_userns = true; + arg_userns_chown = true; + arg_uid_shift = UID_INVALID; + arg_uid_range = 0x10000U; + arg_uid_shift_pick = true; + break; + case ARG_KILL_SIGNAL: arg_kill_signal = signal_from_string_try_harder(optarg); if (arg_kill_signal < 0) { -- cgit v1.2.3-54-g00ecf From 0de7accea9e0f7b696f108a43bff7e454fa8f016 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 13:02:53 +0200 Subject: nspawn: allow configuration of user namespaces in .nspawn files In order to implement this we change the bool arg_userns into an enum UserNamespaceMode, which can take one of NO, PICK or FIXED, and replace the arg_uid_range_pick bool with it. --- src/nspawn/nspawn-gperf.gperf | 4 +- src/nspawn/nspawn-settings.c | 86 ++++++++++++++++++++ src/nspawn/nspawn-settings.h | 15 +++- src/nspawn/nspawn.c | 183 ++++++++++++++++++++++++++++-------------- 4 files changed, 225 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 116655cdd2..34e1310e29 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -16,7 +16,7 @@ struct ConfigPerfItem; %includes %% Exec.Boot, config_parse_boot, 0, 0 -Exec.ProcessTwo, config_parse_pid2, 0, 0, +Exec.ProcessTwo, config_parse_pid2, 0, 0 Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters) Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment) Exec.User, config_parse_string, 0, offsetof(Settings, user) @@ -26,11 +26,13 @@ Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality) Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id) Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory) +Exec.PrivateUsers, config_parse_private_users, 0, 0 Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only) Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode) Files.Bind, config_parse_bind, 0, 0 Files.BindReadOnly, config_parse_bind, 1, 0 Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0 +Files.PrivateUsersChown, config_parse_tristate, 0, offsetof(Settings, userns_chown) Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network) Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces) Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan) diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 4fb0054698..b98a79fd09 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -25,7 +25,9 @@ #include "parse-util.h" #include "process-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" +#include "string-util.h" int settings_load(FILE *f, const char *path, Settings **ret) { _cleanup_(settings_freep) Settings *s = NULL; @@ -40,9 +42,13 @@ int settings_load(FILE *f, const char *path, Settings **ret) { s->start_mode = _START_MODE_INVALID; s->personality = PERSONALITY_INVALID; + s->userns_mode = _USER_NAMESPACE_MODE_INVALID; + s->uid_shift = UID_INVALID; + s->uid_range = UID_INVALID; s->read_only = -1; s->volatile_mode = _VOLATILE_MODE_INVALID; + s->userns_chown = -1; s->private_network = -1; s->network_veth = -1; @@ -59,6 +65,16 @@ int settings_load(FILE *f, const char *path, Settings **ret) { if (r < 0) return r; + /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either + * both fields shall be initialized or neither. */ + if (s->userns_mode == USER_NAMESPACE_PICK) + s->userns_chown = true; + else if (s->userns_mode != _USER_NAMESPACE_MODE_INVALID && s->userns_chown < 0) + s->userns_chown = false; + + if (s->userns_chown >= 0 && s->userns_mode == _USER_NAMESPACE_MODE_INVALID) + s->userns_mode = USER_NAMESPACE_NO; + *ret = s; s = NULL; @@ -392,3 +408,73 @@ conflict: log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring."); return 0; } + +int config_parse_private_users( + 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) { + + Settings *settings = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = parse_boolean(rvalue); + if (r == 0) { + /* no: User namespacing off */ + settings->userns_mode = USER_NAMESPACE_NO; + settings->uid_shift = UID_INVALID; + settings->uid_range = UINT32_C(0x10000); + } else if (r > 0) { + /* yes: User namespacing on, UID range is read from root dir */ + settings->userns_mode = USER_NAMESPACE_FIXED; + settings->uid_shift = UID_INVALID; + settings->uid_range = UINT32_C(0x10000); + } else if (streq(rvalue, "pick")) { + /* pick: User namespacing on, UID range is picked randomly */ + settings->userns_mode = USER_NAMESPACE_PICK; + settings->uid_shift = UID_INVALID; + settings->uid_range = UINT32_C(0x10000); + } else { + const char *range, *shift; + uid_t sh, rn; + + /* anything else: User namespacing on, UID range is explicitly configured */ + + range = strchr(rvalue, ':'); + if (range) { + shift = strndupa(rvalue, range - rvalue); + range++; + + r = safe_atou32(range, &rn); + if (r < 0 || rn <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID range invalid, ignoring: %s", range); + return 0; + } + } else { + shift = rvalue; + rn = UINT32_C(0x10000); + } + + r = parse_uid(shift, &sh); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID shift invalid, ignoring: %s", range); + return 0; + } + + settings->userns_mode = USER_NAMESPACE_FIXED; + settings->uid_shift = sh; + settings->uid_range = rn; + } + + return 0; +} diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index a017405cd9..e12e91b886 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -33,6 +33,14 @@ typedef enum StartMode { _START_MODE_INVALID = -1 } StartMode; +typedef enum UserNamespaceMode { + USER_NAMESPACE_NO, + USER_NAMESPACE_FIXED, + USER_NAMESPACE_PICK, + _USER_NAMESPACE_MODE_MAX, + _USER_NAMESPACE_MODE_INVALID = -1, +} UserNamespaceMode; + typedef enum SettingsMask { SETTING_START_MODE = 1 << 0, SETTING_ENVIRONMENT = 1 << 1, @@ -47,7 +55,8 @@ typedef enum SettingsMask { SETTING_VOLATILE_MODE = 1 << 10, SETTING_CUSTOM_MOUNTS = 1 << 11, SETTING_WORKING_DIRECTORY = 1 << 12, - _SETTINGS_MASK_ALL = (1 << 13) -1 + SETTING_USERNS = 1 << 13, + _SETTINGS_MASK_ALL = (1 << 14) -1 } SettingsMask; typedef struct Settings { @@ -62,12 +71,15 @@ typedef struct Settings { unsigned long personality; sd_id128_t machine_id; char *working_directory; + UserNamespaceMode userns_mode; + uid_t uid_shift, uid_range; /* [Image] */ int read_only; VolatileMode volatile_mode; CustomMount *custom_mounts; unsigned n_custom_mounts; + int userns_chown; /* [Network] */ int private_network; @@ -99,3 +111,4 @@ int config_parse_tmpfs(const char *unit, const char *filename, unsigned line, co int config_parse_veth_extra(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_boot(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_pid2(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_private_users(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/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3e32f59f75..40e3d5a3fe 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -181,10 +181,9 @@ static char *arg_image = NULL; static VolatileMode arg_volatile_mode = VOLATILE_NO; static ExposePort *arg_expose_ports = NULL; static char **arg_property = NULL; -static bool arg_userns = false; -static bool arg_userns_chown = false; +static UserNamespaceMode arg_userns_mode = USER_NAMESPACE_NO; static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U; -static bool arg_uid_shift_pick = false; +static bool arg_userns_chown = false; static int arg_kill_signal = 0; static bool arg_unified_cgroup_hierarchy = false; static SettingsMask arg_settings_mask = 0; @@ -284,7 +283,7 @@ static int custom_mounts_prepare(void) { for (i = 0; i < arg_n_custom_mounts; i++) { CustomMount *m = &arg_custom_mounts[i]; - if (path_equal(m->destination, "/") && arg_userns) { + if (path_equal(m->destination, "/") && arg_userns_mode != USER_NAMESPACE_NO) { if (arg_userns_chown) { log_error("--private-users-chown may not be combined with custom root mounts."); @@ -817,56 +816,67 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_PRIVATE_USERS: - if (optarg) { + + r = optarg ? parse_boolean(optarg) : 1; + if (r == 0) { + /* no: User namespacing off */ + arg_userns_mode = USER_NAMESPACE_NO; + arg_uid_shift = UID_INVALID; + arg_uid_range = UINT32_C(0x10000); + } else if (r > 0) { + /* yes: User namespacing on, UID range is read from root dir */ + arg_userns_mode = USER_NAMESPACE_FIXED; + arg_uid_shift = UID_INVALID; + arg_uid_range = UINT32_C(0x10000); + } else if (streq(optarg, "pick")) { + /* pick: User namespacing on, UID range is picked randomly */ + arg_userns_mode = USER_NAMESPACE_PICK; + arg_uid_shift = UID_INVALID; + arg_uid_range = UINT32_C(0x10000); + } else { _cleanup_free_ char *buffer = NULL; const char *range, *shift; - if (streq(optarg, "pick")) { - arg_uid_shift = UID_INVALID; - arg_uid_range = 0x10000U; - arg_uid_shift_pick = true; - } else { - 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); + /* anything else: User namespacing on, UID range is explicitly configured */ + + 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; - arg_uid_shift_pick = false; + if (parse_uid(shift, &arg_uid_shift) < 0) { + log_error("Failed to parse UID: %s", optarg); + return -EINVAL; } - } else { - arg_uid_shift = UID_INVALID; - arg_uid_range = 0x10000U; - arg_uid_shift_pick = false; + + arg_userns_mode = USER_NAMESPACE_FIXED; } - arg_userns = true; + arg_settings_mask |= SETTING_USERNS; break; - case ARG_PRIVATE_USERS_CHOWN: - arg_userns_chown = true; + case 'U': + arg_userns_mode = USER_NAMESPACE_PICK; + arg_uid_shift = UID_INVALID; + arg_uid_range = UINT32_C(0x10000); + + arg_settings_mask |= SETTING_USERNS; break; - case 'U': - arg_userns = true; + case ARG_PRIVATE_USERS_CHOWN: arg_userns_chown = true; - arg_uid_shift = UID_INVALID; - arg_uid_range = 0x10000U; - arg_uid_shift_pick = true; + + arg_settings_mask |= SETTING_USERNS; break; case ARG_KILL_SIGNAL: @@ -937,7 +947,7 @@ static int parse_argv(int argc, char *argv[]) { if (arg_share_system) arg_register = false; - if (arg_uid_shift_pick) + if (arg_userns_mode == USER_NAMESPACE_PICK) arg_userns_chown = true; if (arg_start_mode != START_PID1 && arg_share_system) { @@ -980,7 +990,7 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if (arg_userns && access("/proc/self/uid_map", F_OK) < 0) { + if (arg_userns_mode != USER_NAMESPACE_NO && access("/proc/self/uid_map", F_OK) < 0) { log_error("--private-users= is not supported, kernel compiled without user namespace support."); return -EOPNOTSUPP; } @@ -1047,7 +1057,7 @@ static int verify_arguments(void) { static int userns_lchown(const char *p, uid_t uid, gid_t gid) { assert(p); - if (!arg_userns) + if (arg_userns_mode == USER_NAMESPACE_NO) return 0; if (uid == UID_INVALID && gid == GID_INVALID) @@ -2277,7 +2287,7 @@ static int recursive_chown(const char *directory, uid_t shift, uid_t range) { assert(directory); - if (!arg_userns || !arg_userns_chown) + if (arg_userns_mode == USER_NAMESPACE_NO || !arg_userns_chown) return 0; r = path_patch_uid(directory, arg_uid_shift, arg_uid_range); @@ -2512,7 +2522,7 @@ static int determine_names(void) { static int determine_uid_shift(const char *directory) { int r; - if (!arg_userns) { + if (arg_userns_mode == USER_NAMESPACE_NO) { arg_uid_shift = 0; return 0; } @@ -2575,7 +2585,7 @@ static int inner_child( cg_unified_flush(); - if (arg_userns) { + if (arg_userns_mode != USER_NAMESPACE_NO) { /* Tell the parent, that it now can write the UID map. */ (void) barrier_place(barrier); /* #1 */ @@ -2586,7 +2596,14 @@ static int inner_child( } } - r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(NULL, + arg_userns_mode != USER_NAMESPACE_NO, + true, + arg_private_network, + arg_uid_shift, + arg_uid_range, + arg_selinux_apifs_context); + if (r < 0) return r; @@ -2825,7 +2842,7 @@ static int outer_child( if (r < 0) return r; - if (arg_userns) { + if (arg_userns_mode != USER_NAMESPACE_NO) { /* Let the parent know which UID shift we read from the image */ l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL); if (l < 0) @@ -2835,7 +2852,7 @@ static int outer_child( return -EIO; } - if (arg_uid_shift_pick) { + if (arg_userns_mode == USER_NAMESPACE_PICK) { /* When we are supposed to pick the UID shift, the parent will check now whether the UID shift * we just read from the image is available. If yes, it will send the UID shift back to us, if * not it will pick a different one, and send it back to us. */ @@ -2860,11 +2877,23 @@ static int outer_child( if (r < 0) return r; - r = setup_volatile(directory, arg_volatile_mode, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_context); + r = setup_volatile( + directory, + arg_volatile_mode, + arg_userns_mode != USER_NAMESPACE_NO, + arg_uid_shift, + arg_uid_range, + arg_selinux_context); if (r < 0) return r; - r = setup_volatile_state(directory, arg_volatile_mode, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_context); + r = setup_volatile_state( + directory, + arg_volatile_mode, + arg_userns_mode != USER_NAMESPACE_NO, + arg_uid_shift, + arg_uid_range, + arg_selinux_context); if (r < 0) return r; @@ -2878,7 +2907,13 @@ static int outer_child( return log_error_errno(r, "Failed to make tree read-only: %m"); } - r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(directory, + arg_userns_mode != USER_NAMESPACE_NO, + false, + arg_private_network, + arg_uid_shift, + arg_uid_range, + arg_selinux_apifs_context); if (r < 0) return r; @@ -2920,11 +2955,24 @@ static int outer_child( if (r < 0) return r; - r = mount_custom(directory, arg_custom_mounts, arg_n_custom_mounts, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_custom( + directory, + arg_custom_mounts, + arg_n_custom_mounts, + arg_userns_mode != USER_NAMESPACE_NO, + arg_uid_shift, + arg_uid_range, + arg_selinux_apifs_context); if (r < 0) return r; - r = mount_cgroups(directory, arg_unified_cgroup_hierarchy, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_cgroups( + directory, + arg_unified_cgroup_hierarchy, + arg_userns_mode != USER_NAMESPACE_NO, + arg_uid_shift, + arg_uid_range, + arg_selinux_apifs_context); if (r < 0) return r; @@ -2935,7 +2983,7 @@ static int outer_child( 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), + (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0), NULL); if (pid < 0) return log_error_errno(errno, "Failed to fork inner child: %m"); @@ -2986,7 +3034,7 @@ static int uid_shift_pick(uid_t *shift, LockFile *ret_lock_file) { assert(shift); assert(ret_lock_file); - assert(arg_uid_shift_pick); + assert(arg_userns_mode == USER_NAMESPACE_PICK); assert(arg_uid_range == 0x10000U); candidate = *shift; @@ -3265,6 +3313,19 @@ static int load_settings(void) { } } + if ((arg_settings_mask & SETTING_USERNS) == 0 && + settings->userns_mode != _USER_NAMESPACE_MODE_INVALID) { + + if (!arg_settings_trusted) + log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", p); + else { + arg_userns_mode = settings->userns_mode; + arg_uid_shift = settings->uid_shift; + arg_uid_range = settings->uid_range; + arg_userns_chown = settings->userns_chown; + } + } + return 0; } @@ -3525,7 +3586,7 @@ int main(int argc, char *argv[]) { int ifi = 0; ssize_t l; - if (arg_uid_shift_pick) { + if (arg_userns_mode == USER_NAMESPACE_PICK) { /* When we shall pick the UID/GID range, let's first lock /etc/passwd, so that we can safely * check with getpwuid() if the specific user already exists. Note that /etc might be * read-only, in which case this will fail with EROFS. But that's really OK, as in that case we @@ -3566,7 +3627,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_userns) + if (arg_userns_mode != USER_NAMESPACE_NO) if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) { r = log_error_errno(errno, "Failed to create uid shift socket pair: %m"); goto finish; @@ -3642,7 +3703,7 @@ int main(int argc, char *argv[]) { uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]); uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); - if (arg_userns) { + if (arg_userns_mode != USER_NAMESPACE_NO) { /* The child just let us know the UID shift it might have read from the image. */ l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0); if (l < 0) { @@ -3655,7 +3716,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_uid_shift_pick) { + if (arg_userns_mode == USER_NAMESPACE_PICK) { /* If we are supposed to pick the UID shift, let's try to use the shift read from the * image, but if that's already in use, pick a new one, and report back to the child, * which one we now picked. */ @@ -3715,7 +3776,7 @@ int main(int argc, char *argv[]) { log_debug("Init process invoked as PID " PID_FMT, pid); - if (arg_userns) { + if (arg_userns_mode != USER_NAMESPACE_NO) { if (!barrier_place_and_sync(&barrier)) { /* #1 */ log_error("Child died too early."); r = -ESRCH; -- cgit v1.2.3-54-g00ecf From ccabee0d6465f06b9d339cf449fd8eea0db13373 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 14:10:09 +0200 Subject: nspawn: make -U a tiny bit smarter With this change -U will turn on user namespacing only if the kernel actually supports it and otherwise gracefully degrade to non-userns mode. --- man/systemd-nspawn.xml | 4 +++- src/basic/user-util.h | 5 +++++ src/nspawn/nspawn.c | 13 ++++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index ea0c6562f8..bd688a0ee1 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -444,7 +444,9 @@ - Equivalent to . + If the kernel supports the user namespaces feature, equivalent to + , otherwise equivalent to + . diff --git a/src/basic/user-util.h b/src/basic/user-util.h index c23f1d485d..8026eca3f4 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -21,6 +21,7 @@ #include #include +#include bool uid_is_valid(uid_t uid); @@ -63,3 +64,7 @@ int take_etc_passwd_lock(const char *root); #define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) #define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) + +static inline bool userns_supported(void) { + return access("/proc/self/uid_map", F_OK) >= 0; +} diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 40e3d5a3fe..c8a7ec71a3 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -866,11 +866,14 @@ static int parse_argv(int argc, char *argv[]) { break; case 'U': - arg_userns_mode = USER_NAMESPACE_PICK; - arg_uid_shift = UID_INVALID; - arg_uid_range = UINT32_C(0x10000); + if (userns_supported()) { + arg_userns_mode = USER_NAMESPACE_PICK; + arg_uid_shift = UID_INVALID; + arg_uid_range = UINT32_C(0x10000); + + arg_settings_mask |= SETTING_USERNS; + } - arg_settings_mask |= SETTING_USERNS; break; case ARG_PRIVATE_USERS_CHOWN: @@ -990,7 +993,7 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if (arg_userns_mode != USER_NAMESPACE_NO && access("/proc/self/uid_map", F_OK) < 0) { + if (arg_userns_mode != USER_NAMESPACE_NO && !userns_supported()) { log_error("--private-users= is not supported, kernel compiled without user namespace support."); return -EOPNOTSUPP; } -- cgit v1.2.3-54-g00ecf From 88cd066e11aef5dd73b563c1753ad8bf4dfd9f62 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Apr 2016 18:10:16 +0200 Subject: nspawn: don't try to patch UIDs/GIDs of procfs and suchlike --- src/basic/missing.h | 4 ++++ src/nspawn/nspawn-patch-uid.c | 44 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/missing.h b/src/basic/missing.h index 6616f0b720..b389e94cf7 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -445,6 +445,10 @@ struct btrfs_ioctl_quota_ctl_args { #define TMPFS_MAGIC 0x01021994 #endif +#ifndef MQUEUE_MAGIC +#define MQUEUE_MAGIC 0x19800202 +#endif + #ifndef MS_MOVE #define MS_MOVE 8192 #endif diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c index f53164fbbf..429c45a3a7 100644 --- a/src/nspawn/nspawn-patch-uid.c +++ b/src/nspawn/nspawn-patch-uid.c @@ -18,16 +18,20 @@ ***/ #include +#include #ifdef HAVE_ACL #include #endif #include +#include #include #include "acl-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "missing.h" #include "nspawn-patch-uid.h" +#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" @@ -276,12 +280,46 @@ static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift return r > 0 || changed; } +static int is_procfs_sysfs_or_suchlike(int fd) { + struct statfs sfs; + + assert(fd >= 0); + + if (fstatfs(fd, &sfs) < 0) + return -errno; + + return F_TYPE_EQUAL(sfs.f_type, BINFMTFS_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, CGROUP_SUPER_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, CGROUP2_SUPER_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, DEBUGFS_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, DEVPTS_SUPER_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, EFIVARFS_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, HUGETLBFS_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, MQUEUE_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, PROC_SUPER_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, PSTOREFS_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, SELINUX_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, SMACK_MAGIC) || + F_TYPE_EQUAL(sfs.f_type, SYSFS_MAGIC); +} + static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift) { bool changed = false; int r; assert(fd >= 0); + /* We generally want to permit crossing of mount boundaries when patching the UIDs/GIDs. However, we + * probably shouldn't do this for /proc and /sys if that is already mounted into place. Hence, let's + * stop the recursion when we hit a procfs or sysfs file system. */ + r = is_procfs_sysfs_or_suchlike(fd); + if (r < 0) + goto finish; + if (r > 0) { + r = 0; /* don't recurse */ + goto finish; + } + r = patch_fd(fd, NULL, st, shift); if (r < 0) goto finish; @@ -294,8 +332,10 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift int copy; copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); - if (copy < 0) - return -errno; + if (copy < 0) { + r = -errno; + goto finish; + } fd = copy; donate_fd = true; -- cgit v1.2.3-54-g00ecf From 4aeb20f5aaec25ef969989b64d37377913b2a1ef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 12:48:05 +0200 Subject: nspawn: when readjusting UID/GID ownership of OS trees, skip read-only subtrees This should allow tools like rkt to pre-mount read-only subtrees in the OS tree, without breaking the patching code. Note that the code will still fail, if the top-level directory is already read-only. --- src/basic/fd-util.c | 10 ++++++++++ src/basic/fd-util.h | 2 ++ src/nspawn/nspawn-patch-uid.c | 18 +++++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index ec9560cd07..3d46d708c7 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -25,11 +25,13 @@ #include #include "fd-util.h" +#include "fs-util.h" #include "macro.h" #include "missing.h" #include "parse-util.h" #include "path-util.h" #include "socket-util.h" +#include "stdio-util.h" #include "util.h" int close_nointr(int fd) { @@ -356,3 +358,11 @@ bool fdname_is_valid(const char *s) { return p - s < 256; } + +int fd_get_path(int fd, char **ret) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + + return readlink_malloc(procfs_path, ret); +} diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 44528c6e35..b86e41698a 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -72,6 +72,8 @@ void cmsg_close_all(struct msghdr *mh); bool fdname_is_valid(const char *s); +int fd_get_path(int fd, char **ret); + /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c index 429c45a3a7..c7382d412d 100644 --- a/src/nspawn/nspawn-patch-uid.c +++ b/src/nspawn/nspawn-patch-uid.c @@ -303,7 +303,7 @@ static int is_procfs_sysfs_or_suchlike(int fd) { F_TYPE_EQUAL(sfs.f_type, SYSFS_MAGIC); } -static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift) { +static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift, bool is_toplevel) { bool changed = false; int r; @@ -321,6 +321,18 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift } r = patch_fd(fd, NULL, st, shift); + if (r == -EROFS) { + _cleanup_free_ char *name = NULL; + + if (!is_toplevel) { + /* When we hit a ready-only subtree we simply skip it, but log about it. */ + (void) fd_get_path(fd, &name); + log_debug("Skippping read-only file or directory %s.", strna(name)); + r = 0; + } + + goto finish; + } if (r < 0) goto finish; @@ -369,7 +381,7 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift } - r = recurse_fd(subdir_fd, true, &fst, shift); + r = recurse_fd(subdir_fd, true, &fst, shift, false); if (r < 0) goto finish; if (r > 0) @@ -433,7 +445,7 @@ static int fd_patch_uid_internal(int fd, bool donate_fd, uid_t shift, uid_t rang if (((uint32_t) (st.st_uid ^ shift) >> 16) == 0) return 0; - return recurse_fd(fd, donate_fd, &st, shift); + return recurse_fd(fd, donate_fd, &st, shift, true); finish: if (donate_fd) -- cgit v1.2.3-54-g00ecf From 26919ac110c543291b1ad6fa6f22f56253de704d Mon Sep 17 00:00:00 2001 From: Michal Koutný Date: Tue, 19 Apr 2016 18:44:40 +0200 Subject: Always create dependencies for bind mounts Dependencies were not created for _netdev mountpoints, the reasoning for this is in the commit fc676b00, i.e. to avoid adding dependencies for network mountpoints where What= appears like a path. Thus proposing this semantically more correct condition when dependencies are added for _actual_ bind mounts irrespectively of network flag. Consequently it allows to add _netdev option to bind mounts, which includes them in remote-fs.target, which simplifies configuration. --- src/core/mount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/mount.c b/src/core/mount.c index 632c5c824c..efb4a39eb4 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -274,7 +274,7 @@ static int mount_add_mount_links(Mount *m) { pm = get_mount_parameters_fragment(m); if (pm && pm->what && path_is_absolute(pm->what) && - !mount_is_network(pm)) { + (mount_is_bind(pm) || !mount_is_network(pm))) { r = unit_require_mounts_for(UNIT(m), pm->what); if (r < 0) -- cgit v1.2.3-54-g00ecf From d3bd0986bb7f3527620359aedf77253b16927ba1 Mon Sep 17 00:00:00 2001 From: Michal Koutný Date: Mon, 25 Apr 2016 13:25:00 +0200 Subject: Always create dependencies for loop device mounts In case a file is on a networked filesystem, we may tag the fstab record with _netdev option, however, corrrect dependencies will be created for this mount. --- src/core/mount.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/mount.c b/src/core/mount.c index efb4a39eb4..6cfca1a4a9 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -86,6 +86,15 @@ static bool mount_is_network(const MountParameters *p) { return mount_needs_network(p->options, p->fstype); } +static bool mount_is_loop(const MountParameters *p) { + assert(p); + + if (fstab_test_option(p->options, "loop\0")) + return true; + + return false; +} + static bool mount_is_bind(const MountParameters *p) { assert(p); @@ -269,12 +278,12 @@ static int mount_add_mount_links(Mount *m) { } /* Adds in links to other mount points that might be needed - * for the source path (if this is a bind mount) to be + * for the source path (if this is a bind mount or a loop mount) to be * available. */ pm = get_mount_parameters_fragment(m); if (pm && pm->what && path_is_absolute(pm->what) && - (mount_is_bind(pm) || !mount_is_network(pm))) { + (mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) { r = unit_require_mounts_for(UNIT(m), pm->what); if (r < 0) -- cgit v1.2.3-54-g00ecf From fa647aa978a1fb6408798e365617529c2b7e53c7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 13:42:00 +0200 Subject: sd-netlink: permit RTM_DELLINK messages with no ifindex This is useful for removing network interfaces by name. --- src/libsystemd/sd-netlink/rtnl-message.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 255526bf32..f251536a89 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -402,7 +402,6 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret, int r; assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); - assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL); assert_return(ret, -EINVAL); r = message_new(rtnl, ret, nlmsg_type); -- cgit v1.2.3-54-g00ecf From ef3b2aa7a16cae897390feda791675c9fb2e8116 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 13:42:20 +0200 Subject: nspawn: explicitly remove veth links we created after use Sometimes the kernel keeps veth links pinned after the namespace they have been joined to died. Let's hence explicitly remove veth links after use. Fixes: #2173 --- src/nspawn/nspawn-network.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ src/nspawn/nspawn-network.h | 2 ++ src/nspawn/nspawn.c | 2 ++ 3 files changed, 51 insertions(+) (limited to 'src') diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 74a0ae865b..f2b7e4dd79 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -538,3 +538,50 @@ int veth_extra_parse(char ***l, const char *p) { a = b = NULL; return 0; } + +static int remove_one_veth_link(sd_netlink *rtnl, const char *name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + if (isempty(name)) + return 0; + + r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0); + if (r < 0) + return log_error_errno(r, "Failed to allocate netlink message: %m"); + + r = sd_netlink_message_append_string(m, IFLA_IFNAME, name); + if (r < 0) + return log_error_errno(r, "Failed to add netlink interface name: %m"); + + r = sd_netlink_call(rtnl, m, 0, NULL); + if (r == -ENODEV) /* Already gone */ + return 0; + if (r < 0) + return log_error_errno(r, "Failed to remove veth interface %s: %m", name); + + return 1; +} + +int remove_veth_links(const char *primary, char **pairs) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + char **a, **b; + int r; + + /* In some cases the kernel might pin the veth links between host and container even after the namespace + * died. Hence, let's better remove them explicitly too. */ + + if (isempty(primary) && strv_isempty(pairs)) + return 0; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + remove_one_veth_link(rtnl, primary); + + STRV_FOREACH_PAIR(a, b, pairs) + remove_one_veth_link(rtnl, *a); + + return 0; +} diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index 9ab1606d1c..c5036ab470 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -34,3 +34,5 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces); int move_network_interfaces(pid_t pid, char **ifaces); int veth_extra_parse(char ***l, const char *p); + +int remove_veth_links(const char *primary, char **pairs); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e1d37d383a..d687df8a09 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3713,6 +3713,7 @@ int main(int argc, char *argv[]) { } expose_port_flush(arg_expose_ports, &exposed); + (void) remove_veth_links(veth_name, arg_network_veth_extra); } finish: @@ -3745,6 +3746,7 @@ finish: } expose_port_flush(arg_expose_ports, &exposed); + (void) remove_veth_links(veth_name, arg_network_veth_extra); free(arg_directory); free(arg_template); -- cgit v1.2.3-54-g00ecf From 5d1ce25728856956c1fbfe05b491067f83bd2216 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 00:31:24 +0200 Subject: sd-journal: add API for opening journal files or directories by fd Also, expose this via the "journalctl --file=-" syntax for STDIN. This feature remains undocumented though, as it is probably not too useful in real-life as this still requires fds that support mmaping and seeking, i.e. does not work for pipes, for which reading from STDIN is most commonly used. --- src/journal/journal-file.c | 50 ++++-- src/journal/journal-file.h | 2 + src/journal/journal-internal.h | 3 + src/journal/journalctl.c | 24 ++- src/journal/journald-server.c | 2 +- src/journal/sd-journal.c | 259 +++++++++++++++++++++++++++----- src/journal/test-journal-flush.c | 2 +- src/journal/test-journal-interleaving.c | 8 +- src/journal/test-journal-stream.c | 6 +- src/journal/test-journal-verify.c | 6 +- src/journal/test-journal.c | 10 +- src/libsystemd/libsystemd.sym | 6 + src/systemd/sd-journal.h | 2 + 13 files changed, 305 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index bed825cdc3..bd7c257e0c 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -37,6 +37,7 @@ #include "journal-file.h" #include "lookup3.h" #include "parse-util.h" +#include "path-util.h" #include "random-util.h" #include "sd-event.h" #include "set.h" @@ -362,7 +363,8 @@ JournalFile* journal_file_close(JournalFile *f) { (void) btrfs_defrag_fd(f->fd); } - safe_close(f->fd); + if (f->close_fd) + safe_close(f->fd); free(f->path); mmap_cache_unref(f->mmap); @@ -2466,8 +2468,7 @@ int journal_file_next_entry( if (p > 0 && (direction == DIRECTION_DOWN ? ofs <= p : ofs >= p)) { - log_debug("%s: entry array corrupted at entry %"PRIu64, - f->path, i); + log_debug("%s: entry array corrupted at entry %"PRIu64, f->path, i); return -EBADMSG; } @@ -2898,6 +2899,7 @@ static int journal_file_warn_btrfs(JournalFile *f) { } int journal_file_open( + int fd, const char *fname, int flags, mode_t mode, @@ -2914,22 +2916,24 @@ int journal_file_open( void *h; int r; - assert(fname); assert(ret); + assert(fd >= 0 || fname); if ((flags & O_ACCMODE) != O_RDONLY && (flags & O_ACCMODE) != O_RDWR) return -EINVAL; - if (!endswith(fname, ".journal") && - !endswith(fname, ".journal~")) - return -EINVAL; + if (fname) { + if (!endswith(fname, ".journal") && + !endswith(fname, ".journal~")) + return -EINVAL; + } f = new0(JournalFile, 1); if (!f) return -ENOMEM; - f->fd = -1; + f->fd = fd; f->mode = mode; f->flags = flags; @@ -2954,7 +2958,10 @@ int journal_file_open( } } - f->path = strdup(fname); + if (fname) + f->path = strdup(fname); + else /* If we don't know the path, fill in something explanatory and vaguely useful */ + asprintf(&f->path, "/proc/self/%i", fd); if (!f->path) { r = -ENOMEM; goto fail; @@ -2966,10 +2973,15 @@ int journal_file_open( goto fail; } - f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode); if (f->fd < 0) { - r = -errno; - goto fail; + f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode); + if (f->fd < 0) { + r = -errno; + goto fail; + } + + /* fds we opened here by us should also be closed by us. */ + f->close_fd = true; } r = journal_file_fstat(f); @@ -3090,6 +3102,9 @@ int journal_file_open( goto fail; } + /* The file is opened now successfully, thus we take possesion of any passed in fd. */ + f->close_fd = true; + *ret = f; return 0; @@ -3116,6 +3131,11 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred if (!old_file->writable) return -EINVAL; + /* Is this a journal file that was passed to us as fd? If so, we synthesized a path name for it, and we refuse + * rotation, since we don't know the actual path, and couldn't rename the file hence.*/ + if (path_startswith(old_file->path, "/proc/self/fd")) + return -EINVAL; + if (!endswith(old_file->path, ".journal")) return -EINVAL; @@ -3142,7 +3162,7 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred * we archive them */ old_file->defrag_on_close = true; - r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, deferred_closes, old_file, &new_file); + r = journal_file_open(-1, old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, deferred_closes, old_file, &new_file); if (deferred_closes && set_put(deferred_closes, old_file) >= 0) @@ -3170,7 +3190,7 @@ int journal_file_open_reliably( size_t l; _cleanup_free_ char *p = NULL; - r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); + r = journal_file_open(-1, fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); if (!IN_SET(r, -EBADMSG, /* corrupted */ -ENODATA, /* truncated */ @@ -3211,7 +3231,7 @@ int journal_file_open_reliably( log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname); - return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); + return journal_file_open(-1, fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret); } int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) { diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 9ad6013359..a0ec8c284b 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -85,6 +85,7 @@ typedef struct JournalFile { bool compress_lz4:1; bool seal:1; bool defrag_on_close:1; + bool close_fd:1; bool tail_entry_monotonic_valid:1; @@ -142,6 +143,7 @@ typedef struct JournalFile { } JournalFile; int journal_file_open( + int fd, const char *fname, int flags, mode_t mode, diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h index 7639325acf..34a48141f5 100644 --- a/src/journal/journal-internal.h +++ b/src/journal/journal-internal.h @@ -82,6 +82,8 @@ struct Directory { }; struct sd_journal { + int toplevel_fd; + char *path; char *prefix; @@ -117,6 +119,7 @@ struct sd_journal { bool on_network:1; bool no_new_files:1; + bool no_inotify:1; bool unique_file_lost:1; /* File we were iterating over got removed, and there were no more files, so sd_j_enumerate_unique diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index dcd709bd79..d6fa81061c 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -101,6 +101,7 @@ static const char *arg_after_cursor = NULL; static bool arg_show_cursor = false; static const char *arg_directory = NULL; static char **arg_file = NULL; +static bool arg_file_stdin = false; static int arg_priorities = 0xFF; static const char *arg_verify_key = NULL; #ifdef HAVE_GCRYPT @@ -592,9 +593,17 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_FILE: - r = glob_extend(&arg_file, optarg); - if (r < 0) - return log_error_errno(r, "Failed to add paths: %m"); + if (streq(optarg, "-")) + /* An undocumented feature: we can read journal files from STDIN. We don't document + * this though, since after all we only support this for mmap-able, seekable files, and + * not for example pipes which are probably the primary usecase for reading things from + * STDIN. To avoid confusion we hence don't document this feature. */ + arg_file_stdin = true; + else { + r = glob_extend(&arg_file, optarg); + if (r < 0) + return log_error_errno(r, "Failed to add paths: %m"); + } break; case ARG_ROOT: @@ -2103,7 +2112,10 @@ int main(int argc, char *argv[]) { if (arg_directory) r = sd_journal_open_directory(&j, arg_directory, arg_journal_type); - else if (arg_file) + else if (arg_file_stdin) { + int ifd = STDIN_FILENO; + r = sd_journal_open_files_fd(&j, &ifd, 1, 0); + } else if (arg_file) r = sd_journal_open_files(&j, (const char**) arg_file, 0); else if (arg_machine) r = sd_journal_open_container(&j, arg_machine, 0); @@ -2283,6 +2295,10 @@ int main(int argc, char *argv[]) { /* Opening the fd now means the first sd_journal_wait() will actually wait */ if (arg_follow) { r = sd_journal_get_fd(j); + if (r == -EMEDIUMTYPE) { + log_error_errno(r, "The --follow switch is not supported in conjunction with reading from STDIN."); + goto finish; + } if (r < 0) { log_error_errno(r, "Failed to get journal fd: %m"); goto finish; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 8089bb5883..e14d0ad980 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -253,7 +253,7 @@ static int open_journal( if (reliably) r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f); else - r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f); + r = journal_file_open(-1, fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f); if (r < 0) return r; diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 5104bc3e01..0798247326 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1233,14 +1233,37 @@ static bool file_type_wanted(int flags, const char *filename) { return false; } -static int add_any_file(sd_journal *j, const char *path) { +static bool path_has_prefix(sd_journal *j, const char *path, const char *prefix) { + assert(j); + assert(path); + assert(prefix); + + if (j->toplevel_fd >= 0) + return false; + + return path_startswith(path, prefix); +} + +static const char *skip_slash(const char *p) { + + if (!p) + return NULL; + + while (*p == '/') + p++; + + return p; +} + +static int add_any_file(sd_journal *j, int fd, const char *path) { JournalFile *f = NULL; + bool close_fd = false; int r, k; assert(j); - assert(path); + assert(fd >= 0 || path); - if (ordered_hashmap_get(j->files, path)) + if (path && ordered_hashmap_get(j->files, path)) return 0; if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { @@ -1249,8 +1272,24 @@ static int add_any_file(sd_journal *j, const char *path) { goto fail; } - r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f); + if (fd < 0 && j->toplevel_fd >= 0) { + + /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative, + * explicitly, since otherwise openat() ignores the first argument.) */ + + fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC); + if (fd < 0) { + r = log_debug_errno(errno, "Failed to open journal file %s: %m", path); + goto fail; + } + + close_fd = true; + } + + r = journal_file_open(fd, path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f); if (r < 0) { + if (close_fd) + safe_close(fd); log_debug_errno(r, "Failed to open journal file %s: %m", path); goto fail; } @@ -1259,10 +1298,16 @@ static int add_any_file(sd_journal *j, const char *path) { r = ordered_hashmap_put(j->files, f->path, f); if (r < 0) { + f->close_fd = close_fd; (void) journal_file_close(f); goto fail; } + if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run")) + j->has_runtime_files = true; + else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var")) + j->has_persistent_files = true; + log_debug("File %s added.", f->path); check_network(j, f->fd); @@ -1286,18 +1331,14 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { assert(prefix); assert(filename); - if (j->no_new_files || - !file_type_wanted(j->flags, filename)) + if (j->no_new_files) return 0; - path = strjoina(prefix, "/", filename); - - if (!j->has_runtime_files && path_startswith(path, "/run/log/journal")) - j->has_runtime_files = true; - else if (!j->has_persistent_files && path_startswith(path, "/var/log/journal")) - j->has_persistent_files = true; + if (!file_type_wanted(j->flags, filename)) + return 0; - return add_any_file(j, path); + path = strjoina(prefix, "/", filename); + return add_any_file(j, -1, path); } static void remove_file(sd_journal *j, const char *prefix, const char *filename) { @@ -1373,21 +1414,33 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) assert(j); assert(prefix); - assert(dirname); - log_debug("Considering %s/%s.", prefix, dirname); + /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch + * and reenumerates directory contents */ - if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && - !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run"))) - return 0; - - path = strjoin(prefix, "/", dirname, NULL); + if (dirname) + path = strjoin(prefix, "/", dirname, NULL); + else + path = strdup(prefix); if (!path) { r = -ENOMEM; goto fail; } - d = opendir(path); + log_debug("Considering directory %s.", path); + + /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */ + if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && + !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run"))) + return 0; + + + if (j->toplevel_fd < 0) + d = opendir(path); + else + /* Open the specified directory relative to the the toplevel fd. Enforce that the path specified is + * relative, by dropping the initial slash */ + d = xopendirat(j->toplevel_fd, skip_slash(path), 0); if (!d) { r = log_debug_errno(errno, "Failed to open directory %s: %m", path); goto fail; @@ -1419,6 +1472,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) return 0; if (m->wd <= 0 && j->inotify_fd >= 0) { + /* Watch this directory, if it not being watched yet. */ m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d), IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| @@ -1441,7 +1495,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) return 0; fail: - k = journal_put_error(j, r, path ?: dirname); + k = journal_put_error(j, r, path ?: prefix); if (k < 0) return k; @@ -1449,28 +1503,62 @@ fail: } static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { + _cleanup_closedir_ DIR *d = NULL; struct dirent *de; Directory *m; int r, k; assert(j); - assert(p); - if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) && - !path_startswith(p, "/run")) - return -EINVAL; + /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we + * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially + * populate the set, as well as to update it later. */ - if (j->prefix) - p = strjoina(j->prefix, p); + if (p) { + /* If there's a path specified, use it. */ - d = opendir(p); - if (!d) { - if (errno == ENOENT && missing_ok) - return 0; + if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) && + !path_has_prefix(j, p, "/run")) + return -EINVAL; - r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); - goto fail; + if (j->prefix) + p = strjoina(j->prefix, p); + + if (j->toplevel_fd < 0) + d = opendir(p); + else + d = xopendirat(j->toplevel_fd, skip_slash(p), 0); + + if (!d) { + if (errno == ENOENT && missing_ok) + return 0; + + r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); + goto fail; + } + } else { + int dfd; + + /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since + * opendir() will take possession of the fd, and close it, which we don't want. */ + + p = "."; /* store this as "." in the directories hashmap */ + + dfd = fcntl(j->toplevel_fd, F_DUPFD_CLOEXEC, 3); + if (dfd < 0) { + r = -errno; + goto fail; + } + + d = fdopendir(dfd); + if (!d) { + r = -errno; + safe_close(dfd); + goto fail; + } + + rewinddir(d); } m = hashmap_get(j->directories_by_path, p); @@ -1482,6 +1570,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { } m->is_root = true; + m->path = strdup(p); if (!m->path) { free(m); @@ -1585,8 +1674,7 @@ static int add_current_paths(sd_journal *j) { assert(j); assert(j->no_new_files); - /* Simply adds all directories for files we have open as - * "root" directories. We don't expect errors here, so we + /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we * treat them as fatal. */ ORDERED_HASHMAP_FOREACH(f, j->files, i) { @@ -1597,7 +1685,7 @@ static int add_current_paths(sd_journal *j) { if (!dir) return -ENOMEM; - r = add_root_directory(j, dir, true); + r = add_directory(j, dir, NULL); if (r < 0) return r; } @@ -1625,6 +1713,7 @@ static sd_journal *journal_new(int flags, const char *path) { return NULL; j->original_pid = getpid(); + j->toplevel_fd = -1; j->inotify_fd = -1; j->flags = flags; j->data_threshold = DEFAULT_DATA_THRESHOLD; @@ -1735,7 +1824,6 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f fail: sd_journal_close(j); - return r; } @@ -1752,7 +1840,7 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla return -ENOMEM; STRV_FOREACH(path, paths) { - r = add_any_file(j, *path); + r = add_any_file(j, -1, *path); if (r < 0) goto fail; } @@ -1764,7 +1852,93 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla fail: sd_journal_close(j); + return r; +} + +_public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) { + sd_journal *j; + struct stat st; + int r; + + assert_return(ret, -EINVAL); + assert_return(fd >= 0, -EBADF); + assert_return(flags == 0, -EINVAL); + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISDIR(st.st_mode)) + return -EBADFD; + + j = journal_new(flags, NULL); + if (!j) + return -ENOMEM; + j->toplevel_fd = fd; + + r = add_root_directory(j, NULL, false); + if (r < 0) + goto fail; + + *ret = j; + return 0; + +fail: + sd_journal_close(j); + return r; +} + +_public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags) { + Iterator iterator; + JournalFile *f; + sd_journal *j; + unsigned i; + int r; + + assert_return(ret, -EINVAL); + assert_return(n_fds > 0, -EBADF); + assert_return(flags == 0, -EINVAL); + + j = journal_new(flags, NULL); + if (!j) + return -ENOMEM; + + for (i = 0; i < n_fds; i++) { + struct stat st; + + if (fds[i] < 0) { + r = -EBADF; + goto fail; + } + + if (fstat(fds[i], &st) < 0) { + r = -errno; + goto fail; + } + + if (!S_ISREG(st.st_mode)) { + r = -EBADFD; + goto fail; + } + + r = add_any_file(j, fds[i], NULL); + if (r < 0) + goto fail; + } + + j->no_new_files = true; + j->no_inotify = true; + + *ret = j; + return 0; + +fail: + /* If we fail, make sure we don't take possession of the files we managed to make use of successfuly, and they + * remain open */ + ORDERED_HASHMAP_FOREACH(f, j->files, iterator) + f->close_fd = false; + + sd_journal_close(j); return r; } @@ -2091,6 +2265,9 @@ _public_ int sd_journal_get_fd(sd_journal *j) { assert_return(j, -EINVAL); assert_return(!journal_pid_changed(j), -ECHILD); + if (j->no_inotify) + return -EMEDIUMTYPE; + if (j->inotify_fd >= 0) return j->inotify_fd; @@ -2098,10 +2275,14 @@ _public_ int sd_journal_get_fd(sd_journal *j) { if (r < 0) return r; + log_debug("Reiterating files to get inotify watches established"); + /* Iterate through all dirs again, to add them to the * inotify */ if (j->no_new_files) r = add_current_paths(j); + else if (j->toplevel_fd >= 0) + r = add_root_directory(j, NULL, false); else if (j->path) r = add_root_directory(j, j->path, true); else diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c index 93dc0e0d81..ba8b20b228 100644 --- a/src/journal/test-journal-flush.c +++ b/src/journal/test-journal-flush.c @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { assert_se(mkdtemp(dn)); fn = strappend(dn, "/test.journal"); - r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, NULL, &new_journal); + r = journal_file_open(-1, fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, NULL, &new_journal); assert_se(r >= 0); r = sd_journal_open(&j, 0); diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index f887f43f0d..5e063f4d04 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -52,7 +52,7 @@ noreturn static void log_assert_errno(const char *text, int eno, const char *fil static JournalFile *test_open(const char *name) { JournalFile *f; - assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &f)); + assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &f)); return f; } @@ -216,7 +216,7 @@ static void test_sequence_numbers(void) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644, + assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &one) == 0); append_number(one, 1, &seqnum); @@ -233,7 +233,7 @@ static void test_sequence_numbers(void) { memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t)); - assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644, + assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, one, &two) == 0); assert_se(two->header->state == STATE_ONLINE); @@ -264,7 +264,7 @@ static void test_sequence_numbers(void) { /* restart server */ seqnum = 0; - assert_se(journal_file_open("two.journal", O_RDWR, 0, + assert_se(journal_file_open(-1, "two.journal", O_RDWR, 0, true, false, NULL, NULL, NULL, NULL, &two) == 0); assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id)); diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index 839ea5a9a5..7e5a980719 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -92,9 +92,9 @@ int main(int argc, char *argv[]) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &one) == 0); - assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &two) == 0); - assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &three) == 0); + assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &one) == 0); + assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &two) == 0); + assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &three) == 0); for (i = 0; i < N_ENTRIES; i++) { char *p, *q; diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index 6b4643cd25..3d2312fc55 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -55,7 +55,7 @@ static int raw_verify(const char *fn, const char *verification_key) { JournalFile *f; int r; - r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f); + r = journal_file_open(-1, fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f); if (r < 0) return r; @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) { log_info("Generating..."); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); for (n = 0; n < N_ENTRIES; n++) { struct iovec iovec; @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) { log_info("Verifying..."); - assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); /* journal_file_print_header(f); */ journal_file_dump(f); diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index ea685af782..2543d64b5b 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -42,7 +42,7 @@ static void test_non_empty(void) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f) == 0); dual_timestamp_get(&ts); @@ -131,13 +131,13 @@ static void test_empty(void) { assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, NULL, &f1) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, NULL, &f1) == 0); - assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &f2) == 0); + assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &f2) == 0); - assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, NULL, &f3) == 0); + assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, NULL, &f3) == 0); - assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f4) == 0); + assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f4) == 0); journal_file_print_header(f1); puts(""); diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 4ab637b686..0b3a1708dc 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -489,3 +489,9 @@ global: sd_journal_enumerate_fields; sd_journal_restart_fields; } LIBSYSTEMD_227; + +LIBSYSTEMD_230 { +global: + sd_journal_open_directory_fd; + sd_journal_open_files_fd; +} LIBSYSTEMD_229; diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index d4c6f409cd..06f076935e 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -84,7 +84,9 @@ enum { int sd_journal_open(sd_journal **ret, int flags); int sd_journal_open_directory(sd_journal **ret, const char *path, int flags); +int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags); int sd_journal_open_files(sd_journal **ret, const char **paths, int flags); +int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags); int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); void sd_journal_close(sd_journal *j); -- cgit v1.2.3-54-g00ecf From ae20320785da548130929ad2af758be4803931a7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 11:13:16 +0200 Subject: machined: add new OpenRootDirectory() call to Machine objects This new call returns a file descriptor for the root directory of a container. This file descriptor may then be used to access the rest of the container's file system, via openat() and similar calls. Since the file descriptor returned is for the file system namespace inside of the container it may be used to access all files of the container exactly the way the container itself would see them. This is particularly useful for containers run directly from loopback media, for example via systemd-nspawn's --image= switch. It also provides access to directories such as /run of a container that are normally not accessible to the outside of a container. This replaces PR #2870. Fixes: #2870 --- src/machine/machine-dbus.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ src/machine/machine-dbus.h | 1 + src/machine/machined-dbus.c | 21 +++++++++++ 3 files changed, 114 insertions(+) (limited to 'src') diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index ab54d9e934..5121bfdd18 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -1274,6 +1274,97 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro return 1; } +int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_close_ int fd = -1; + Machine *m = userdata; + int r; + + assert(message); + assert(m); + + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.machine1.manage-machines", + NULL, + false, + UID_INVALID, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + switch (m->class) { + + case MACHINE_HOST: + fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (fd < 0) + return -errno; + + break; + + case MACHINE_CONTAINER: { + _cleanup_close_ int mntns_fd = -1, root_fd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + + r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); + + if (child == 0) { + _cleanup_close_ int dfd = -1; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); + if (r < 0) + _exit(EXIT_FAILURE); + + dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (dfd < 0) + _exit(EXIT_FAILURE); + + r = send_one_fd(pair[1], dfd, 0); + dfd = safe_close(dfd); + if (r < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally."); + + fd = receive_one_fd(pair[0], MSG_DONTWAIT); + if (fd < 0) + return fd; + + break; + } + + default: + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines."); + } + + return sd_bus_reply_method_return(message, "h", fd); +} + const sd_bus_vtable machine_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1297,6 +1388,7 @@ const sd_bus_vtable machine_vtable[] = { 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_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h index 3a8162b171..241b23c7ec 100644 --- a/src/machine/machine-dbus.h +++ b/src/machine/machine-dbus.h @@ -38,6 +38,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu int bus_machine_method_open_shell(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 bus_machine_method_open_root_directory(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/machined-dbus.c b/src/machine/machined-dbus.c index c9639c3cf2..31efa3695b 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -706,6 +706,26 @@ static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_e return bus_machine_method_copy(message, machine, error); } +static int method_open_machine_root_directory(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_root_directory(message, machine, 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; @@ -1225,6 +1245,7 @@ const sd_bus_vtable manager_vtable[] = { 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("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, 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), -- cgit v1.2.3-54-g00ecf From d077390cdf13fc74c0f42dae959e1b5751c3b6a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 11:16:08 +0200 Subject: sd-journal: add logic to open journal files of a specific OS tree With this change a new flag SD_JOURNAL_OS_ROOT is introduced. If specified while opening the journal with the per-directory calls (specifically: sd_journal_open_directory() and sd_journal_open_directory_fd()) the passed directory is assumed to be the root directory of an OS tree, and the journal files are searched for in /var/log/journal, /run/log/journal relative to it. This is useful to allow usage of sd-journal on file descriptors returned by the OpenRootDirectory() call of machined. --- src/journal/sd-journal.c | 14 ++++++++++---- src/systemd/sd-journal.h | 9 +++++---- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 0798247326..c1be1b5faf 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1809,13 +1809,16 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f assert_return(ret, -EINVAL); assert_return(path, -EINVAL); - assert_return(flags == 0, -EINVAL); + assert_return((flags & ~SD_JOURNAL_OS_ROOT) == 0, -EINVAL); j = journal_new(flags, path); if (!j) return -ENOMEM; - r = add_root_directory(j, path, false); + if (flags & SD_JOURNAL_OS_ROOT) + r = add_search_paths(j); + else + r = add_root_directory(j, path, false); if (r < 0) goto fail; @@ -1862,7 +1865,7 @@ _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) { assert_return(ret, -EINVAL); assert_return(fd >= 0, -EBADF); - assert_return(flags == 0, -EINVAL); + assert_return((flags & ~SD_JOURNAL_OS_ROOT) == 0, -EINVAL); if (fstat(fd, &st) < 0) return -errno; @@ -1876,7 +1879,10 @@ _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) { j->toplevel_fd = fd; - r = add_root_directory(j, NULL, false); + if (flags & SD_JOURNAL_OS_ROOT) + r = add_search_paths(j); + else + r = add_root_directory(j, NULL, false); if (r < 0) goto fail; diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index 06f076935e..ac4a2f80ae 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -67,10 +67,11 @@ typedef struct sd_journal sd_journal; /* Open flags */ enum { - SD_JOURNAL_LOCAL_ONLY = 1, - SD_JOURNAL_RUNTIME_ONLY = 2, - SD_JOURNAL_SYSTEM = 4, - SD_JOURNAL_CURRENT_USER = 8, + SD_JOURNAL_LOCAL_ONLY = 1 << 0, + SD_JOURNAL_RUNTIME_ONLY = 1 << 1, + SD_JOURNAL_SYSTEM = 1 << 2, + SD_JOURNAL_CURRENT_USER = 1 << 3, + SD_JOURNAL_OS_ROOT = 1 << 4, SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */ }; -- cgit v1.2.3-54-g00ecf From c4fbc6b6e4017199717b2b8dac3d790ffd8934cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 16:23:29 +0200 Subject: journalctl: add some explanatory comments to get_boots() --- src/journal/journalctl.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index c9a2c3812d..d764ba12aa 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1103,16 +1103,16 @@ static int get_boots( return r; if (advance_older) - r = sd_journal_seek_head(j); + r = sd_journal_seek_head(j); /* seek to oldest */ else - r = sd_journal_seek_tail(j); + r = sd_journal_seek_tail(j); /* seek to newest */ if (r < 0) return r; if (advance_older) - r = sd_journal_next(j); + r = sd_journal_next(j); /* read the oldest entry */ else - r = sd_journal_previous(j); + r = sd_journal_previous(j); /* read the most recently added entry */ if (r < 0) return r; else if (r == 0) @@ -1121,15 +1121,24 @@ static int get_boots( count = 1; goto finish; } + + /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot + * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at + * the following entry, which must then have an older/newer boot ID */ } else { + if (advance_older) - r = sd_journal_seek_tail(j); + r = sd_journal_seek_tail(j); /* seek to newest */ else - r = sd_journal_seek_head(j); + r = sd_journal_seek_head(j); /* seek to oldest */ if (r < 0) return r; - /* No sd_journal_next/previous here. */ + /* No sd_journal_next()/_previous() here. + * + * At this point the read pointer is positioned after the newest/before the oldest entry in the whole + * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest + * entry we have. */ } for (;;) { -- cgit v1.2.3-54-g00ecf From d4723fb5016b6679b3ed254be3832d88804a9f87 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 16:24:05 +0200 Subject: journalctl: simplify get_boots() a bit, by getting rid of one BootId object Let's store the reference as simple sd_id128_t, since we don't actually need a BootId for it. --- src/journal/journalctl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index d764ba12aa..fbb147d1f7 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1072,7 +1072,7 @@ static int discover_next_boot( static int get_boots( sd_journal *j, BootId **boots, - BootId *query_ref_boot, + sd_id128_t *query_ref_boot, int ref_boot_offset) { bool skip_once; @@ -1085,19 +1085,19 @@ static int get_boots( /* 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; + skip_once = query_ref_boot && sd_id128_is_null(*query_ref_boot) && 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)) { + if (query_ref_boot && !sd_id128_is_null(*query_ref_boot)) { char match[9+32+1] = "_BOOT_ID="; sd_journal_flush_matches(j); - sd_id128_to_string(query_ref_boot->id, match + 9); + sd_id128_to_string(*query_ref_boot, match + 9); r = sd_journal_add_match(j, match, sizeof(match) - 1); if (r < 0) return r; @@ -1160,7 +1160,7 @@ static int get_boots( if (ref_boot_offset == 0) { count = 1; - query_ref_boot->id = current->id; + *query_ref_boot = current->id; break; } } else { @@ -1216,8 +1216,8 @@ static int list_boots(sd_journal *j) { static int add_boot(sd_journal *j) { char match[9+32+1] = "_BOOT_ID="; + sd_id128_t ref_boot_id; int r; - BootId ref_boot_id = {}; assert(j); @@ -1227,7 +1227,7 @@ 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); - ref_boot_id.id = arg_boot_id; + ref_boot_id = arg_boot_id; r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset); assert(r <= 1); if (r <= 0) { @@ -1243,7 +1243,7 @@ static int add_boot(sd_journal *j) { return r == 0 ? -ENODATA : r; } - sd_id128_to_string(ref_boot_id.id, match + 9); + sd_id128_to_string(ref_boot_id, match + 9); r = sd_journal_add_match(j, match, sizeof(match) - 1); if (r < 0) -- cgit v1.2.3-54-g00ecf From d1bf9dc9631de75c4e1fd062ac5351abebfd9592 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 16:37:09 +0200 Subject: journalctl: simplify discover_next_boot() a bit Drop the "read_realtime" parameter. Getting the realtime timestamp from an entry is cheap, as it is a normal header field, hence let's just get this unconditionally, and simplify our code a bit. --- src/journal/journalctl.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index fbb147d1f7..97310e287c 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -991,8 +991,7 @@ static void boot_id_free_all(BootId *l) { static int discover_next_boot( sd_journal *j, BootId **boot, - bool advance_older, - bool read_realtime) { + bool advance_older) { int r; char match[9+32+1] = "_BOOT_ID="; @@ -1029,11 +1028,9 @@ static int discover_next_boot( if (r < 0) return r; - if (read_realtime) { - r = sd_journal_get_realtime_usec(j, &next_boot->first); - if (r < 0) - return r; - } + 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); @@ -1057,11 +1054,9 @@ static int discover_next_boot( else if (r == 0) return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */ - if (read_realtime) { - r = sd_journal_get_realtime_usec(j, &next_boot->last); - if (r < 0) - return r; - } + r = sd_journal_get_realtime_usec(j, &next_boot->last); + if (r < 0) + return r; *boot = next_boot; next_boot = NULL; @@ -1144,7 +1139,7 @@ static int get_boots( for (;;) { _cleanup_free_ BootId *current = NULL; - r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); + r = discover_next_boot(j, ¤t, advance_older); if (r < 0) { boot_id_free_all(head); return r; -- cgit v1.2.3-54-g00ecf From d2773e59de3dd970d861e9f996bc48de20ef4314 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 17:36:51 +0200 Subject: nspawn: explicitly remove veth links after use (#3111) * sd-netlink: permit RTM_DELLINK messages with no ifindex This is useful for removing network interfaces by name. * nspawn: explicitly remove veth links we created after use Sometimes the kernel keeps veth links pinned after the namespace they have been joined to died. Let's hence explicitly remove veth links after use. Fixes: #2173 --- src/libsystemd/sd-netlink/rtnl-message.c | 1 - src/nspawn/nspawn-network.c | 47 ++++++++++++++++++++++++++++++++ src/nspawn/nspawn-network.h | 2 ++ src/nspawn/nspawn.c | 2 ++ 4 files changed, 51 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 255526bf32..f251536a89 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -402,7 +402,6 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret, int r; assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); - assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL); assert_return(ret, -EINVAL); r = message_new(rtnl, ret, nlmsg_type); diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 74a0ae865b..f2b7e4dd79 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -538,3 +538,50 @@ int veth_extra_parse(char ***l, const char *p) { a = b = NULL; return 0; } + +static int remove_one_veth_link(sd_netlink *rtnl, const char *name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + if (isempty(name)) + return 0; + + r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0); + if (r < 0) + return log_error_errno(r, "Failed to allocate netlink message: %m"); + + r = sd_netlink_message_append_string(m, IFLA_IFNAME, name); + if (r < 0) + return log_error_errno(r, "Failed to add netlink interface name: %m"); + + r = sd_netlink_call(rtnl, m, 0, NULL); + if (r == -ENODEV) /* Already gone */ + return 0; + if (r < 0) + return log_error_errno(r, "Failed to remove veth interface %s: %m", name); + + return 1; +} + +int remove_veth_links(const char *primary, char **pairs) { + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + char **a, **b; + int r; + + /* In some cases the kernel might pin the veth links between host and container even after the namespace + * died. Hence, let's better remove them explicitly too. */ + + if (isempty(primary) && strv_isempty(pairs)) + return 0; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + remove_one_veth_link(rtnl, primary); + + STRV_FOREACH_PAIR(a, b, pairs) + remove_one_veth_link(rtnl, *a); + + return 0; +} diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index 9ab1606d1c..c5036ab470 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -34,3 +34,5 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces); int move_network_interfaces(pid_t pid, char **ifaces); int veth_extra_parse(char ***l, const char *p); + +int remove_veth_links(const char *primary, char **pairs); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e1d37d383a..d687df8a09 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3713,6 +3713,7 @@ int main(int argc, char *argv[]) { } expose_port_flush(arg_expose_ports, &exposed); + (void) remove_veth_links(veth_name, arg_network_veth_extra); } finish: @@ -3745,6 +3746,7 @@ finish: } expose_port_flush(arg_expose_ports, &exposed); + (void) remove_veth_links(veth_name, arg_network_veth_extra); free(arg_directory); free(arg_template); -- cgit v1.2.3-54-g00ecf From 0808b92f0274ec76dd0c92d1f2a8332add9b2bfc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 18:06:47 +0200 Subject: journalctl: improve output of --header a bit Show the various timestamps in hexadecimal too. This is useful for matching the timestamps included in cursor strings (which are encoded in hex, too), with the references in the journal header. --- src/journal/journal-file.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index bed825cdc3..4dd1b39d02 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -2806,11 +2806,11 @@ void journal_file_print_header(JournalFile *f) { "Data Hash Table Size: %"PRIu64"\n" "Field Hash Table Size: %"PRIu64"\n" "Rotate Suggested: %s\n" - "Head Sequential Number: %"PRIu64"\n" - "Tail Sequential Number: %"PRIu64"\n" - "Head Realtime Timestamp: %s\n" - "Tail Realtime Timestamp: %s\n" - "Tail Monotonic Timestamp: %s\n" + "Head Sequential Number: %"PRIu64" (%"PRIx64")\n" + "Tail Sequential Number: %"PRIu64" (%"PRIx64")\n" + "Head Realtime Timestamp: %s (%"PRIx64")\n" + "Tail Realtime Timestamp: %s (%"PRIx64")\n" + "Tail Monotonic Timestamp: %s (%"PRIx64")\n" "Objects: %"PRIu64"\n" "Entry Objects: %"PRIu64"\n", f->path, @@ -2831,11 +2831,11 @@ void journal_file_print_header(JournalFile *f) { le64toh(f->header->data_hash_table_size) / sizeof(HashItem), le64toh(f->header->field_hash_table_size) / sizeof(HashItem), yes_no(journal_file_rotate_suggested(f, 0)), - le64toh(f->header->head_entry_seqnum), - le64toh(f->header->tail_entry_seqnum), - format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)), - format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)), - format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC), + le64toh(f->header->head_entry_seqnum), le64toh(f->header->head_entry_seqnum), + le64toh(f->header->tail_entry_seqnum), le64toh(f->header->tail_entry_seqnum), + format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)), le64toh(f->header->head_entry_realtime), + format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)), le64toh(f->header->tail_entry_realtime), + format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC), le64toh(f->header->tail_entry_monotonic), le64toh(f->header->n_objects), le64toh(f->header->n_entries)); -- cgit v1.2.3-54-g00ecf From dc00966228ff90c554fd034e588ea55eb605ec52 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 18:08:42 +0200 Subject: journalctl: don't trust the per-field entry tables when looking for boot IDs When appending to a journal file, journald will: a) first, append the actual entry to the end of the journal file b) second, add an offset reference to it to the global entry array stored at the beginning of the file c) third, add offset references to it to the per-field entry array stored at various places of the file The global entry array, maintained by b) is used when iterating through the journal without matches applied. The per-field entry array maintained by c) is used when iterating through the journal with a match for that specific field applied. In the wild, there are journal files where a) and b) were completed, but c) was not before the files were abandoned. This means, that in some cases log entries are at the end of these files that appear in the global entry array, but not in the per-field entry array of the _BOOT_ID= field. Now, the "journalctl --list-boots" command alternatingly uses the global entry array and the per-field entry array of the _BOOT_ID= field. It seeks to the last entry of a specific _BOOT_ID=field by having the right match installed, and then jumps to the next following entry with no match installed anymore, under the assumption this would bring it to the next boot ID. However, if the per-field entry wasn't written fully, it might actually turn out that the global entry array might know one more entry with the same _BOOT_ID, thus resulting in a indefinite loop around the same _BOOT_ID. This patch fixes that, by updating the boot search logic to always continue reading entries until the boot ID actually changed from the previous. Thus, the per-field entry array is used as quick jump index (i.e. as an optimization), but not trusted otherwise. Only the global entry array is trusted. This replaces PR #1904, which is actually very similar to this one. However, this one actually reads the boot ID directly from the entry header, and doesn't try to read it at all until the read pointer is actually really located on the first item to read. Fixes: #617 Replaces: #1904 --- src/journal/journalctl.c | 58 +++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 97310e287c..4b2736c9eb 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -988,17 +988,18 @@ static void boot_id_free_all(BootId *l) { } } -static int discover_next_boot( - sd_journal *j, - BootId **boot, - bool advance_older) { +static int discover_next_boot(sd_journal *j, + sd_id128_t previous_boot_id, + bool advance_older, + BootId **ret) { - int r; - char match[9+32+1] = "_BOOT_ID="; _cleanup_free_ BootId *next_boot = NULL; + char match[9+32+1] = "_BOOT_ID="; + sd_id128_t boot_id; + int r; assert(j); - assert(boot); + assert(ret); /* 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 @@ -1011,22 +1012,35 @@ static int discover_next_boot( * we can actually advance to a *different* boot. */ sd_journal_flush_matches(j); - 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. */ + do { + 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. */ + + r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); + if (r < 0) + return r; + + /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that + * normally, this will only require a single iteration, as we seeked to the last entry of the previous + * boot entry already. However, it might happen that the per-journal-field entry arrays are less + * complete than the main entry array, and hence might reference an entry that's not actually the last + * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to + * speed things up, but let's not trust that it is complete, and hence, manually advance as + * necessary. */ + + } while (sd_id128_equal(boot_id, previous_boot_id)); next_boot = new0(BootId, 1); if (!next_boot) return -ENOMEM; - r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id); - if (r < 0) - return r; + next_boot->id = boot_id; r = sd_journal_get_realtime_usec(j, &next_boot->first); if (r < 0) @@ -1058,7 +1072,7 @@ static int discover_next_boot( if (r < 0) return r; - *boot = next_boot; + *ret = next_boot; next_boot = NULL; return 0; @@ -1074,6 +1088,7 @@ static int get_boots( int r, count = 0; BootId *head = NULL, *tail = NULL; const bool advance_older = query_ref_boot && ref_boot_offset <= 0; + sd_id128_t previous_boot_id; assert(j); @@ -1136,10 +1151,11 @@ static int get_boots( * entry we have. */ } + previous_boot_id = SD_ID128_NULL; for (;;) { _cleanup_free_ BootId *current = NULL; - r = discover_next_boot(j, ¤t, advance_older); + r = discover_next_boot(j, previous_boot_id, advance_older, ¤t); if (r < 0) { boot_id_free_all(head); return r; @@ -1148,6 +1164,8 @@ static int get_boots( if (!current) break; + previous_boot_id = current->id; + if (query_ref_boot) { if (!skip_once) ref_boot_offset += advance_older ? 1 : -1; -- cgit v1.2.3-54-g00ecf From d38c62cc76a14d9a91edd8d27aa4cdcd0edc5eec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 11:21:46 +0200 Subject: journalctl: port --machine= switch to use machined's OpenMachineRootDirectory() This way, the switch becomes compatible with nspawn containers using --image=, and those which only store journal data in /run (i.e. have persistant logs off). Fixes: #49 --- src/journal/journalctl.c | 53 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index d6fa81061c..ae62170ae5 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2117,9 +2117,56 @@ int main(int argc, char *argv[]) { r = sd_journal_open_files_fd(&j, &ifd, 1, 0); } else if (arg_file) r = sd_journal_open_files(&j, (const char**) arg_file, 0); - else if (arg_machine) - r = sd_journal_open_container(&j, arg_machine, 0); - else + else if (arg_machine) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int fd; + + if (geteuid() != 0) { + /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of + * the container, thus we need root privileges to override them. */ + log_error("Using the --machine= switch requires root privileges."); + r = -EPERM; + goto finish; + } + + r = sd_bus_open_system(&bus); + if (r < 0) { + log_error_errno(r, "Failed to open system bus: %m"); + goto finish; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "OpenMachineRootDirectory", + &error, + &reply, + "s", arg_machine); + if (r < 0) { + log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r)); + goto finish; + } + + r = sd_bus_message_read(reply, "h", &fd); + if (r < 0) { + bus_log_parse_error(r); + goto finish; + } + + fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (fd < 0) { + r = log_error_errno(errno, "Failed to duplicate file descriptor: %m"); + goto finish; + } + + r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT); + if (r < 0) + safe_close(fd); + } else r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type); if (r < 0) { log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal"); -- cgit v1.2.3-54-g00ecf From 2daa9cbdda628f3a359c0e30a5b57dfe7ad74a34 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 11:31:47 +0200 Subject: sd-journal: "soft" deprecate sd_journal_open_container() Let's document the call as deprecated, since it doesn't cover containers with directories that aren#t visible to the host properly. --- src/journal/sd-journal.c | 3 +++ src/systemd/sd-journal.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index c1be1b5faf..27c1dd346f 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1767,6 +1767,9 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in char *p; int r; + /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in + * combination with sd_journal_open_directory_fd(). */ + assert_return(machine, -EINVAL); assert_return(ret, -EINVAL); assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL); diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index ac4a2f80ae..9c36b27157 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -88,7 +88,7 @@ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags); int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags); int sd_journal_open_files(sd_journal **ret, const char **paths, int flags); int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags); -int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); +int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); /* deprecated */ void sd_journal_close(sd_journal *j); int sd_journal_previous(sd_journal *j); -- cgit v1.2.3-54-g00ecf From 52051dd84c45c745ca877d8893be6f71aa27bf97 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 11:57:56 +0200 Subject: journalctl: turn --unit= in combination with --user into --user-unit= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's be nice to users, and let's turn the nonsensical "--unit=… --user" into "--user-unit=…" which the user more likely meant. Fixes #1621 --- src/journal/journalctl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index ae62170ae5..6de3489e12 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -873,6 +873,18 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } + if (!strv_isempty(arg_system_units) && (arg_journal_type == SD_JOURNAL_CURRENT_USER)) { + + /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user + * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice + * to users, and automatically turn --unit= into --user-unit= if combined with --user. */ + r = strv_extend_strv(&arg_user_units, arg_system_units, true); + if (r < 0) + return -ENOMEM; + + arg_system_units = strv_free(arg_system_units); + } + return 1; } -- cgit v1.2.3-54-g00ecf From b8f99e27e13658fd1e33c0e677f657514abc6538 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Mon, 25 Apr 2016 10:58:16 -0700 Subject: journal: fix already offline check and thread leak (#2810) Early in journal_file_set_offline() f->header->state is tested to see if it's != STATE_ONLINE, and since there's no need to do anything if the journal isn't online, the function simply returned here. Since moving part of the offlining process to a separate thread, there are two problems here: 1. We can't simply check f->header->state, because if there is an offline thread active it may modify f->header->state. 2. Even if the journal is deemed offline, the thread responsible may still need joining, so a bare return may leak the thread's resources like its stack. To address #1, the helper journal_file_is_offlining() is called prior to accessing f->header->state. If journal_file_is_offlining() returns true, f->header->state isn't even checked, because an offlining journal is obviously online, and we'll just continue with the normal set offline code path. If journal_file_is_offlining() returns false, then it's safe to check f->header->state, because the offline_state is beyond the point of modifying f->header->state, and there's a memory barrier in the helper. If we find f->header->state is != STATE_ONLINE, then we call the idempotent journal_file_set_offline_thread_join() on the way out of the function, to join a potential lingering offline thread. --- src/journal/journal-file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index bed825cdc3..12902d9f91 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -217,8 +217,10 @@ int journal_file_set_offline(JournalFile *f, bool wait) { if (!(f->fd >= 0 && f->header)) return -EINVAL; - if (f->header->state != STATE_ONLINE) - return 0; + /* An offlining journal is implicitly online and may modify f->header->state, + * we must also join any potentially lingering offline thread when not online. */ + if (!journal_file_is_offlining(f) && f->header->state != STATE_ONLINE) + return journal_file_set_offline_thread_join(f); /* Restart an in-flight offline thread and wait if needed, or join a lingering done one. */ restarted = journal_file_set_offline_try_restart(f); -- cgit v1.2.3-54-g00ecf From 0b2de9d90ddd788d8f181282607830d725bdc337 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 21:36:25 +0200 Subject: core: fix description of "resources" service error (#3119) The "resources" error is really just the generic error we return when we hit some kind of error and we have no more appropriate error for the case to return, for example because of some OS error. Hence, reword the explanation and don't claim any relation to resource limits. Admittedly, the "resources" service error is a bit of a misnomer, but I figure it's kind of API now. Fixes: #2716 --- src/core/service.h | 2 +- src/shared/bus-unit-util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/service.h b/src/core/service.h index a5ced215e4..cd9e41646e 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -80,7 +80,7 @@ typedef enum NotifyState { typedef enum ServiceResult { SERVICE_SUCCESS, - SERVICE_FAILURE_RESOURCES, + SERVICE_FAILURE_RESOURCES, /* a bit of a misnomer, just our catch-all error for errnos we didn't expect */ SERVICE_FAILURE_TIMEOUT, SERVICE_FAILURE_EXIT_CODE, SERVICE_FAILURE_SIGNAL, diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index da479aec8d..2b755cea28 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -684,7 +684,7 @@ static int bus_job_get_service_result(BusWaitForJobs *d, char **result) { static const struct { const char *result, *explanation; } explanations [] = { - { "resources", "a configured resource limit was exceeded" }, + { "resources", "of unavailable resources or another system error" }, { "timeout", "a timeout was exceeded" }, { "exit-code", "the control process exited with error code" }, { "signal", "a fatal signal was delivered to the control process" }, -- cgit v1.2.3-54-g00ecf From f56012a57cd216d247170b432059f6e59c364ff2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 21:37:51 +0200 Subject: machined: generate a nicer error when the user tries "machinectl clone" on non-btrfs file systems (#3117) Fixes: #2060 (Of course, in the long run, we should probably add a copy-based fall-back. But given how slow that is, this probably requires some asynchronous forking logic like the CopyFrom() and CopyTo() method calls already implement.) --- src/machine/image-dbus.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 73f5112c4d..b764bc43a0 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -137,6 +137,8 @@ int bus_image_method_clone( return 1; /* Will call us back */ r = image_clone(image, new_name, read_only); + if (r == -EOPNOTSUPP) + return sd_bus_reply_method_errnof(message, r, "Image cloning is currently only supported on btrfs file systems."); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 1000522a60ceade446773c67031b47a566d4a70d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 26 Apr 2016 05:19:10 -0400 Subject: systemd --user: call pam_loginuid when creating user@.service (#3120) This way the user service will have a loginuid, and it will be inherited by child services. This shouldn't change anything as far as systemd itself is concerned, but is nice for various services spawned from by systemd --user that expect a loginuid. pam_loginuid(8) says that it should be enabled for "..., crond and atd". user@.service should behave similarly to those two as far as audit is concerned. https://bugzilla.redhat.com/show_bug.cgi?id=1328947#c28 --- src/login/systemd-user.m4 | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/login/systemd-user.m4 b/src/login/systemd-user.m4 index 7933508f2b..f188a8e548 100644 --- a/src/login/systemd-user.m4 +++ b/src/login/systemd-user.m4 @@ -8,4 +8,5 @@ m4_ifdef(`HAVE_SELINUX', session required pam_selinux.so close session required pam_selinux.so nottys open )m4_dnl +session required pam_loginuid.so session include system-auth -- cgit v1.2.3-54-g00ecf From 50809d7a9c986f78d8b8872098e4880aa8ff2076 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 21:42:15 +0200 Subject: sd-journal: detect earlier if we try to read an object from an invalid offset Specifically, detect early if we try to read from offset 0, i.e. are using uninitialized offset data. --- src/journal/journal-file.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index ac6c30f9f2..c4318636f7 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -709,6 +709,10 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset if (!VALID64(offset)) return -EFAULT; + /* Object may not be located in the file header */ + if (offset < le64toh(f->header->header_size)) + return -EBADMSG; + r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From d00f1d57cc326231e7003340056f4fbcf056674c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Apr 2016 21:43:12 +0200 Subject: journal: when dumping journal contents, react nicer to lines we can't read If journal files are not cleanly closed it might happen that intermediaery journal entries cannot be read. Handle this nicely, skip over the unreadable entries, and log a debug message about it; after all we generally follow the logic that we try to make the best of corrupted files. --- src/shared/logs-show.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index cd3d53669c..9351b85eed 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -287,7 +287,10 @@ static int output_short( if (r < 0) return r; } - + if (r == -EBADMSG) { + log_debug_errno(r, "Skipping message we can't read: %m"); + return 0; + } if (r < 0) return log_error_errno(r, "Failed to get journal fields: %m"); -- cgit v1.2.3-54-g00ecf From bd30fdf213c830002aaf48a0d840c011f739ce8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 11:37:22 +0200 Subject: journal-file: always generate the same error when encountering corrupted files Let's make sure EBADMSG is the one error we throw when we encounter corrupted data, so that we can neatly test for it. --- src/journal/journal-file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index c4318636f7..e13ae05990 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -707,7 +707,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset /* Objects may only be located at multiple of 64 bit */ if (!VALID64(offset)) - return -EFAULT; + return -EBADMSG; /* Object may not be located in the file header */ if (offset < le64toh(f->header->header_size)) -- cgit v1.2.3-54-g00ecf From caeab8f626e709569cc492b75eb7e119076059e7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 11:38:39 +0200 Subject: journal-file: when iterating through a partly corruped journal file, treat error like EOF When we linearly iterate through a corrupted journal file, and we encounter a read error, don't consider this fatal, but merely as EOF condition (and log about it). --- src/journal/journal-file.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index e13ae05990..c97b3f9882 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -2469,12 +2469,18 @@ int journal_file_next_entry( le64toh(f->header->entry_array_offset), i, ret, &ofs); + if (r == -EBADMSG && direction == DIRECTION_DOWN) { + /* Special case: when we iterate throught the journal file linearly, and hit an entry we can't read, + * consider this the end of the journal file. */ + log_debug_errno(r, "Encountered entry we can't read while iterating through journal file. Considering this the end of the file."); + return 0; + } if (r <= 0) return r; if (p > 0 && (direction == DIRECTION_DOWN ? ofs <= p : ofs >= p)) { - log_debug("%s: entry array corrupted at entry %"PRIu64, f->path, i); + log_debug("%s: entry array corrupted at entry %" PRIu64, f->path, i); return -EBADMSG; } -- cgit v1.2.3-54-g00ecf From bee6a29198e7c8f6636aafece9a42c97435d171e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 11:39:48 +0200 Subject: journal-file: make seeking in corrupted files work Previously, when we used a bisection table for seeking through a corrupted file, and the end of the bisection table was corrupted we'd most likely fail the entire seek operation. Improve the situation: if we encounter invalid entries in a bisection table, linearly go backwards until we find a working entry again. --- src/journal/journal-file.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index c97b3f9882..ff01e5aa94 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -1984,9 +1984,14 @@ static int generic_array_bisect( i = right - 1; lp = p = le64toh(array->entry_array.items[i]); if (p <= 0) - return -EBADMSG; - - r = test_object(f, p, needle); + r = -EBADMSG; + else + r = test_object(f, p, needle); + if (r == -EBADMSG) { + log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (1)"); + n = i; + continue; + } if (r < 0) return r; @@ -2062,9 +2067,14 @@ static int generic_array_bisect( p = le64toh(array->entry_array.items[i]); if (p <= 0) - return -EBADMSG; - - r = test_object(f, p, needle); + r = -EBADMSG; + else + r = test_object(f, p, needle); + if (r == -EBADMSG) { + log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (2)"); + right = n = i; + continue; + } if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 6e3930c40f3379b7123e505a71ba4cd6db6c372f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 14:38:45 +0200 Subject: smaller journal fixes (#3124) * sd-journal: detect earlier if we try to read an object from an invalid offset Specifically, detect early if we try to read from offset 0, i.e. are using uninitialized offset data. * journal: when dumping journal contents, react nicer to lines we can't read If journal files are not cleanly closed it might happen that intermediaery journal entries cannot be read. Handle this nicely, skip over the unreadable entries, and log a debug message about it; after all we generally follow the logic that we try to make the best of corrupted files. * journal-file: always generate the same error when encountering corrupted files Let's make sure EBADMSG is the one error we throw when we encounter corrupted data, so that we can neatly test for it. * journal-file: when iterating through a partly corruped journal file, treat error like EOF When we linearly iterate through a corrupted journal file, and we encounter a read error, don't consider this fatal, but merely as EOF condition (and log about it). * journal-file: make seeking in corrupted files work Previously, when we used a bisection table for seeking through a corrupted file, and the end of the bisection table was corrupted we'd most likely fail the entire seek operation. Improve the situation: if we encounter invalid entries in a bisection table, linearly go backwards until we find a working entry again. * man: elaborate on the automatic systemd-journald.socket service dependencies Fixes: #1603 --- man/systemd.exec.xml | 13 ++++++++----- src/journal/journal-file.c | 36 ++++++++++++++++++++++++++++-------- src/shared/logs-show.c | 5 ++++- 3 files changed, 40 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 4ed62dbada..fea42ebd31 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -94,11 +94,10 @@ required to access /tmp and /var/tmp. - Units whose output standard output or error output is - connected to any other sink but , - and automatically - acquire dependencies of type After= on - journald.socket. + Units whose output standard output or error output is connected to , + or (or their combinations with console output, see below) + automatically acquire dependencies of type After= on + systemd-journald.socket. @@ -470,6 +469,10 @@ similar to the same option of StandardInput=. + If the standard output (or error output, see below) of a unit is connected with the journal, syslog or + the kernel log buffer the unit will implicitly gain a dependency of type After= on + systemd-journald.socket (also see the automatic dependencies section above). + This setting defaults to the value set with in systemd-system.conf5, diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index ac6c30f9f2..ff01e5aa94 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -707,7 +707,11 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset /* Objects may only be located at multiple of 64 bit */ if (!VALID64(offset)) - return -EFAULT; + return -EBADMSG; + + /* Object may not be located in the file header */ + if (offset < le64toh(f->header->header_size)) + return -EBADMSG; r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t); if (r < 0) @@ -1980,9 +1984,14 @@ static int generic_array_bisect( i = right - 1; lp = p = le64toh(array->entry_array.items[i]); if (p <= 0) - return -EBADMSG; - - r = test_object(f, p, needle); + r = -EBADMSG; + else + r = test_object(f, p, needle); + if (r == -EBADMSG) { + log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (1)"); + n = i; + continue; + } if (r < 0) return r; @@ -2058,9 +2067,14 @@ static int generic_array_bisect( p = le64toh(array->entry_array.items[i]); if (p <= 0) - return -EBADMSG; - - r = test_object(f, p, needle); + r = -EBADMSG; + else + r = test_object(f, p, needle); + if (r == -EBADMSG) { + log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (2)"); + right = n = i; + continue; + } if (r < 0) return r; @@ -2465,12 +2479,18 @@ int journal_file_next_entry( le64toh(f->header->entry_array_offset), i, ret, &ofs); + if (r == -EBADMSG && direction == DIRECTION_DOWN) { + /* Special case: when we iterate throught the journal file linearly, and hit an entry we can't read, + * consider this the end of the journal file. */ + log_debug_errno(r, "Encountered entry we can't read while iterating through journal file. Considering this the end of the file."); + return 0; + } if (r <= 0) return r; if (p > 0 && (direction == DIRECTION_DOWN ? ofs <= p : ofs >= p)) { - log_debug("%s: entry array corrupted at entry %"PRIu64, f->path, i); + log_debug("%s: entry array corrupted at entry %" PRIu64, f->path, i); return -EBADMSG; } diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index cd3d53669c..9351b85eed 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -287,7 +287,10 @@ static int output_short( if (r < 0) return r; } - + if (r == -EBADMSG) { + log_debug_errno(r, "Skipping message we can't read: %m"); + return 0; + } if (r < 0) return log_error_errno(r, "Failed to get journal fields: %m"); -- cgit v1.2.3-54-g00ecf From 25eb92e14f2bcc7743f64230d52c75e9f864d5f5 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 26 Apr 2016 09:52:30 -0400 Subject: Revert "smaller journal fixes (#3124)" This reverts commit 6e3930c40f3379b7123e505a71ba4cd6db6c372f. Merge got squashed by mistake. --- man/systemd.exec.xml | 13 +++++-------- src/journal/journal-file.c | 36 ++++++++---------------------------- src/shared/logs-show.c | 5 +---- 3 files changed, 14 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index fea42ebd31..4ed62dbada 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -94,10 +94,11 @@ required to access /tmp and /var/tmp. - Units whose output standard output or error output is connected to , - or (or their combinations with console output, see below) - automatically acquire dependencies of type After= on - systemd-journald.socket. + Units whose output standard output or error output is + connected to any other sink but , + and automatically + acquire dependencies of type After= on + journald.socket. @@ -469,10 +470,6 @@ similar to the same option of StandardInput=. - If the standard output (or error output, see below) of a unit is connected with the journal, syslog or - the kernel log buffer the unit will implicitly gain a dependency of type After= on - systemd-journald.socket (also see the automatic dependencies section above). - This setting defaults to the value set with in systemd-system.conf5, diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index ff01e5aa94..ac6c30f9f2 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -707,11 +707,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset /* Objects may only be located at multiple of 64 bit */ if (!VALID64(offset)) - return -EBADMSG; - - /* Object may not be located in the file header */ - if (offset < le64toh(f->header->header_size)) - return -EBADMSG; + return -EFAULT; r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t); if (r < 0) @@ -1984,14 +1980,9 @@ static int generic_array_bisect( i = right - 1; lp = p = le64toh(array->entry_array.items[i]); if (p <= 0) - r = -EBADMSG; - else - r = test_object(f, p, needle); - if (r == -EBADMSG) { - log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (1)"); - n = i; - continue; - } + return -EBADMSG; + + r = test_object(f, p, needle); if (r < 0) return r; @@ -2067,14 +2058,9 @@ static int generic_array_bisect( p = le64toh(array->entry_array.items[i]); if (p <= 0) - r = -EBADMSG; - else - r = test_object(f, p, needle); - if (r == -EBADMSG) { - log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (2)"); - right = n = i; - continue; - } + return -EBADMSG; + + r = test_object(f, p, needle); if (r < 0) return r; @@ -2479,18 +2465,12 @@ int journal_file_next_entry( le64toh(f->header->entry_array_offset), i, ret, &ofs); - if (r == -EBADMSG && direction == DIRECTION_DOWN) { - /* Special case: when we iterate throught the journal file linearly, and hit an entry we can't read, - * consider this the end of the journal file. */ - log_debug_errno(r, "Encountered entry we can't read while iterating through journal file. Considering this the end of the file."); - return 0; - } if (r <= 0) return r; if (p > 0 && (direction == DIRECTION_DOWN ? ofs <= p : ofs >= p)) { - log_debug("%s: entry array corrupted at entry %" PRIu64, f->path, i); + log_debug("%s: entry array corrupted at entry %"PRIu64, f->path, i); return -EBADMSG; } diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 9351b85eed..cd3d53669c 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -287,10 +287,7 @@ static int output_short( if (r < 0) return r; } - if (r == -EBADMSG) { - log_debug_errno(r, "Skipping message we can't read: %m"); - return 0; - } + if (r < 0) return log_error_errno(r, "Failed to get journal fields: %m"); -- cgit v1.2.3-54-g00ecf From 959718c62107c11f1665f813e856a0a1d5b0bb7c Mon Sep 17 00:00:00 2001 From: tblume Date: Tue, 26 Apr 2016 17:10:36 +0200 Subject: core: set start job timeout from the kernel commandline (#3112) Add the boot parameter: systemd.default_timeout_start_sec to allow modification of the default start job timeout at boot time. --- man/kernel-command-line.xml | 9 +++++++++ src/core/main.c | 9 +++++++++ 2 files changed, 18 insertions(+) (limited to 'src') diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 42d5e006bb..9c04849f66 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -321,6 +321,15 @@ + + systemd.default_timeout_start_sec= + + + Overwrites the default start job timeout DefaultTimeoutStartSec= at boot. For details, + see systemd-system.conf5. + + + modules-load= rd.modules-load= diff --git a/src/core/main.c b/src/core/main.c index 8dfb3928de..75c5ff81f2 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -413,6 +413,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { target = runlevel_to_target(key); if (target) return free_and_strdup(&arg_default_unit, target); + + } else if (streq(key, "systemd.default_timeout_start_sec") && value) { + + r = parse_sec(value, &arg_default_timeout_start_usec); + if (r < 0) + log_warning_errno(r, "Failed to parse default start timeout: %s, ignoring.", value); + + if (arg_default_timeout_start_usec <= 0) + arg_default_timeout_start_usec = USEC_INFINITY; } return 0; -- cgit v1.2.3-54-g00ecf From 8eb851711fd166024297c425e9261200c36f489d Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Tue, 26 Apr 2016 23:29:43 -0700 Subject: journal: set STATE_ARCHIVED as part of offlining (#2740) The only code path which makes a journal durable is via journal_file_set_offline(). When we perform a rotate the journal's header->state is being set to STATE_ARCHIVED prior to journal_file_set_offline() being called. In journal_file_set_offline(), we short-circuit the entire offline when f->header->state != STATE_ONLINE. This all results in none of the journal_file_set_offline() fsync() calls being reached when rotate archives a journal, so archived journals are never explicitly made durable. What we do now is instead of setting the f->header->state to STATE_ARCHIVED directly in journal_file_rotate() prior to journal_file_close(), we set an archive flag in f->archive for the journal_file_set_offline() machinery to honor by committing STATE_ARCHIVED instead of STATE_OFFLINE when set. Prior to this, rotated journals were never getting fsync() explicitly performed on them, since journal_file_set_offline() short-circuited. Obviously this is undesirable, and depends entirely on the underlying filesystem as to how much durability was achieved when simply closing the file. Note that this problem existed prior to the recent asynchronous fsync changes, but those changes do facilitate our performing this durable offline on rotate without blocking, regardless of the underlying filesystem sync-on-close semantics. --- src/journal/journal-file.c | 10 ++++++++-- src/journal/journal-file.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index ff01e5aa94..35f4abab1d 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -120,7 +120,7 @@ static void journal_file_set_offline_internal(JournalFile *f) { if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_OFFLINING)) continue; - f->header->state = STATE_OFFLINE; + f->header->state = f->archive ? STATE_ARCHIVED : STATE_OFFLINE; (void) fsync(f->fd); break; @@ -3177,7 +3177,13 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred if (r < 0 && errno != ENOENT) return -errno; - old_file->header->state = STATE_ARCHIVED; + /* Set as archive so offlining commits w/state=STATE_ARCHIVED. + * Previously we would set old_file->header->state to STATE_ARCHIVED directly here, + * but journal_file_set_offline() short-circuits when state != STATE_ONLINE, which + * would result in the rotated journal never getting fsync() called before closing. + * Now we simply queue the archive state by setting an archive bit, leaving the state + * as STATE_ONLINE so proper offlining occurs. */ + old_file->archive = true; /* Currently, btrfs is not very good with out write patterns * and fragments heavily. Let's defrag our journal files when diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index a0ec8c284b..564e1a8179 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -86,6 +86,7 @@ typedef struct JournalFile { bool seal:1; bool defrag_on_close:1; bool close_fd:1; + bool archive:1; bool tail_entry_monotonic_valid:1; -- cgit v1.2.3-54-g00ecf From 739d638a6e4f214217f60708911db6028a87a48c Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Wed, 27 Apr 2016 09:58:42 +0200 Subject: path-util: Add hidden suffixes for ucf (#3131) ucf is a standard Debian helper for managing configuration file upgrades which need more interaction or elaborate merging than conffiles managed by dpkg. Ignore its temporary and backup files similarly to the *.dpkg-* ones to avoid creating units for them in generators. https://bugs.debian.org/775903 --- src/basic/path-util.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 044a12889d..25aa355397 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -774,6 +774,9 @@ bool hidden_file_allow_backup(const char *filename) { endswith(filename, ".dpkg-bak") || endswith(filename, ".dpkg-backup") || endswith(filename, ".dpkg-remove") || + endswith(filename, ".ucf-new") || + endswith(filename, ".ucf-old") || + endswith(filename, ".ucf-dist") || endswith(filename, ".swp"); } -- cgit v1.2.3-54-g00ecf From daf535a3829121155683e63e729093347b691a3e Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Wed, 27 Apr 2016 04:32:05 -0400 Subject: Correctly parse OBJECT_PID in journald messages (#3129) The parse_pid() function doesn't succeed if we don't zero-terminate after the last digit in the buffer. --- src/journal/journald-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 3d8f05996b..a445291a5e 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -206,7 +206,7 @@ void server_process_native_message( allow_object_pid(ucred)) { char buf[DECIMAL_STR_MAX(pid_t)]; memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID=")); - char_array_0(buf); + buf[l-strlen("OBJECT_PID=")] = '\0'; /* ignore error */ parse_pid(buf, &object_pid); -- cgit v1.2.3-54-g00ecf From 0bf50960493787a76d542356a93bb22f22af8072 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 24 Apr 2016 11:31:19 -0400 Subject: machinectl: simplify option string assignment It's better to avoid having the option string duplicated, lest we forget to modify them in sync in the future. --- src/machine/machinectl.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index b03198bbf1..5a68c4ceb2 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2516,14 +2516,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argv); for (;;) { - const char *option_string; + const char * const option_string = "+hp:als:H:M:qn:o:"; - if (reorder) - option_string = "hp:als:H:M:qn:o:"; - else - option_string = "+hp:als:H:M:qn:o:"; - - c = getopt_long(argc, argv, option_string, options, NULL); + c = getopt_long(argc, argv, option_string + reorder, options, NULL); if (c < 0) { /* We generally are fine with the fact that getopt_long() reorders the command line, and looks * for switches after the main verb. However, for "shell" we really don't want that, since we -- cgit v1.2.3-54-g00ecf From b1e02ee7cf27654359f3b7843df4d4d4b52608cc Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 24 Apr 2016 21:20:26 -0400 Subject: networkd: drop unnecessary stmt --- src/network/networkd-link.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5101d553d5..8d6b9cce3d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -576,8 +576,6 @@ static void link_set_state(Link *link, LinkState state) { link->state = state; link_send_changed(link, "AdministrativeState", NULL); - - return; } static void link_enter_unmanaged(Link *link) { -- cgit v1.2.3-54-g00ecf From ddb3706d2643461a9b03044bd215e53c981d755b Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 27 Apr 2016 08:59:12 -0400 Subject: basic/dirent-util: do not call hidden_file_allow_backup from dirent_is_file_with_suffix If the file name is supposed to end in a suffix, there's not need to check the name against a list of "special" file names, which is slow. Instead, just check that the name doens't start with a period. --- src/basic/dirent-util.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index 5fb535cb13..5019882a0a 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -55,9 +55,7 @@ bool dirent_is_file(const struct dirent *de) { if (hidden_file(de->d_name)) return false; - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) + if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) return false; return true; @@ -66,12 +64,10 @@ bool dirent_is_file(const struct dirent *de) { bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { assert(de); - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) + if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) return false; - if (hidden_file_allow_backup(de->d_name)) + if (de->d_name[0] == '.') return false; return endswith(de->d_name, suffix); -- cgit v1.2.3-54-g00ecf From 55cdd057b9ab5190150b97ae26a6b7905595ba8a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 27 Apr 2016 09:24:59 -0400 Subject: tree-wide: rename hidden_file to hidden_or_backup_file and optimize In standard linux parlance, "hidden" usually means that the file name starts with ".", and nothing else. Rename the function to convey what the function does better to casual readers. Stop exposing hidden_file_allow_backup which is rather ugly and rewrite hidden_file to extract the suffix first. Note that hidden_file_allow_backup excluded files with "~" at the end, which is quite confusing. Let's get rid of it before it gets used in the wrong place. --- src/basic/dirent-util.c | 4 +- src/basic/dirent-util.h | 2 +- src/basic/fd-util.c | 2 +- src/basic/fdset.c | 2 +- src/basic/path-util.c | 52 +++++++++++----------- src/basic/path-util.h | 3 +- src/basic/util.c | 2 +- src/shared/dropin.c | 2 +- .../tty-ask-password-agent.c | 2 +- 9 files changed, 35 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index 5019882a0a..59067121b7 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -52,10 +52,10 @@ int dirent_ensure_type(DIR *d, struct dirent *de) { bool dirent_is_file(const struct dirent *de) { assert(de); - if (hidden_file(de->d_name)) + if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) return false; - if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) + if (hidden_or_backup_file(de->d_name)) return false; return true; diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h index 6bf099b46c..b91d04908f 100644 --- a/src/basic/dirent-util.h +++ b/src/basic/dirent-util.h @@ -38,7 +38,7 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pu on_error; \ } \ break; \ - } else if (hidden_file((de)->d_name)) \ + } else if (hidden_or_backup_file((de)->d_name)) \ continue; \ else diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 3d46d708c7..9130d023d7 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -231,7 +231,7 @@ int close_all_fds(const int except[], unsigned n_except) { while ((de = readdir(d))) { int fd = -1; - if (hidden_file(de->d_name)) + if (hidden_or_backup_file(de->d_name)) continue; if (safe_atoi(de->d_name, &fd) < 0) diff --git a/src/basic/fdset.c b/src/basic/fdset.c index 06f8ecbdbc..527f27bc67 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -151,7 +151,7 @@ int fdset_new_fill(FDSet **_s) { while ((de = readdir(d))) { int fd = -1; - if (hidden_file(de->d_name)) + if (hidden_or_backup_file(de->d_name)) continue; r = safe_atoi(de->d_name, &fd); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 25aa355397..100e3f5af2 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -756,37 +756,37 @@ char *file_in_same_dir(const char *path, const char *filename) { return ret; } -bool hidden_file_allow_backup(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".dpkg-tmp") || - endswith(filename, ".dpkg-dist") || - endswith(filename, ".dpkg-bak") || - endswith(filename, ".dpkg-backup") || - endswith(filename, ".dpkg-remove") || - endswith(filename, ".ucf-new") || - endswith(filename, ".ucf-old") || - endswith(filename, ".ucf-dist") || - endswith(filename, ".swp"); -} +bool hidden_or_backup_file(const char *filename) { + const char *p; -bool hidden_file(const char *filename) { assert(filename); - if (endswith(filename, "~")) + if (filename[0] == '.' || + streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || + endswith(filename, "~")) return true; - return hidden_file_allow_backup(filename); + p = strrchr(filename, '.'); + if (!p) + return false; + + return STR_IN_SET(p + 1, + "rpmnew", + "rpmsave", + "rpmorig", + "dpkg-old", + "dpkg-new", + "dpkg-tmp", + "dpkg-dist", + "dpkg-bak", + "dpkg-backup", + "dpkg-remove", + "ucf-new", + "ucf-old", + "ucf-dist", + "swp"); } bool is_device_path(const char *path) { diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 34d5cd1570..a27c13fcc3 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -122,7 +122,6 @@ bool path_is_safe(const char *p) _pure_; char *file_in_same_dir(const char *path, const char *filename); -bool hidden_file_allow_backup(const char *filename); -bool hidden_file(const char *filename) _pure_; +bool hidden_or_backup_file(const char *filename) _pure_; bool is_device_path(const char *path); diff --git a/src/basic/util.c b/src/basic/util.c index b70c50047f..756c663be4 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -522,7 +522,7 @@ int on_ac_power(void) { if (!de) break; - if (hidden_file(de->d_name)) + if (hidden_or_backup_file(de->d_name)) continue; device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); diff --git a/src/shared/dropin.c b/src/shared/dropin.c index cc1acd6f23..b9cd952ac8 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -160,7 +160,7 @@ static int iterate_dir( if (!de) break; - if (hidden_file(de->d_name)) + if (hidden_or_backup_file(de->d_name)) continue; f = strjoin(path, "/", de->d_name, NULL); 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 7b67831e54..c7ded451a2 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -481,7 +481,7 @@ static int show_passwords(void) { if (de->d_type != DT_REG) continue; - if (hidden_file(de->d_name)) + if (hidden_or_backup_file(de->d_name)) continue; if (!startswith(de->d_name, "ask.")) -- cgit v1.2.3-54-g00ecf From b05b9cde124d11f18d84abb61a27b6d0c75d4448 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Apr 2016 08:24:25 -0400 Subject: test-path-util: add a trivial test for hidden_or_backup_file --- src/test/test-path-util.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src') diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 5d77e2959c..b53324b5e6 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -489,6 +489,27 @@ static void test_filename_is_valid(void) { assert_se(filename_is_valid("o.o")); } +static void test_hidden_or_backup_file(void) { + assert_se(hidden_or_backup_file(".hidden")); + assert_se(hidden_or_backup_file("..hidden")); + assert_se(!hidden_or_backup_file("hidden.")); + + assert_se(hidden_or_backup_file("backup~")); + assert_se(hidden_or_backup_file(".backup~")); + + assert_se(hidden_or_backup_file("lost+found")); + assert_se(hidden_or_backup_file("aquota.user")); + assert_se(hidden_or_backup_file("aquota.group")); + + assert_se(hidden_or_backup_file("test.rpmnew")); + assert_se(hidden_or_backup_file("test.dpkg-old")); + assert_se(hidden_or_backup_file("test.dpkg-remove")); + assert_se(hidden_or_backup_file("test.swp")); + + assert_se(!hidden_or_backup_file("test.rpmnew.")); + assert_se(!hidden_or_backup_file("test.dpkg-old.foo")); +} + int main(int argc, char **argv) { test_path(); test_find_binary(argv[0]); @@ -502,6 +523,7 @@ int main(int argc, char **argv) { test_path_is_mount_point(); test_file_in_same_dir(); test_filename_is_valid(); + test_hidden_or_backup_file(); return 0; } -- cgit v1.2.3-54-g00ecf From 80b2ab4bc00fe18ee4e9f1325bfc7cdd055c6466 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Fri, 29 Apr 2016 00:41:50 +0900 Subject: cgtop: initialize `ours' to NULL properly (#3139) Running cgtop on a system, which lacks expecting stat file, results in a segfault. For example, a system with blkio tree but without cfq io scheduler, lacks "blkio.io_service_bytes". When the targeting cgroup's file does not exist, process() returns 0 and also does not modify `*ret' value (which is `*ours'). As a result, callers of refresh_one() can have bogus pointer, which result in SEGV. This patch just properly initialize the variable to NULL. --- src/cgtop/cgtop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 9c0e82ebb3..14eb46c8db 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -362,7 +362,7 @@ static int refresh_one( Group **ret) { _cleanup_closedir_ DIR *d = NULL; - Group *ours; + Group *ours = NULL; int r; assert(controller); -- cgit v1.2.3-54-g00ecf From 5aa3eba50c52722e57cf444432ef80acf3298a85 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Thu, 28 Apr 2016 20:48:17 +0300 Subject: nspawn: initialize the veth_name (#3141) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: $ systemd-nspawn -h ... Failed to remove veth interface ����: Operation not permitted This is a follow-up for d2773e59de3dd970d861 --- src/nspawn/nspawn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 5d39c9d7c3..8c90aa8015 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3339,7 +3339,7 @@ int main(int argc, char *argv[]) { _cleanup_close_ int master = -1, image_fd = -1; _cleanup_fdset_free_ FDSet *fds = NULL; int r, n_fd_passed, loop_nr = -1; - char veth_name[IFNAMSIZ]; + char veth_name[IFNAMSIZ] = ""; bool secondary = false, remove_subvol = false; sigset_t mask_chld; pid_t pid = 0; -- cgit v1.2.3-54-g00ecf From a44cb5cbf79cd2af699e981256fa25b6246d30d8 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Apr 2016 13:49:16 -0400 Subject: basic/mount-util: recognize pvfs2 as network fs (#3140) Added to kernel 4.6. --- src/basic/mount-util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 5faa2eba05..ba698959b7 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -498,7 +498,9 @@ bool fstype_is_network(const char *fstype) { "nfs4\0" "gfs\0" "gfs2\0" - "glusterfs\0"; + "glusterfs\0" + "pvfs2\0" /* OrangeFS */ + ; const char *x; -- cgit v1.2.3-54-g00ecf From d544d1a4d596106ffc7df3bbc4eee695e4e1ef70 Mon Sep 17 00:00:00 2001 From: Alex Crawford Date: Wed, 27 Apr 2016 23:54:47 -0700 Subject: install: upgrade message to a warning --- src/shared/install.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index b74ff6de22..1ea7e4674f 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2403,6 +2403,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char STRV_FOREACH(p, files) { _cleanup_fclose_ FILE *f; char line[LINE_MAX]; + int n = 0; f = fopen(*p, "re"); if (!f) { @@ -2417,6 +2418,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char char *l; l = strstrip(line); + n++; if (isempty(l)) continue; @@ -2443,7 +2445,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char continue; } - log_debug("Couldn't parse line '%s'", l); + log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line); } } -- cgit v1.2.3-54-g00ecf From 6fc2549711493b3374a56c3025291df16e455e25 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Fri, 29 Apr 2016 04:33:29 +0530 Subject: networkd: reconfigure IPv6 and static address after link up event (#3105) Now we are not setting static address, start dhcp6 client and discovering IPv6 routers after link gained carrier. This fixes #2912. --- src/network/networkd-link.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5101d553d5..892162136f 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1458,7 +1458,7 @@ static int link_acquire_ipv6_conf(Link *link) { return 0; } -static int link_acquire_conf(Link *link) { +static int link_acquire_ipv4_conf(Link *link) { int r; assert(link); @@ -1486,6 +1486,24 @@ static int link_acquire_conf(Link *link) { return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); } + return 0; +} + +static int link_acquire_conf(Link *link) { + int r; + + assert(link); + + r = link_acquire_ipv4_conf(link); + if (r < 0) + return r; + + if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) { + r = link_acquire_ipv6_conf(link); + if (r < 0) + return r; + } + if (link_lldp_tx_enabled(link)) { r = link_lldp_tx_start(link); if (r < 0) @@ -2351,12 +2369,6 @@ static int link_configure(Link *link) { r = link_acquire_conf(link); if (r < 0) return r; - - if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) { - r = link_acquire_ipv6_conf(link); - if (r < 0) - return r; - } } return link_enter_join_netdev(link); @@ -2739,6 +2751,10 @@ static int link_carrier_gained(Link *link) { link_enter_failed(link); return r; } + + r = link_enter_set_addresses(link); + if (r < 0) + return r; } r = link_handle_bound_by_list(link); -- cgit v1.2.3-54-g00ecf From e192a2815ef92ba8b2d6855be6cef0cbf3712272 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Fri, 29 Apr 2016 11:38:35 +0300 Subject: nspawn: convert uuid to string (#3146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: cp /etc/machine-id /var/tmp/systemd-test.HccKPa/nspawn-root/etc systemd-nspawn -D /var/tmp/systemd-test.HccKPa/nspawn-root --link-journal host -b ... Host and machine ids are equal (P�S!V): refusing to link journals --- src/nspawn/nspawn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8c90aa8015..3fc6cc955c 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1464,7 +1464,7 @@ static int setup_journal(const char *directory) { if (sd_id128_equal(arg_uuid, this_id)) { log_full(try ? LOG_WARNING : LOG_ERR, - "Host and machine ids are equal (%s): refusing to link journals", id); + "Host and machine ids are equal (%s): refusing to link journals", sd_id128_to_string(arg_uuid, id)); if (try) return 0; return -EEXIST; -- cgit v1.2.3-54-g00ecf From e4196edfbf8edcee8771be5a71b69c95ea63d604 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 29 Apr 2016 11:45:07 +0200 Subject: parse-util: fix conversion from size_t on s390 (#3147) On s390 size_t is an unsigned long, nor an unsigned int. They both are of the same size and can be cast to each other safely, but the compiler still seems unhappy about incompatible pointers. Fixes: 7c2da2ca8 --- src/basic/parse-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index c407263e16..7dc579a159 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -93,7 +93,7 @@ static inline int safe_atoli(const char *s, long int *ret_u) { #if SIZE_MAX == UINT_MAX static inline int safe_atozu(const char *s, size_t *ret_u) { assert_cc(sizeof(size_t) == sizeof(unsigned)); - return safe_atou(s, ret_u); + return safe_atou(s, (unsigned *) ret_u); } #else static inline int safe_atozu(const char *s, size_t *ret_u) { -- cgit v1.2.3-54-g00ecf From a0fe2a2d2028ea8b5e6873b1f55e91a36081656c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 15:47:55 +0200 Subject: journal: when creating a new journal file, fsync() the directory it is created in too Fixes: #2831 --- src/basic/fd-util.c | 8 +++++++- src/journal/journal-file.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 9130d023d7..8b466cff15 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -361,8 +361,14 @@ bool fdname_is_valid(const char *s) { int fd_get_path(int fd, char **ret) { char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + int r; xsprintf(procfs_path, "/proc/self/fd/%i", fd); - return readlink_malloc(procfs_path, ret); + r = readlink_malloc(procfs_path, ret); + + if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */ + return -EBADF; + + return r; } diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 35f4abab1d..a58079bdd1 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -439,6 +439,39 @@ static int journal_file_init_header(JournalFile *f, JournalFile *template) { return 0; } +static int fsync_directory_of_file(int fd) { + _cleanup_free_ char *path = NULL, *dn = NULL; + _cleanup_close_ int dfd = -1; + struct stat st; + int r; + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISREG(st.st_mode)) + return -EBADFD; + + r = fd_get_path(fd, &path); + if (r < 0) + return r; + + if (!path_is_absolute(path)) + return -EINVAL; + + dn = dirname_malloc(path); + if (!dn) + return -ENOMEM; + + dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (dfd < 0) + return -errno; + + if (fsync(dfd) < 0) + return -errno; + + return 0; +} + static int journal_file_refresh_header(JournalFile *f) { sd_id128_t boot_id; int r; @@ -464,6 +497,9 @@ static int journal_file_refresh_header(JournalFile *f) { /* Sync the online state to disk */ (void) fsync(f->fd); + /* We likely just created a new file, also sync the directory this file is located in. */ + (void) fsync_directory_of_file(f->fd); + return r; } -- cgit v1.2.3-54-g00ecf From 076ea6f6d2d9d119cd467e7776e020d5766e2577 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 16:19:28 +0200 Subject: networkd: clean up DUID code a bit Let's move DUID configuration into the [DHCP] section, since it only makes sense in a DHCP context, and should be close to the configuration of ClientIdentifier= and suchlike. This really shouldn't be a section of its own, we don't have any for any of our other per-protocol specific identifiers... Follow-up for #2890 #2943 --- man/systemd.network.xml | 59 ++++++++++++-------------------- src/network/networkd-conf.c | 55 ++++++++++++++++------------- src/network/networkd-gperf.gperf | 4 +-- src/network/networkd-network-gperf.gperf | 4 +-- src/network/networkd-network.c | 1 - 5 files changed, 57 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 9bf1b198ad..2a20748376 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -815,9 +815,8 @@ ClientIdentifier= - DHCP client identifier to use. Either mac - to use the MAC address of the link or duid - (the default) to use a RFC4361-compliant Client ID. + The DHCPv4 client identifier to use. Either mac to use the MAC address of the link + or duid (the default, see below) to use a RFC4361-compliant Client ID. @@ -827,6 +826,25 @@ type and configuration. + + DUIDRawData= + Specifies the DHCP DUID bytes as a single newline-terminated, hexadecimal string, with each + byte separated by a ':'. A DHCPv6 client sends the DHCP Unique Identifier (DUID) and the interface Identity + Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 address. Similar, DHCPv4 clients + send the IAID and DUID to the DHCP server when acquiring a dynamic IPv4 address if + . IAID and DUID allows a DHCP server to uniquely identify the machine + and the interface requesting a DHCP IP address. + + The DUID value specified here takes precedence over the DUID that systemd-networkd generates + using the machine-id from the /etc/machine-id file, as well as the + global DUID that may be specified in networkd.conf + 5. + + The configured DHCP DUID should conform to the specification in + RFC 3315, + RFC 6355. + + RequestBroadcast= @@ -846,40 +864,7 @@ - - - - - [DUID] Section Options - - This section configures the DHCP Unique Identifier (DUID) value used by DHCP - protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface - Identity Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 - address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring - a dynamic IPv4 address if . IAID and DUID allows a - DHCP server to uniquely identify the machine and the interface requesting a DHCP IP. - - The DUID value specified here overrides the DUID that systemd-networkd generates - using the machine-id from the /etc/machine-id file, as well as the - global DUID that may be specified in networkd.conf - 5. - - The configured DHCP DUID should conform to the specification in - RFC 3315, - RFC 6355. - - The following options are available in [DUID] section: - - - - - RawData= - Specifies the DUID bytes as a single newline-terminated, hexadecimal - string, with each byte separated by a ':'. - - - - + [DHCPServer] Section Options diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 73a8d16b58..70f0121d6d 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -31,7 +31,7 @@ int manager_parse_config_file(Manager *m) { return config_parse_many(PKGSYSCONFDIR "/networkd.conf", CONF_PATHS_NULSTR("systemd/networkd.conf.d"), - "DUID\0", + "DHCP\0", config_item_perf_lookup, networkd_gperf_lookup, false, m); } @@ -57,7 +57,8 @@ int config_parse_duid_rawdata( const char *rvalue, void *data, void *userdata) { - int r, n1, n2, byte; + + int r; char *cbyte; const char *pduid = rvalue; Manager *m = userdata; @@ -72,71 +73,78 @@ int config_parse_duid_rawdata( assert(rvalue); assert(userdata); - duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type - : n->duid_type; + duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type : n->duid_type; if (duidtype == _DUID_TYPE_INVALID) duidtype = DUID_TYPE_RAW; switch (duidtype) { + case DUID_TYPE_LLT: /* RawData contains DUID-LLT link-layer address (offset 6) */ duid_start_offset = 6; break; + case DUID_TYPE_EN: /* RawData contains DUID-EN identifier (offset 4) */ duid_start_offset = 4; break; + case DUID_TYPE_LL: /* RawData contains DUID-LL link-layer address (offset 2) */ duid_start_offset = 2; break; + case DUID_TYPE_UUID: /* RawData specifies UUID (offset 0) - fall thru */ + case DUID_TYPE_RAW: /* First two bytes of RawData is DUID Type - fall thru */ + default: break; } if (duidtype != DUID_TYPE_RAW) - dhcp_duid_type = (uint16_t)duidtype; + dhcp_duid_type = (uint16_t) duidtype; /* RawData contains DUID in format " NN:NN:NN... " */ for (;;) { + int n1, n2; + uint32_t byte; + r = extract_first_word(&pduid, &cbyte, ":", 0); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to read DUID, ignoring assignment: %s.", rvalue); - goto exit; + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue); + return 0; } if (r == 0) break; - if ((duid_start_offset + dhcp_duid_len) >= MAX_DUID_LEN) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Max DUID length exceeded, ignoring assignment: %s.", rvalue); - goto exit; + if (duid_start_offset + dhcp_duid_len >= MAX_DUID_LEN) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue); + return 0; } len = strlen(cbyte); - if ((len == 0) || (len > 2)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue); - goto exit; + if (len != 1 && len != 2) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue); + return 0; } - n2 = 0; n1 = unhexchar(cbyte[0]); if (len == 2) n2 = unhexchar(cbyte[1]); - if ((n1 < 0) || (n2 < 0)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue); - goto exit; + else + n2 = 0; + + if (n1 < 0 || n2 < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue); + return 0; } - byte = (n1 << (4 * (len-1))) | n2; + + byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2; /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ - if ((duidtype == DUID_TYPE_RAW) && (count < 2)) { + if (duidtype == DUID_TYPE_RAW && count < 2) { dhcp_duid_type |= (byte << (8 * (1 - count))); count++; continue; @@ -159,6 +167,5 @@ int config_parse_duid_rawdata( memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); } -exit: return 0; } diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index 0625fb335b..afc71b4cb8 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -14,5 +14,5 @@ struct ConfigPerfItem; %struct-type %includes %% -DUID.Type, config_parse_duid_type, 0, offsetof(Manager, duid_type) -DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid_type) +DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 1da99cd5bc..654d6a0316 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -28,8 +28,6 @@ Match.Architecture, config_parse_net_condition, Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid) -DUID.Type, config_parse_duid_type, 0, offsetof(Network, duid_type) -DUID.RawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) @@ -85,6 +83,8 @@ DHCP.Hostname, config_parse_hostname, DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid_type) +DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 07f8fb028f..2ebcdfa744 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -137,7 +137,6 @@ static int network_load_one(Manager *manager, const char *filename) { r = config_parse(NULL, filename, file, "Match\0" "Link\0" - "DUID\0" "Network\0" "Address\0" "Route\0" -- cgit v1.2.3-54-g00ecf From 1fcefd8815455e416c1eda3c8c1220831a2f82e9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 12:21:52 +0200 Subject: journal-file: when rotating a journal file, fsync directory too As suggested by: https://github.com/systemd/systemd/pull/3126#discussion_r61125474 --- src/journal/journal-file.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index a58079bdd1..c9ce5c73be 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -3213,6 +3213,9 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred if (r < 0 && errno != ENOENT) return -errno; + /* Sync the rename to disk */ + (void) fsync_directory_of_file(old_file->fd); + /* Set as archive so offlining commits w/state=STATE_ARCHIVED. * Previously we would set old_file->header->state to STATE_ARCHIVED directly here, * but journal_file_set_offline() short-circuits when state != STATE_ONLINE, which -- cgit v1.2.3-54-g00ecf From 941060bf5efae24eb9879e42444e15c649973473 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 13:26:12 +0200 Subject: path-util: document that we shouldn't add further entries to hidden_or_backup_file() And let's add ".bak" as a generic suffix for backups, that people can use without having to register their stuff in our list. --- src/basic/path-util.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 100e3f5af2..bcf72913df 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -772,6 +772,19 @@ bool hidden_or_backup_file(const char *filename) { if (!p) return false; + /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up + * with always new suffixes and that everybody else should just adjust to that, then it really should be on + * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt + * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional + * string. Specifically: there's now: + * + * The generic suffixes "~" and ".bak" for backup files + * The generic prefix "." for hidden files + * + * Thus, if a new package manager "foopkg" wants its own set of "foopkg-new", "foopkg-old", "foopkg-dist" or so + * registered, let's refuse that and ask them to use "foopkg-new.bak" or "foopkg-new~" instead. + */ + return STR_IN_SET(p + 1, "rpmnew", "rpmsave", @@ -786,7 +799,8 @@ bool hidden_or_backup_file(const char *filename) { "ucf-new", "ucf-old", "ucf-dist", - "swp"); + "swp", + "bak"); } bool is_device_path(const char *path) { -- cgit v1.2.3-54-g00ecf From 0e2b2caccde55ba777b84d667d19541a82c3f3a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 14:21:22 +0200 Subject: copy: also copy AF_UNIX sockets We previously would fail with EOPNOTSUPP when encountering an AF_UNIX socket in the directory tree to copy. Fix that, and copy them too (even if they are dead in the result). Fixes: #2914 --- src/basic/copy.c | 4 ++-- src/test/test-copy.c | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index 03487a6878..3001234a01 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -364,7 +364,7 @@ static int fd_copy_directory( q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name); else if (S_ISFIFO(buf.st_mode)) q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name); - else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)) + else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode)) q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name); else q = -EOPNOTSUPP; @@ -396,7 +396,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) return fd_copy_symlink(fdf, from, &st, fdt, to); else if (S_ISFIFO(st.st_mode)) return fd_copy_fifo(fdf, from, &st, fdt, to); - else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) + else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode)) return fd_copy_node(fdf, from, &st, fdt, to); else return -EOPNOTSUPP; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index cb437754b4..d1bf376385 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -95,6 +95,8 @@ static void test_copy_tree(void) { char **links = STRV_MAKE("link", "file", "link2", "dir1/file"); char **p, **link; + const char *unixsockp; + struct stat st; log_info("%s", __func__); @@ -116,6 +118,9 @@ static void test_copy_tree(void) { assert_se(symlink(f, l) == 0); } + unixsockp = strjoina(original_dir, "unixsock"); + assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0); + assert_se(copy_tree(original_dir, copy_dir, true) == 0); STRV_FOREACH(p, files) { @@ -137,6 +142,10 @@ static void test_copy_tree(void) { assert_se(path_equal(f, target)); } + unixsockp = strjoina(copy_dir, "unixsock"); + assert_se(stat(unixsockp, &st) >= 0); + assert_se(S_ISSOCK(st.st_mode)); + assert_se(copy_tree(original_dir, copy_dir, false) < 0); assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0); -- cgit v1.2.3-54-g00ecf From 2397bc4312f6d1fbdf97bf826a1ca6ad409aabf3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 14:25:52 +0200 Subject: test-copy: never call alloca() in a loop That's a total no-no, hence rework this to use malloc()-based memory instead of alloca()-based memory. Also see CODING_STYLE about this. --- src/test/test-copy.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/test/test-copy.c b/src/test/test-copy.c index d1bf376385..68154fc4e8 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -104,15 +104,19 @@ static void test_copy_tree(void) { (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); STRV_FOREACH(p, files) { - char *f = strjoina(original_dir, *p); + _cleanup_free_ char *f; + + assert_se(f = strappend(original_dir, *p)); assert_se(mkdir_parents(f, 0755) >= 0); assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0); } STRV_FOREACH_PAIR(link, p, links) { - char *f = strjoina(original_dir, *p); - char *l = strjoina(original_dir, *link); + _cleanup_free_ char *f, *l; + + assert_se(f = strappend(original_dir, *p)); + assert_se(l = strappend(original_dir, *link)); assert_se(mkdir_parents(l, 0755) >= 0); assert_se(symlink(f, l) == 0); @@ -124,9 +128,10 @@ static void test_copy_tree(void) { assert_se(copy_tree(original_dir, copy_dir, true) == 0); STRV_FOREACH(p, files) { - _cleanup_free_ char *buf = NULL; + _cleanup_free_ char *buf = NULL, *f; size_t sz = 0; - char *f = strjoina(copy_dir, *p); + + assert_se(f = strappend(copy_dir, *p)); assert_se(access(f, F_OK) == 0); assert_se(read_full_file(f, &buf, &sz) == 0); @@ -134,9 +139,10 @@ static void test_copy_tree(void) { } STRV_FOREACH_PAIR(link, p, links) { - _cleanup_free_ char *target = NULL; - char *f = strjoina(original_dir, *p); - char *l = strjoina(copy_dir, *link); + _cleanup_free_ char *target = NULL, *f, *l; + + assert_se(f = strjoin(original_dir, *p, NULL)); + assert_se(l = strjoin(copy_dir, *link, NULL)); assert_se(readlink_and_canonicalize(l, &target) == 0); assert_se(path_equal(f, target)); -- cgit v1.2.3-54-g00ecf From 313fe66fbd0cd3d62566edece7944d6cf45b1b21 Mon Sep 17 00:00:00 2001 From: kayrus Date: Fri, 29 Apr 2016 15:59:51 +0200 Subject: core: Filter by unit name behind the D-Bus, instead on the client side (#3142) This commit improves systemd performance on the systems which have thousands of units. --- src/core/dbus-manager.c | 52 ++++++++++++++++++-- src/core/org.freedesktop.systemd1.conf | 8 ++++ src/shared/install.c | 11 ++++- src/shared/install.h | 2 +- src/systemctl/systemctl.c | 88 ++++++++++++++++++++++++++++------ src/test/test-install-root.c | 2 +- src/test/test-install.c | 2 +- src/test/test-unit-file.c | 2 +- 8 files changed, 143 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index d2eb388f7c..73c50766d1 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -889,7 +889,7 @@ static int method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_e return sd_bus_reply_method_return(message, NULL); } -static int list_units_filtered(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, char **patterns) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; const char *k; @@ -929,6 +929,10 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e !strv_contains(states, unit_sub_state_to_string(u))) continue; + if (!strv_isempty(patterns) && + !strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE)) + continue; + unit_path = unit_dbus_path(u); if (!unit_path) return -ENOMEM; @@ -963,7 +967,7 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e } static int method_list_units(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return list_units_filtered(message, userdata, error, NULL); + return list_units_filtered(message, userdata, error, NULL, NULL); } static int method_list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -974,7 +978,23 @@ static int method_list_units_filtered(sd_bus_message *message, void *userdata, s if (r < 0) return r; - return list_units_filtered(message, userdata, error, states); + return list_units_filtered(message, userdata, error, states, NULL); +} + +static int method_list_units_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **states = NULL; + _cleanup_strv_free_ char **patterns = NULL; + int r; + + r = sd_bus_message_read_strv(message, &states); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &patterns); + if (r < 0) + return r; + + return list_units_filtered(message, userdata, error, states, patterns); } static int method_list_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -1465,7 +1485,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_ return sd_bus_reply_method_return(message, NULL); } -static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { +static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; UnitFileList *item; @@ -1490,7 +1510,7 @@ static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bu if (!h) return -ENOMEM; - r = unit_file_get_list(m->unit_file_scope, NULL, h); + r = unit_file_get_list(m->unit_file_scope, NULL, h, states, patterns); if (r < 0) goto fail; @@ -1518,6 +1538,26 @@ fail: return r; } +static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return list_unit_files_by_patterns(message, userdata, error, NULL, NULL); +} + +static int method_list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **states = NULL; + _cleanup_strv_free_ char **patterns = NULL; + int r; + + r = sd_bus_message_read_strv(message, &states); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &patterns); + if (r < 0) + return r; + + return list_unit_files_by_patterns(message, userdata, error, states, patterns); +} + static int method_get_unit_file_state(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; const char *name; @@ -2073,6 +2113,7 @@ const sd_bus_vtable bus_manager_vtable[] = { 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("ListUnitsByPatterns", "asas", "a(ssssssouso)", method_list_units_by_patterns, 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), @@ -2091,6 +2132,7 @@ const sd_bus_vtable bus_manager_vtable[] = { 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("ListUnitFilesByPatterns", "asas", "a(ss)", method_list_unit_files_by_patterns, 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), SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index b732501364..6c504a5e69 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -68,10 +68,18 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="ListUnitsFiltered"/> + + + + diff --git a/src/shared/install.c b/src/shared/install.c index b74ff6de22..931d3e2907 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -2653,7 +2653,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one); int unit_file_get_list( UnitFileScope scope, const char *root_dir, - Hashmap *h) { + Hashmap *h, + char **states, + char **patterns) { _cleanup_lookup_paths_free_ LookupPaths paths = {}; char **i; @@ -2685,6 +2687,9 @@ int unit_file_get_list( if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) continue; + if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE)) + continue; + if (hashmap_get(h, de->d_name)) continue; @@ -2705,6 +2710,10 @@ int unit_file_get_list( if (r < 0) f->state = UNIT_FILE_BAD; + if (!strv_isempty(states) && + !strv_contains(states, unit_file_state_to_string(f->state))) + continue; + r = hashmap_put(h, basename(f->path), f); if (r < 0) return r; diff --git a/src/shared/install.h b/src/shared/install.h index 4133faffa2..4ffc5a21f2 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -232,7 +232,7 @@ int unit_file_add_dependency( int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name); -int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); +int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns); Hashmap* unit_file_list_free(Hashmap *h); int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 595d6853c6..9af25e22a4 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -541,6 +541,7 @@ static int get_unit_list( size_t size = c; int r; UnitInfo u; + bool fallback = false; assert(bus); assert(unit_infos); @@ -552,8 +553,7 @@ static int get_unit_list( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "ListUnitsFiltered"); - + "ListUnitsByPatterns"); if (r < 0) return bus_log_create_error(r); @@ -561,7 +561,34 @@ static int get_unit_list( if (r < 0) return bus_log_create_error(r); + r = sd_bus_message_append_strv(m, patterns); + if (r < 0) + return bus_log_create_error(r); + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { + /* Fallback to legacy ListUnitsFiltered method */ + fallback = true; + log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r)); + m = sd_bus_message_unref(m); + sd_bus_error_free(&error); + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnitsFiltered"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, arg_states); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); + } if (r < 0) return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r)); @@ -572,7 +599,7 @@ static int get_unit_list( while ((r = bus_parse_unit_info(reply, &u)) > 0) { u.machine = machine; - if (!output_show_unit(&u, patterns)) + if (!output_show_unit(&u, fallback ? patterns : NULL)) continue; if (!GREEDY_REALLOC(*unit_infos, size, c+1)) @@ -1282,7 +1309,7 @@ static int compare_unit_file_list(const void *a, const void *b) { return strcasecmp(basename(u->path), basename(v->path)); } -static bool output_show_unit_file(const UnitFileList *u, char **patterns) { +static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) { assert(u); if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE)) @@ -1299,8 +1326,8 @@ static bool output_show_unit_file(const UnitFileList *u, char **patterns) { return false; } - if (!strv_isempty(arg_states) && - !strv_find(arg_states, unit_file_state_to_string(u->state))) + if (!strv_isempty(states) && + !strv_find(states, unit_file_state_to_string(u->state))) return false; return true; @@ -1373,6 +1400,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { const char *state; char *path; int r; + bool fallback = false; pager_open(arg_no_pager, false); @@ -1386,7 +1414,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { if (!h) return log_oom(); - r = unit_file_get_list(arg_scope, arg_root, h); + r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1)); if (r < 0) { unit_file_list_free(h); return log_error_errno(r, "Failed to get unit file list: %m"); @@ -1401,7 +1429,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { } HASHMAP_FOREACH(u, h, i) { - if (!output_show_unit_file(u, strv_skip(argv, 1))) + if (!output_show_unit_file(u, NULL, NULL)) continue; units[c++] = *u; @@ -1411,6 +1439,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { assert(c <= n_units); hashmap_free(h); } else { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; @@ -1418,15 +1447,44 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "ListUnitFiles", - &error, - &reply, - NULL); + "ListUnitFilesByPatterns"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, arg_states); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, strv_skip(argv, 1)); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { + /* Fallback to legacy ListUnitFiles method */ + fallback = true; + log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r)); + m = sd_bus_message_unref(m); + sd_bus_error_free(&error); + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnitFiles"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); + } if (r < 0) return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r)); @@ -1444,7 +1502,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { unit_file_state_from_string(state) }; - if (output_show_unit_file(&units[c], strv_skip(argv, 1))) + if (output_show_unit_file(&units[c], + fallback ? arg_states : NULL, + fallback ? strv_skip(argv, 1) : NULL)) c++; } diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 2d73c9743b..4680b0336d 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -606,7 +606,7 @@ static void test_preset_and_list(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(h = hashmap_new(&string_hash_ops)); - assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h) >= 0); + assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0); p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); diff --git a/src/test/test-install.c b/src/test/test-install.c index 50315c1d9a..0ac85f040a 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -50,7 +50,7 @@ int main(int argc, char* argv[]) { log_parse_environment(); h = hashmap_new(&string_hash_ops); - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); assert_se(r == 0); HASHMAP_FOREACH(p, h, i) { diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 114ddf8478..c340673c6c 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -53,7 +53,7 @@ static int test_unit_file_get_set(void) { h = hashmap_new(&string_hash_ops); assert_se(h); - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); if (r == -EPERM || r == -EACCES) { printf("Skipping test: unit_file_get_list: %s", strerror(-r)); -- cgit v1.2.3-54-g00ecf From 94a0ef6e572896140b8f28f688e881e198e2f2ab Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 29 Apr 2016 10:17:43 -0400 Subject: path-util: also support ".old" and ".new" suffixes and recommend them ~ suffix works fine, but looks to much like it the file is supposed to be automatically cleaned up. For new versions of configuration files installers might want to using something that looks more permanent like foobar.new. So let's add treat ".old" and ".new" as special. Update test to match. --- src/basic/path-util.c | 8 +++++--- test/sysv-generator-test.py | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/basic/path-util.c b/src/basic/path-util.c index bcf72913df..b2fa81a294 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -781,8 +781,8 @@ bool hidden_or_backup_file(const char *filename) { * The generic suffixes "~" and ".bak" for backup files * The generic prefix "." for hidden files * - * Thus, if a new package manager "foopkg" wants its own set of "foopkg-new", "foopkg-old", "foopkg-dist" or so - * registered, let's refuse that and ask them to use "foopkg-new.bak" or "foopkg-new~" instead. + * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist" + * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead. */ return STR_IN_SET(p + 1, @@ -800,7 +800,9 @@ bool hidden_or_backup_file(const char *filename) { "ucf-old", "ucf-dist", "swp", - "bak"); + "bak", + "old", + "new"); } bool is_device_path(const char *path) { diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py index aadc29ebeb..838dd57a6f 100755 --- a/test/sysv-generator-test.py +++ b/test/sysv-generator-test.py @@ -397,11 +397,12 @@ class SysvGeneratorTest(unittest.TestCase): # backup files (not enabled in rcN.d/) shutil.copy(script, script + '.bak') shutil.copy(script, script + '.old') + shutil.copy(script, script + '.tmp') + shutil.copy(script, script + '.new') err, results = self.run_generator() print(err) - self.assertEqual(sorted(results), - ['foo.bak.service', 'foo.old.service', 'foo.service']) + self.assertEqual(sorted(results), ['foo.service', 'foo.tmp.service']) # ensure we don't try to create a symlink to itself self.assertNotIn('itself', err) -- cgit v1.2.3-54-g00ecf From 3282493ad0038fc2051506dd0994638dd74458d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 27 Apr 2016 09:44:49 +0200 Subject: build-sys: improve compat with older kernel headers In 4.2 kernel headers, some netlink defines are missing that we need. missing.h already can add them in, but currently makes this dependent on a definition that these kernels already have. Change the check hence to check for the newest definition in the table, so that the whole bunch of definitions as added in on all kernels lacking this. --- configure.ac | 2 +- src/basic/missing.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/configure.ac b/configure.ac index d4e8ab6664..1d668623a4 100644 --- a/configure.ac +++ b/configure.ac @@ -336,7 +336,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, IFLA_BRIDGE_VLAN_INFO, IFLA_BRPORT_PROXYARP, IFLA_BRPORT_LEARNING_SYNC, - IFLA_BR_PRIORITY, + IFLA_BR_VLAN_DEFAULT_PVID, NDA_IFINDEX, IFA_FLAGS], [], [], [[ diff --git a/src/basic/missing.h b/src/basic/missing.h index b389e94cf7..22ea8f67cc 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -557,7 +557,7 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_INET6_ADDR_GEN_MODE 8 #define __IFLA_INET6_MAX 9 -#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) +#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) #define IN6_ADDR_GEN_MODE_EUI64 0 #define IN6_ADDR_GEN_MODE_NONE 1 @@ -742,7 +742,7 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif -#if !HAVE_DECL_IFLA_BR_PRIORITY +#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID #define IFLA_BR_UNSPEC 0 #define IFLA_BR_FORWARD_DELAY 1 #define IFLA_BR_HELLO_TIME 2 -- cgit v1.2.3-54-g00ecf From 8b26cdbd2a949b02c0f4d94d0e157cdb9438d246 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 20:26:15 +0200 Subject: core: introduce activation rate limiting for socket units This adds two new settings TriggerLimitIntervalSec= and TriggerLimitBurst= that define a rate limit for activation of socket units. When the limit is hit, the socket is is put into a failure mode. This is an alternative fix for #2467, since the original fix resulted in issue #2684. In a later commit the StartLimitInterval=/StartLimitBurst= rate limiter will be changed to be applied after any start conditions checks are made. This way, there are two separate rate limiters enforced: one at triggering time, before any jobs are queued with this patch, as well as the start limit that is moved again to be run immediately before the unit is activated. Condition checks are done in between the two, and thus no longer affect the start limit. --- man/systemd.socket.xml | 16 ++++++++++++++++ src/core/dbus-socket.c | 2 ++ src/core/load-fragment-gperf.gperf.m4 | 2 ++ src/core/main.c | 1 + src/core/socket.c | 20 +++++++++++++++++--- src/core/socket.h | 3 +++ 6 files changed, 41 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 2d6339680b..dc3fee5dfb 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -807,6 +807,22 @@ suffix. + + TriggerLimitIntervalSec= + TriggerLimitIntervalBurst= + + Configures a limit on how often this socket unit my be activated within a specific time + interval. The TriggerLimitIntervalSec= may be used to configure the length of the time + interval in the usual time units us, ms, s, + min, h, … and defaults to 5s (See + systemd.time7 for details on + the various time units available). The TriggerLimitBurst= setting takes an integer value and + specifies the numer of permitted activations per time interval, and defaults to 2500 (thus by default + permitting 2500 activations per 5s). Set either to 0 to disable any form of trigger rate limiting. If the limit + is hit, the socket unit is placed into a failure mode, and will not be connectible anymore until + restarted. Note that this limit is enforced before the service activation is enqueued. + + Check diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index d33e494f6b..bb09a515f8 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -149,6 +149,8 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0), SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0), SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TriggerLimitIntervalSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5568b4696f..32bb62fa63 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -297,6 +297,8 @@ Socket.RemoveOnStop, config_parse_bool, 0, Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks) Socket.FileDescriptorName, config_parse_fdname, 0, 0 Socket.Service, config_parse_socket_service, 0, 0 +Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval) +Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst) m4_ifdef(`HAVE_SMACK', `Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in) diff --git a/src/core/main.c b/src/core/main.c index 75c5ff81f2..9fcd3fe1bd 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -289,6 +289,7 @@ static int parse_crash_chvt(const char *value) { } static int set_machine_id(const char *m) { + assert(m); if (sd_id128_from_string(m, &arg_machine_id) < 0) return -EINVAL; diff --git a/src/core/socket.c b/src/core/socket.c index a9fff9c259..42260d8729 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -99,6 +99,8 @@ static void socket_init(Unit *u) { s->exec_context.std_error = u->manager->default_std_error; s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; + + RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500); } static void socket_unwatch_control_pid(Socket *s) { @@ -1887,6 +1889,9 @@ static void socket_enter_running(Socket *s, int cfd) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; + /* Note that this call takes possession of the connection fd passed. It either has to assign it somewhere or + * close it. */ + assert(s); /* We don't take connections anymore if we are supposed to @@ -1896,7 +1901,7 @@ static void socket_enter_running(Socket *s, int cfd) { log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled."); if (cfd >= 0) - safe_close(cfd); + cfd = safe_close(cfd); else { /* Flush all sockets by closing and reopening them */ socket_close_fds(s); @@ -1918,6 +1923,13 @@ static void socket_enter_running(Socket *s, int cfd) { return; } + if (!ratelimit_test(&s->trigger_limit)) { + safe_close(cfd); + log_unit_warning(UNIT(s), "Trigger limit hit, refusing further activation."); + socket_enter_stop_pre(s, SOCKET_FAILURE_TRIGGER_LIMIT_HIT); + return; + } + if (cfd < 0) { Iterator i; Unit *other; @@ -1949,7 +1961,7 @@ static void socket_enter_running(Socket *s, int cfd) { Service *service; if (s->n_connections >= s->max_connections) { - log_unit_warning(UNIT(s), "Too many incoming connections (%u)", s->n_connections); + log_unit_warning(UNIT(s), "Too many incoming connections (%u), refusing connection attempt.", s->n_connections); safe_close(cfd); return; } @@ -1965,6 +1977,7 @@ static void socket_enter_running(Socket *s, int cfd) { /* ENOTCONN is legitimate if TCP RST was received. * This connection is over, but the socket unit lives on. */ + log_unit_debug(UNIT(s), "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring."); safe_close(cfd); return; } @@ -1993,7 +2006,7 @@ static void socket_enter_running(Socket *s, int cfd) { if (r < 0) goto fail; - cfd = -1; + cfd = -1; /* We passed ownership of the fd to the service now. Forget it here. */ s->n_connections++; r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL); @@ -2806,6 +2819,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { [SOCKET_FAILURE_EXIT_CODE] = "exit-code", [SOCKET_FAILURE_SIGNAL] = "signal", [SOCKET_FAILURE_CORE_DUMP] = "core-dump", + [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" }; diff --git a/src/core/socket.h b/src/core/socket.h index b537b026a7..2a4b1bb674 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -52,6 +52,7 @@ typedef enum SocketResult { SOCKET_FAILURE_EXIT_CODE, SOCKET_FAILURE_SIGNAL, SOCKET_FAILURE_CORE_DUMP, + SOCKET_FAILURE_TRIGGER_LIMIT_HIT, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, _SOCKET_RESULT_MAX, _SOCKET_RESULT_INVALID = -1 @@ -156,6 +157,8 @@ struct Socket { bool reset_cpu_usage:1; char *fdname; + + RateLimit trigger_limit; }; /* Called from the service code when collecting fds */ -- cgit v1.2.3-54-g00ecf From 7629ec4642b03517742d09b7303c204fddf82108 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 20:34:33 +0200 Subject: core: move start ratelimiting check after condition checks With #2564 unit start rate limiting was moved from after the condition checks are to before they are made, in an attempt to fix #2467. This however resulted in #2684. However, with a previous commit a concept of per socket unit trigger rate limiting has been added, to fix #2467 more comprehensively, hence the start limit can be moved after the condition checks again, thus fixing #2684. Fixes: #2684 --- man/systemd.unit.xml | 3 ++- src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/unit.c | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 7993301167..9c869b9805 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -769,7 +769,8 @@ manually at a later point, from which point on, the restart logic is again activated. Note that systemctl reset-failed will cause the restart rate counter for a service to be flushed, which is useful if the administrator wants to manually start a unit and the start limit interferes with - that. + that. Note that this rate-limiting is enforced after any unit condition checks are executed, and hence unit + activations with failing conditions are not counted by this rate limiting. diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 32bb62fa63..5f4d66d64d 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -220,6 +220,7 @@ Service.TimeoutStartSec, config_parse_service_timeout, 0, Service.TimeoutStopSec, config_parse_service_timeout, 0, 0 Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec) Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec) +m4_dnl The following three only exist for compatibility, they moved into Unit, see above Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) diff --git a/src/core/unit.c b/src/core/unit.c index cb79c7c6b1..6c0684225a 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1497,11 +1497,6 @@ int unit_start(Unit *u) { if (UNIT_IS_ACTIVE_OR_RELOADING(state)) return -EALREADY; - /* Make sure we don't enter a busy loop of some kind. */ - r = unit_start_limit_test(u); - if (r < 0) - return r; - /* Units that aren't loaded cannot be started */ if (u->load_state != UNIT_LOADED) return -EINVAL; @@ -1543,6 +1538,11 @@ int unit_start(Unit *u) { if (!UNIT_VTABLE(u)->start) return -EBADR; + /* Make sure we don't enter a busy loop of some kind. */ + r = unit_start_limit_test(u); + if (r < 0) + return r; + /* We don't suppress calls to ->start() here when we are * already starting, to allow this request to be used as a * "hurry up" call, for example when the unit is in some "auto -- cgit v1.2.3-54-g00ecf From f0367da7d1a61ad698a55d17b5c28ddce0dc265a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Apr 2016 20:46:20 +0200 Subject: core: rename StartLimitInterval= to StartLimitIntervalSec= We generally follow the rule that for time settings we suffix the setting name with "Sec" to indicate the default unit if none is specified. The only exception was the rate limiting interval settings. Fix this, and keep the old names for compatibility. Do the same for journald's RateLimitInterval= setting --- catalog/systemd.be.catalog | 2 +- catalog/systemd.be@latin.catalog | 2 +- catalog/systemd.catalog | 2 +- catalog/systemd.da.catalog | 2 +- catalog/systemd.fr.catalog | 2 +- catalog/systemd.hu.catalog | 2 +- catalog/systemd.it.catalog | 2 +- catalog/systemd.ko.catalog | 2 +- catalog/systemd.pl.catalog | 2 +- catalog/systemd.pt_BR.catalog | 2 +- catalog/systemd.ru.catalog | 2 +- catalog/systemd.sr.catalog | 2 +- catalog/systemd.zh_CN.catalog | 2 +- catalog/systemd.zh_TW.catalog | 2 +- man/journald.conf.xml | 6 +++--- man/systemd-system.conf.xml | 6 +++--- man/systemd.unit.xml | 10 +++++----- src/core/dbus-manager.c | 3 ++- src/core/dbus-unit.c | 3 ++- src/core/load-fragment-gperf.gperf.m4 | 2 ++ src/core/main.c | 3 ++- src/core/system.conf | 2 +- src/core/user.conf | 2 +- src/journal/journald-gperf.gperf | 2 ++ src/journal/journald.conf | 2 +- 25 files changed, 38 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/catalog/systemd.be.catalog b/catalog/systemd.be.catalog index be081d6efc..051f49492f 100644 --- a/catalog/systemd.be.catalog +++ b/catalog/systemd.be.catalog @@ -53,7 +53,7 @@ Documentation: man:journald.conf(5) Паведамленні іншых сэрвісаў засталіся. Мяжа, пасля якой паведамленні будуць адкінуты, наладжваецца з -дапамогай RateLimitInterval= і RateLimitBurst= у файле +дапамогай RateLimitIntervalSec= і RateLimitBurst= у файле /etc/systemd/journald.conf. Глядзіце journald.conf(5) для дэталей. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.be@latin.catalog b/catalog/systemd.be@latin.catalog index 382fdb8b04..6ab361aafb 100644 --- a/catalog/systemd.be@latin.catalog +++ b/catalog/systemd.be@latin.catalog @@ -53,7 +53,7 @@ Majcie na ŭvazie, što byli adkinuty paviedamliennia toĺki hetaha servisu. Paviedamlienni inšych servisaŭ zastalisia. Miaža, paslia jakoj paviedamlienni buduć adkinuty, naladžvajecca z -dapamohaj RateLimitInterval= i RateLimitBurst= u fajlie +dapamohaj RateLimitIntervalSec= i RateLimitBurst= u fajlie /etc/systemd/journald.conf. Hliadzicie journald.conf(5) dlia detaliej. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.catalog b/catalog/systemd.catalog index 077f182a5a..90929bca6d 100644 --- a/catalog/systemd.catalog +++ b/catalog/systemd.catalog @@ -66,7 +66,7 @@ Note that only messages from the service in question have been dropped, other services' messages are unaffected. The limits controlling when messages are dropped may be configured -with RateLimitInterval= and RateLimitBurst= in +with RateLimitIntervalSec= and RateLimitBurst= in /etc/systemd/journald.conf. See journald.conf(5) for details. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.da.catalog b/catalog/systemd.da.catalog index bd4d742d8a..093e8139da 100644 --- a/catalog/systemd.da.catalog +++ b/catalog/systemd.da.catalog @@ -52,7 +52,7 @@ Kun beskeder fra omtalte service er smidt væk. Beskeder fra andre services er ikke påvirket. Grænsen for hvornår beskeder bliver smidt væk kan konfigureres -med RateLimitInterval= og RateLimitBurst= i +med RateLimitIntervalSec= og RateLimitBurst= i /etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.fr.catalog b/catalog/systemd.fr.catalog index 03a457786f..d71c2902d7 100644 --- a/catalog/systemd.fr.catalog +++ b/catalog/systemd.fr.catalog @@ -51,7 +51,7 @@ Notez que seuls des messages de ce service ont été évincés, les messages des autres services ne sont pas affectés. Les limites définissant ce comportement peuvent être configurées avec les -paramètres RateLimitInterval= et RateLimitBurst= dans le fichier +paramètres RateLimitIntervalSec= et RateLimitBurst= dans le fichier /etc/systemd/journald.conf. Voir journald.conf(5) pour plus de détails. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.hu.catalog b/catalog/systemd.hu.catalog index 30d76916cc..68e8c2572e 100644 --- a/catalog/systemd.hu.catalog +++ b/catalog/systemd.hu.catalog @@ -51,7 +51,7 @@ Ne feledje, hogy csak a kérdéses szolgáltatás üzenetei kerültek eldobásra más szolgáltatások üzeneteit ez nem befolyásolja. Az üzenetek eldobását vezérlő korlátok az /etc/systemd/journald.conf -RateLimitInterval= és RateLimitBurst= beállításaival adhatók meg. +RateLimitIntervalSec= és RateLimitBurst= beállításaival adhatók meg. Részletekért lásd a journald.conf(5) man oldalt. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.it.catalog b/catalog/systemd.it.catalog index 861b92b74a..b6fca48221 100644 --- a/catalog/systemd.it.catalog +++ b/catalog/systemd.it.catalog @@ -46,7 +46,7 @@ Solo i messaggi del servizio indicato sono stati eliminati, i messaggi degli altri servizi rimangono invariati. I limiti oltre i quali i messaggi si eliminano si configurano -con RateLimitInterval= e RateLimitBurst= in +con RateLimitIntervalSec= e RateLimitBurst= in /etc/systemd/journald.conf. Vedi journald.conf(5) per maggiori informazioni. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.ko.catalog b/catalog/systemd.ko.catalog index 3c3535a94c..2fc6b60b1b 100644 --- a/catalog/systemd.ko.catalog +++ b/catalog/systemd.ko.catalog @@ -55,7 +55,7 @@ Documentation: man:journald.conf(5) 다른 서비스의 메시지에는 영향을 주지 않습니다. 메시지 거절 제어 제한 값은 /etc/systemd/journald.conf 의 -RateLimitInterval= 변수와 RateLimitBurst= 변수로 설정합니다. +RateLimitIntervalSec= 변수와 RateLimitBurst= 변수로 설정합니다. 자세한 내용은 ournald.conf(5)를 살펴보십시오. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.pl.catalog b/catalog/systemd.pl.catalog index 0d2e3d22cf..d8059e93cd 100644 --- a/catalog/systemd.pl.catalog +++ b/catalog/systemd.pl.catalog @@ -69,7 +69,7 @@ Proszę zauważyć, że tylko komunikaty z danej usługi zostały pominięte. Ni to wpływu na komunikaty innych usług. Ograniczenia kontrolujące pomijanie komunikatów mogą być konfigurowane -za pomocą opcji RateLimitInterval= i RateLimitBurst= w pliku +za pomocą opcji RateLimitIntervalSec= i RateLimitBurst= w pliku /etc/systemd/journald.conf. Strona journald.conf(5) zawiera więcej informacji. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.pt_BR.catalog b/catalog/systemd.pt_BR.catalog index d9716e30f7..8b856e8355 100644 --- a/catalog/systemd.pt_BR.catalog +++ b/catalog/systemd.pt_BR.catalog @@ -53,7 +53,7 @@ Note que apenas mensagens de um serviço em questão foram descartadas; outras mensagens dos serviços não foram afetadas. Os controles de limites de quando as mensagens são descartadas pode ser -configurado com RateLimitInterval= e RateLimitBurst= no +configurado com RateLimitIntervalSec= e RateLimitBurst= no /etc/systemd/journald.conf. Veja journald.conf(5) para detalhes. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.ru.catalog b/catalog/systemd.ru.catalog index eedbb8aa9c..e56dbe3acc 100644 --- a/catalog/systemd.ru.catalog +++ b/catalog/systemd.ru.catalog @@ -76,7 +76,7 @@ Documentation: man:journald.conf(5) сообщения других служб не затронуты. Предел, после которого служба журнала начинает игнорировать сообщения, -настраивается параметрами RateLimitInterval= и RateLimitBurst= в файле +настраивается параметрами RateLimitIntervalSec= и RateLimitBurst= в файле /etc/systemd/journald.conf. Подробности смотрите на странице руководства journald.conf(5). diff --git a/catalog/systemd.sr.catalog b/catalog/systemd.sr.catalog index cf700c477b..cc689b7956 100644 --- a/catalog/systemd.sr.catalog +++ b/catalog/systemd.sr.catalog @@ -52,7 +52,7 @@ Documentation: man:journald.conf(5) услуге нису захваћене овим. Ограничења која подешавају начин на који се поруке одбацују се могу подесити -помоћу „RateLimitInterval=“ и „RateLimitBurst=“ параметара унутар датотеке +помоћу „RateLimitIntervalSec=“ и „RateLimitBurst=“ параметара унутар датотеке /etc/systemd/journald.conf. Погледајте journald.conf(5) за појединости. -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/catalog/systemd.zh_CN.catalog b/catalog/systemd.zh_CN.catalog index 38639109e4..ed59fc9250 100644 --- a/catalog/systemd.zh_CN.catalog +++ b/catalog/systemd.zh_CN.catalog @@ -50,7 +50,7 @@ Documentation: man:journald.conf(5) 请注意只有由有问题的服务传来的消息被丢弃, 其它服务的消息不受影响。 -可以在 /etc/systemd/journald.conf 中设定 RateLimitInterval= +可以在 /etc/systemd/journald.conf 中设定 RateLimitIntervalSec= 以及 RateLimitBurst = 的值以控制丢弃信息的限制。 请参见 journald.conf(5) 以了解详情。 diff --git a/catalog/systemd.zh_TW.catalog b/catalog/systemd.zh_TW.catalog index 027ffe44e5..aa5004db08 100644 --- a/catalog/systemd.zh_TW.catalog +++ b/catalog/systemd.zh_TW.catalog @@ -53,7 +53,7 @@ Documentation: man:journald.conf(5) 其他服務的訊息則不受影響。 可以在 /etc/systemd/journald.conf 中設定 -RateLimitInterval= 以及 RateLimitBurst= +RateLimitIntervalSec= 以及 RateLimitBurst= 來控制當訊息要開始被丟棄時的限制。參見 journald.conf(5) 以獲得更多資訊。 -- e9bf28e6e834481bb6f48f548ad13606 diff --git a/man/journald.conf.xml b/man/journald.conf.xml index a9690e8138..3964cd6bc5 100644 --- a/man/journald.conf.xml +++ b/man/journald.conf.xml @@ -148,12 +148,12 @@ - RateLimitInterval= + RateLimitIntervalSec= RateLimitBurst= Configures the rate limiting that is applied to all messages generated on the system. If, in the time - interval defined by RateLimitInterval=, + interval defined by RateLimitIntervalSec=, more messages than specified in RateLimitBurst= are logged by a service, all further messages within the interval are dropped until the @@ -162,7 +162,7 @@ per-service, so that two services which log do not interfere with each other's limits. Defaults to 1000 messages in 30s. The time specification for - RateLimitInterval= may be specified in the + RateLimitIntervalSec= may be specified in the following units: s, min, h, ms, us. To turn off any kind of rate limiting, diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index edc6df914a..8833e73c72 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -271,16 +271,16 @@ - DefaultStartLimitInterval= + DefaultStartLimitIntervalSec= DefaultStartLimitBurst= Configure the default unit start rate limiting, as configured per-service by - StartLimitInterval= and + StartLimitIntervalSec= and StartLimitBurst=. See systemd.service5 for details on the per-service settings. - DefaultStartLimitInterval= defaults to + DefaultStartLimitIntervalSec= defaults to 10s. DefaultStartLimitBurst= defaults to 5. diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 9c869b9805..f4b13a7a77 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -751,14 +751,14 @@ - StartLimitInterval= + StartLimitIntervalSec= StartLimitBurst= Configure unit start rate limiting. By default, units which are started more than 5 times within 10 seconds are not permitted to start any more times until the 10 second interval ends. With these two - options, this rate limiting may be modified. Use StartLimitInterval= to configure the - checking interval (defaults to DefaultStartLimitInterval= in manager configuration file, set - to 0 to disable any kind of rate limiting). Use StartLimitBurst= to configure how many + options, this rate limiting may be modified. Use StartLimitIntervalSec= to configure the + checking interval (defaults to DefaultStartLimitIntervalSec= in manager configuration file, + set to 0 to disable any kind of rate limiting). Use StartLimitBurst= to configure how many starts per interval are allowed (defaults to DefaultStartLimitBurst= in manager configuration file). These configuration options are particularly useful in conjunction with the service setting Restart= (see @@ -777,7 +777,7 @@ StartLimitAction= Configure the action to take if the rate limit configured with - StartLimitInterval= and StartLimitBurst= is hit. Takes one of + StartLimitIntervalSec= and StartLimitBurst= is hit. Takes one of , , , , , or . If is set, hitting the rate limit will trigger no diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 73c50766d1..d45f511489 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2050,7 +2050,8 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */ SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index abe30413c3..e912fe2192 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -704,7 +704,8 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), 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_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */ SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5f4d66d64d..928b913c7b 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -164,6 +164,8 @@ Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LE Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout) Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action) Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) +Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval) +m4_dnl The following is a legacy alias name for compatibility Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) diff --git a/src/core/main.c b/src/core/main.c index 9fcd3fe1bd..ed4d42c8cc 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -670,7 +670,8 @@ static int parse_config_file(void) { { "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec }, { "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec }, { "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec }, - { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, + { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, /* obsolete alias */ + { "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval }, { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, { "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit }, diff --git a/src/core/system.conf b/src/core/system.conf index e2ded27333..eacd7ee282 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -34,7 +34,7 @@ #DefaultTimeoutStartSec=90s #DefaultTimeoutStopSec=90s #DefaultRestartSec=100ms -#DefaultStartLimitInterval=10s +#DefaultStartLimitIntervalSec=10s #DefaultStartLimitBurst=5 #DefaultEnvironment= #DefaultCPUAccounting=no diff --git a/src/core/user.conf b/src/core/user.conf index 87c8164378..b427f1ef6d 100644 --- a/src/core/user.conf +++ b/src/core/user.conf @@ -23,7 +23,7 @@ #DefaultTimeoutStartSec=90s #DefaultTimeoutStopSec=90s #DefaultRestartSec=100ms -#DefaultStartLimitInterval=10s +#DefaultStartLimitIntervalSec=10s #DefaultStartLimitBurst=5 #DefaultEnvironment= #DefaultLimitCPU= diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf index c154610c54..7fecd7a964 100644 --- a/src/journal/journald-gperf.gperf +++ b/src/journal/journald-gperf.gperf @@ -19,7 +19,9 @@ Journal.Storage, config_parse_storage, 0, offsetof(Server, storage Journal.Compress, config_parse_bool, 0, offsetof(Server, compress) Journal.Seal, config_parse_bool, 0, offsetof(Server, seal) Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec) +# The following is a legacy name for compatibility Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, rate_limit_interval) +Journal.RateLimitIntervalSec,config_parse_sec, 0, offsetof(Server, rate_limit_interval) Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_limit_burst) Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use) Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size) diff --git a/src/journal/journald.conf b/src/journal/journald.conf index 7beb96c671..2541b949be 100644 --- a/src/journal/journald.conf +++ b/src/journal/journald.conf @@ -17,7 +17,7 @@ #Seal=yes #SplitMode=uid #SyncIntervalSec=5m -#RateLimitInterval=30s +#RateLimitIntervalSec=30s #RateLimitBurst=1000 #SystemMaxUse= #SystemKeepFree= -- cgit v1.2.3-54-g00ecf From 7f2fbbff06519a486a37ad140ea9200513d42747 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Apr 2016 16:51:30 +0200 Subject: core: minor error path fix In service_set_socket_fd(), let's make sure that if we can't add the requested dependencies we take no possession of the passed connection fd. This way, we follow the strict rule: we take possession of the passed fd on success, but on failure we don't, and the fd remains in possession of the caller. --- src/core/service.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/service.c b/src/core/service.c index b46dd8bcdd..3c4328c584 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -3139,9 +3139,8 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context assert(s); assert(fd >= 0); - /* This is called by the socket code when instantiating a new - * service for a stream socket and the socket needs to be - * configured. */ + /* This is called by the socket code when instantiating a new service for a stream socket and the socket needs + * to be configured. We take ownership of the passed fd on success. */ if (UNIT(s)->load_state != UNIT_LOADED) return -EINVAL; @@ -3169,12 +3168,15 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context return r; } + r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false); + if (r < 0) + return r; + s->socket_fd = fd; s->socket_fd_selinux_context_net = selinux_context_net; unit_ref_set(&s->accept_socket, UNIT(sock)); - - return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false); + return 0; } static void service_reset_failed(Unit *u) { -- cgit v1.2.3-54-g00ecf From 3e7a1f50e473a374e1657d2051237e2db04c4db2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Apr 2016 17:09:50 +0200 Subject: core: make sure to close connection fd when we fail to activate a per-connection service Fixes: #2993 #2691 --- src/core/service.c | 2 +- src/core/service.h | 1 + src/core/socket.c | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/service.c b/src/core/service.c index 3c4328c584..88f8cc5795 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -180,7 +180,7 @@ static int service_set_main_pid(Service *s, pid_t pid) { return 0; } -static void service_close_socket_fd(Service *s) { +void service_close_socket_fd(Service *s) { assert(s); s->socket_fd = asynchronous_close(s->socket_fd); diff --git a/src/core/service.h b/src/core/service.h index cd9e41646e..c7f1e81bdb 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -198,6 +198,7 @@ struct Service { extern const UnitVTable service_vtable; int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net); +void service_close_socket_fd(Service *s); const char* service_restart_to_string(ServiceRestart i) _const_; ServiceRestart service_restart_from_string(const char *s) _pure_; diff --git a/src/core/socket.c b/src/core/socket.c index 42260d8729..a897a11a29 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2010,8 +2010,12 @@ static void socket_enter_running(Socket *s, int cfd) { s->n_connections++; r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL); - if (r < 0) + if (r < 0) { + /* We failed to activate the new service, but it still exists. Let's make sure the service + * closes and forgets the connection fd again, immediately. */ + service_close_socket_fd(service); goto fail; + } /* Notify clients about changed counters */ unit_add_to_dbus_queue(UNIT(s)); -- cgit v1.2.3-54-g00ecf From 29857001854a02c292f1f3b324e7a66831e859c8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Apr 2016 21:00:28 +0200 Subject: core: make parsing of RLIMIT_NICE aware of actual nice levels --- man/systemd.exec.xml | 38 +++++++++++++++------------------ src/basic/rlimit-util.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- src/test/test-rlimit-util.c | 12 +++++++++++ 3 files changed, 80 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 2d0fb63f1d..2a93760428 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -629,27 +629,23 @@ LimitNICE= LimitRTPRIO= LimitRTTIME= - These settings set both soft and hard limits - of various resources for executed processes. See - setrlimit2 - for details. The resource limit is possible to specify in two formats, - to set soft and hard limits to the same value, - or to set both limits individually (e.g. LimitAS=4G:16G). - Use the string infinity to - configure no limit on a specific resource. The multiplicative - suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E - may be used for resource limits measured in bytes - (e.g. LimitAS=16G). For the limits referring to time values, - the usual time units ms, s, min, h and so on may be used (see - systemd.time7 - for details). Note that if no time unit is specified for - LimitCPU= the default unit of seconds is - implied, while for LimitRTTIME= the default - unit of microseconds is implied. Also, note that the effective - granularity of the limits might influence their - enforcement. For example, time limits specified for - LimitCPU= will be rounded up implicitly to - multiples of 1s. + Set soft and hard limits on various resources for executed processes. See + setrlimit2 for details on + the resource limit concept. Resource limits may be specified in two formats: either as single value to set a + specific soft and hard limit to the same value, or as colon-separated pair to set + both limits individually (e.g. LimitAS=4G:16G). Use the string infinity + to configure no limit on a specific resource. The multiplicative suffixes K, M, G, T, P and E (to the base + 1024) may be used for resource limits measured in bytes (e.g. LimitAS=16G). For the limits referring to time + values, the usual time units ms, s, min, h and so on may be used (see + systemd.time7 for + details). Note that if no time unit is specified for LimitCPU= the default unit of seconds + is implied, while for LimitRTTIME= the default unit of microseconds is implied. Also, note + that the effective granularity of the limits might influence their enforcement. For example, time limits + specified for LimitCPU= will be rounded up implicitly to multiples of 1s. For + LimitNICE= the value may be specified in two syntaxes: if prefixed with + + or -, the value is understood as regular Linux nice value in the range -20..19. If not + prefixed like this the value is understood as raw resource limit parameter in the range 0..40 (with 0 being + equivalent to 1). Note that most process resource limits configured with these options are per-process, and processes may fork in order diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 7540b43215..ee063720ed 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -153,6 +153,56 @@ static int rlimit_parse_usec(const char *val, rlim_t *ret) { return 0; } +static int rlimit_parse_nice(const char *val, rlim_t *ret) { + uint64_t rl; + int r; + + /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the + * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is + * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight + * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we + * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0. + * + * Yeah, Linux is quality engineering sometimes... */ + + if (val[0] == '+') { + + /* Prefixed with "+": Parse as positive user-friendly nice value */ + r = safe_atou64(val + 1, &rl); + if (r < 0) + return r; + + if (rl >= PRIO_MAX) + return -ERANGE; + + rl = 20 - rl; + + } else if (val[0] == '-') { + + /* Prefixed with "-": Parse as negative user-friendly nice value */ + r = safe_atou64(val + 1, &rl); + if (r < 0) + return r; + + if (rl > (uint64_t) (-PRIO_MIN)) + return -ERANGE; + + rl = 20 + rl; + } else { + + /* Not prefixed: parse as raw resource limit value */ + r = safe_atou64(val, &rl); + if (r < 0) + return r; + + if (rl > (uint64_t) (20 - PRIO_MIN)) + return -ERANGE; + } + + *ret = (rlim_t) rl; + return 0; +} + static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = { [RLIMIT_CPU] = rlimit_parse_sec, [RLIMIT_FSIZE] = rlimit_parse_size, @@ -167,7 +217,7 @@ static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret [RLIMIT_LOCKS] = rlimit_parse_u64, [RLIMIT_SIGPENDING] = rlimit_parse_u64, [RLIMIT_MSGQUEUE] = rlimit_parse_size, - [RLIMIT_NICE] = rlimit_parse_u64, + [RLIMIT_NICE] = rlimit_parse_nice, [RLIMIT_RTPRIO] = rlimit_parse_u64, [RLIMIT_RTTIME] = rlimit_parse_usec, }; diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c index d9ac9368cd..62afd2de5e 100644 --- a/src/test/test-rlimit-util.c +++ b/src/test/test-rlimit-util.c @@ -99,6 +99,18 @@ int main(int argc, char *argv[]) { test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL); test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL); test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL); + test_rlimit_parse_format(RLIMIT_NICE, "20", 20, 20, 0, "20"); + test_rlimit_parse_format(RLIMIT_NICE, "40", 40, 40, 0, "40"); + test_rlimit_parse_format(RLIMIT_NICE, "41", 41, 41, -ERANGE, "41"); + test_rlimit_parse_format(RLIMIT_NICE, "0", 0, 0, 0, "0"); + test_rlimit_parse_format(RLIMIT_NICE, "-7", 27, 27, 0, "27"); + test_rlimit_parse_format(RLIMIT_NICE, "-20", 40, 40, 0, "40"); + test_rlimit_parse_format(RLIMIT_NICE, "-21", 41, 41, -ERANGE, "41"); + test_rlimit_parse_format(RLIMIT_NICE, "-0", 20, 20, 0, "20"); + test_rlimit_parse_format(RLIMIT_NICE, "+7", 13, 13, 0, "13"); + test_rlimit_parse_format(RLIMIT_NICE, "+19", 1, 1, 0, "1"); + test_rlimit_parse_format(RLIMIT_NICE, "+20", 0, 0, -ERANGE, "0"); + test_rlimit_parse_format(RLIMIT_NICE, "+0", 20, 20, 0, "20"); return 0; } -- cgit v1.2.3-54-g00ecf From 18e854f8e5093f346dc814b8d33997f871b40f7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Apr 2016 21:47:20 +0200 Subject: socket: really always close auxiliary fds when closing socket fds --- src/core/socket.c | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index a897a11a29..377a331158 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -794,47 +794,45 @@ static void socket_close_fds(Socket *s) { assert(s); LIST_FOREACH(port, p, s->ports) { + bool was_open; - p->event_source = sd_event_source_unref(p->event_source); - - if (p->fd < 0) - continue; + was_open = p->fd >= 0; + p->event_source = sd_event_source_unref(p->event_source); p->fd = safe_close(p->fd); socket_cleanup_fd_list(p); - /* One little note: we should normally not delete any - * sockets in the file system here! After all some - * other process we spawned might still have a - * reference of this fd and wants to continue to use - * it. Therefore we delete sockets in the file system - * before we create a new one, not after we stopped - * using one! */ + /* One little note: we should normally not delete any sockets in the file system here! After all some + * other process we spawned might still have a reference of this fd and wants to continue to use + * it. Therefore we normally delete sockets in the file system before we create a new one, not after we + * stopped using one! That all said, if the user explicitly requested this, we'll delete them here + * anyway, but only then. */ - if (s->remove_on_stop) { - switch (p->type) { + if (!was_open || !s->remove_on_stop) + continue; - case SOCKET_FIFO: - unlink(p->path); - break; + switch (p->type) { - case SOCKET_MQUEUE: - mq_unlink(p->path); - break; + case SOCKET_FIFO: + (void) unlink(p->path); + break; - case SOCKET_SOCKET: - socket_address_unlink(&p->address); - break; + case SOCKET_MQUEUE: + (void) mq_unlink(p->path); + break; - default: - break; - } + case SOCKET_SOCKET: + (void) socket_address_unlink(&p->address); + break; + + default: + break; } } if (s->remove_on_stop) STRV_FOREACH(i, s->symlinks) - unlink(*i); + (void) unlink(*i); } static void socket_apply_socket_options(Socket *s, int fd) { -- cgit v1.2.3-54-g00ecf From e4f673174e54f1f187ec78f5ac908a62fbeb1236 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 11:14:03 +0200 Subject: core: rework socket/service GC logic There's no need to set the no_gc bit for service units that socket units prepare, as we always keep a proper reference (as maintained by unit_ref_set()) on them, and such references are honoured by the GC logic anyway. Moreover, explicitly setting the no_gc bit is problematic if the socket gets GC'ed for a reason, as the service might then leak with the bit set. --- src/core/socket.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index 377a331158..7eeed068bd 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -229,7 +229,6 @@ int socket_instantiate_service(Socket *s) { if (r < 0) return r; - u->no_gc = true; unit_ref_set(&s->service, u); return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false); @@ -1994,10 +1993,8 @@ static void socket_enter_running(Socket *s, int cfd) { service = SERVICE(UNIT_DEREF(s->service)); unit_ref_unset(&s->service); - s->n_accepted++; - - UNIT(service)->no_gc = false; + s->n_accepted++; unit_choose_id(UNIT(service), name); r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net); -- cgit v1.2.3-54-g00ecf From b75102e5bf4cf249052d42be955d403e3e03b47c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 11:18:53 +0200 Subject: core: rerun GC logic for a unit that loses a reference Let's make sure when we drop a reference to a unit, that we run the GC queue on it again. This (together with the previous commit) should deal with the GC issues pointed out in: https://github.com/systemd/systemd/pull/2993#issuecomment-215331189 --- src/core/unit.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index 6c0684225a..81cd7ee2b8 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3222,6 +3222,10 @@ void unit_ref_unset(UnitRef *ref) { if (!ref->unit) return; + /* We are about to drop a reference to the unit, make sure the garbage collection has a look at it as it might + * be unreferenced now. */ + unit_add_to_gc_queue(ref->unit); + LIST_REMOVE(refs, ref->unit->refs, ref); ref->unit = NULL; } -- cgit v1.2.3-54-g00ecf From 5cc3985ed1817078785fb3323f5c1d08a9c3e32f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 11:36:00 +0200 Subject: core: merge service_connection_unref() into service_close_socket_fd() We always call one after the other anyway, and this way service_set_socket_fd() and service_close_socket_fd() nicely match each other as one undoes the effect of the other. --- src/core/service.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/core/service.c b/src/core/service.c index 88f8cc5795..f7a3fcf2b9 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -183,17 +183,14 @@ static int service_set_main_pid(Service *s, pid_t pid) { void service_close_socket_fd(Service *s) { assert(s); - s->socket_fd = asynchronous_close(s->socket_fd); -} + /* Undo the effect of service_set_socket_fd(). */ -static void service_connection_unref(Service *s) { - assert(s); - - if (!UNIT_ISSET(s->accept_socket)) - return; + s->socket_fd = asynchronous_close(s->socket_fd); - socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket))); - unit_ref_unset(&s->accept_socket); + if (UNIT_ISSET(s->accept_socket)) { + socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket))); + unit_ref_unset(&s->accept_socket); + } } static void service_stop_watchdog(Service *s) { @@ -321,7 +318,6 @@ static void service_done(Unit *u) { s->bus_name_owner = mfree(s->bus_name_owner); service_close_socket_fd(s); - service_connection_unref(s); unit_ref_unset(&s->accept_socket); @@ -910,10 +906,8 @@ static void service_set_state(Service *s, ServiceState state) { SERVICE_RUNNING, SERVICE_RELOAD, 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)) { + !(state == SERVICE_DEAD && UNIT(s)->job)) service_close_socket_fd(s); - service_connection_unref(s); - } if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) service_stop_watchdog(s); -- cgit v1.2.3-54-g00ecf From 934e749e18bc0641a3dc8d83c4f16a2ba4c8d966 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 17:31:02 +0200 Subject: core: refuse merging on units when the unit type does not support alias The concept of merging units exists so that we can create Unit objects for a number of names early, and then load them only later, possibly merging units which then turn out to be symlinked to other names. This of course only makes sense for unit types where multiple names per unit are supported. For all others, let's refuse the merge operation early. --- src/core/unit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index cb79c7c6b1..4a129ffd5e 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -720,6 +720,9 @@ int unit_merge(Unit *u, Unit *other) { if (!u->instance != !other->instance) return -EINVAL; + if (UNIT_VTABLE(u)->no_alias) /* Merging only applies to unit names that support aliases */ + return -EEXIST; + if (other->load_state != UNIT_STUB && other->load_state != UNIT_NOT_FOUND) return -EEXIST; @@ -776,9 +779,9 @@ int unit_merge(Unit *u, Unit *other) { } int unit_merge_by_name(Unit *u, const char *name) { + _cleanup_free_ char *s = NULL; Unit *other; int r; - _cleanup_free_ char *s = NULL; assert(u); assert(name); -- cgit v1.2.3-54-g00ecf From 454f0f8680ebbded135e8575b4d9615b427fdf76 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 17:33:29 +0200 Subject: hashmap: optimize set_put_strdup() a bit Hashing should be quicker than allocating, hence let's first check if the string already exists and only then allocate a new copy for it. --- src/basic/hashmap.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 85b8d812b3..49a0479592 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -1773,20 +1773,18 @@ int set_consume(Set *s, void *value) { int set_put_strdup(Set *s, const char *p) { char *c; - int r; assert(s); assert(p); + if (set_contains(s, (char*) p)) + return 0; + c = strdup(p); if (!c) return -ENOMEM; - r = set_consume(s, c); - if (r == -EEXIST) - return 0; - - return r; + return set_consume(s, c); } int set_put_strdupv(Set *s, char **l) { -- cgit v1.2.3-54-g00ecf From a837f0880362c190254619ebbb8bad20603211f4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 17:37:33 +0200 Subject: core: when encountering a symlink alias for non-aliasable units warn nicely If the user defines a symlink alias for a unit whose type does not support aliasing, detect this early and print a nice warning. Fixe: #2730 --- src/core/load-fragment.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index c4566f7709..31b995aa6a 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3427,10 +3427,10 @@ int config_parse_protect_system( #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { + char *id = NULL; unsigned c = 0; int fd, r; FILE *f; - char *id = NULL; assert(filename); assert(*filename); @@ -3452,7 +3452,6 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { * the names of this unit, but only if it is a valid * unit name. */ name = basename(*filename); - if (unit_name_is_valid(name, UNIT_NAME_ANY)) { id = set_get(names, name); @@ -3492,6 +3491,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { *_f = f; *_final = id; + return 0; } @@ -3552,13 +3552,13 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { } static int load_from_path(Unit *u, const char *path) { - int r; _cleanup_set_free_free_ Set *symlink_names = NULL; _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *filename = NULL; char *id = NULL; Unit *merged; struct stat st; + int r; assert(u); assert(path); @@ -3597,18 +3597,14 @@ static int load_from_path(Unit *u, const char *path) { r = -ENOENT; else r = open_follow(&filename, &f, symlink_names, &id); + if (r >= 0) + break; + filename = mfree(filename); + if (r != -ENOENT) + return r; - if (r < 0) { - filename = mfree(filename); - if (r != -ENOENT) - return r; - - /* Empty the symlink names for the next run */ - set_clear_free(symlink_names); - continue; - } - - break; + /* Empty the symlink names for the next run */ + set_clear_free(symlink_names); } } @@ -3616,6 +3612,11 @@ static int load_from_path(Unit *u, const char *path) { /* Hmm, no suitable file found? */ return 0; + if (UNIT_VTABLE(u)->no_alias && set_size(symlink_names) > 1) { + log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id); + return -ELOOP; + } + merged = u; r = merge_by_names(&merged, symlink_names, id); if (r < 0) -- cgit v1.2.3-54-g00ecf From 634f0f983c57e41292dd36c7327e99316ff61aa3 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Apr 2016 22:52:04 -0400 Subject: networkd: rework headers to avoid circular includes Header files were organized in a way where the includer would add various typedefs used by the includee before including it, resulting in a tangled web of dependencies between files. Replace this with the following logic: networkd.h / \ networkd-link.h \ networkd-ipv4ll.h--\__\ networkd-fdb.h \ networkd-network.h netword-netdev-*.h networkd-route.h \ networkd-netdev.h If a pointer to a structure defined in a different header file is needed, use a typedef line instead of including the whole header. --- src/network/networkd-address-pool.h | 4 ++- src/network/networkd-address.h | 4 ++- src/network/networkd-dhcp4.c | 2 +- src/network/networkd-dhcp6.c | 2 +- src/network/networkd-fdb.h | 8 +++-- src/network/networkd-ipv4ll.c | 2 +- src/network/networkd-link.c | 3 +- src/network/networkd-link.h | 15 +++++---- src/network/networkd-lldp-tx.c | 5 ++- src/network/networkd-ndisc.c | 2 +- src/network/networkd-netdev-bond.c | 1 + src/network/networkd-netdev-bond.h | 8 ++--- src/network/networkd-netdev-bridge.c | 1 + src/network/networkd-netdev-bridge.h | 7 ++--- src/network/networkd-netdev-dummy.h | 7 ++--- src/network/networkd-netdev-gperf.gperf | 12 +++++-- src/network/networkd-netdev-ipvlan.h | 7 ++--- src/network/networkd-netdev-macvlan.h | 2 ++ src/network/networkd-netdev-tunnel.h | 17 +++++++--- src/network/networkd-netdev-tuntap.c | 7 +++-- src/network/networkd-netdev-tuntap.h | 2 ++ src/network/networkd-netdev-veth.h | 1 + src/network/networkd-netdev-vlan.h | 1 + src/network/networkd-netdev-vxlan.c | 2 ++ src/network/networkd-netdev-vxlan.h | 1 + src/network/networkd-netdev.h | 55 +++++++-------------------------- src/network/networkd-network.h | 11 ++++--- src/network/networkd-route.h | 1 - src/network/networkd.h | 23 +++++++++----- 29 files changed, 114 insertions(+), 99 deletions(-) (limited to 'src') diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h index 8e1378ff40..af30decfe0 100644 --- a/src/network/networkd-address-pool.h +++ b/src/network/networkd-address-pool.h @@ -22,7 +22,9 @@ typedef struct AddressPool AddressPool; #include "in-addr-util.h" -#include "networkd.h" +#include "list.h" + +typedef struct Manager Manager; struct AddressPool { Manager *manager; diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 338f6eb9a2..3b5285abf0 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -28,10 +28,12 @@ typedef struct Address Address; #include "networkd-link.h" #include "networkd-network.h" -#include "networkd.h" #define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU +typedef struct Network Network; +typedef struct Link Link; + struct Address { Network *network; unsigned section; diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index c5b61abc9e..d31ea4d066 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -24,7 +24,7 @@ #include "dhcp-lease-internal.h" #include "hostname-util.h" #include "network-internal.h" -#include "networkd-link.h" +#include "networkd.h" static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index d4b2fbfc57..b9c4b8962c 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -23,7 +23,7 @@ #include "sd-dhcp6-client.h" #include "network-internal.h" -#include "networkd-link.h" +#include "networkd.h" static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link); diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h index 89b3e29405..84410714f5 100644 --- a/src/network/networkd-fdb.h +++ b/src/network/networkd-fdb.h @@ -19,10 +19,12 @@ along with systemd; If not, see . ***/ -typedef struct FdbEntry FdbEntry; +#include "list.h" +#include "macro.h" -#include "networkd-network.h" -#include "networkd.h" +typedef struct Network Network; +typedef struct FdbEntry FdbEntry; +typedef struct Link Link; struct FdbEntry { Network *network; diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index e05fd3eea7..35c9b06473 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -21,7 +21,7 @@ #include #include "network-internal.h" -#include "networkd-link.h" +#include "networkd.h" static int ipv4ll_address_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5fc513bfda..a88e4c34ed 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -28,9 +28,8 @@ #include "fileio.h" #include "netlink-util.h" #include "network-internal.h" -#include "networkd-link.h" +#include "networkd.h" #include "networkd-lldp-tx.h" -#include "networkd-netdev.h" #include "set.h" #include "socket-util.h" #include "stdio-util.h" diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index f2a64ca9b5..86139be557 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -21,14 +21,17 @@ #include +#include "sd-bus.h" #include "sd-dhcp-client.h" #include "sd-dhcp-server.h" #include "sd-dhcp6-client.h" #include "sd-ipv4ll.h" #include "sd-lldp.h" #include "sd-ndisc.h" +#include "sd-netlink.h" -typedef struct Link Link; +#include "list.h" +#include "set.h" typedef enum LinkState { LINK_STATE_PENDING, @@ -54,11 +57,11 @@ typedef enum LinkOperationalState { _LINK_OPERSTATE_INVALID = -1 } LinkOperationalState; -#include "networkd-address.h" -#include "networkd-network.h" -#include "networkd.h" +typedef struct Manager Manager; +typedef struct Network Network; +typedef struct Address Address; -struct Link { +typedef struct Link { Manager *manager; int n_ref; @@ -122,7 +125,7 @@ struct Link { Hashmap *bound_by_links; Hashmap *bound_to_links; -}; +} Link; Link *link_unref(Link *link); Link *link_ref(Link *link); diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index 6bde04bc32..03b694c3f1 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -21,15 +21,18 @@ #include #include +#include "alloc-util.h" #include "fd-util.h" #include "fileio.h" #include "hostname-util.h" -#include "networkd-lldp-tx.h" #include "random-util.h" #include "socket-util.h" #include "string-util.h" #include "unaligned.h" +#include "networkd.h" +#include "networkd-lldp-tx.h" + #define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */ diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 4577292e44..b22c58bfe5 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -24,7 +24,7 @@ #include "sd-ndisc.h" -#include "networkd-link.h" +#include "networkd.h" static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index 6b9cbcded6..7913b0088e 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -25,6 +25,7 @@ #include "alloc-util.h" #include "conf-parser.h" +#include "extract-word.h" #include "missing.h" #include "networkd-netdev-bond.h" #include "string-table.h" diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h index cb6baea24f..b941edb344 100644 --- a/src/network/networkd-netdev-bond.h +++ b/src/network/networkd-netdev-bond.h @@ -20,8 +20,7 @@ ***/ #include "in-addr-util.h" - -typedef struct Bond Bond; +#include "list.h" #include "networkd-netdev.h" @@ -106,7 +105,7 @@ typedef struct ArpIpTarget { LIST_FIELDS(struct ArpIpTarget, arp_ip_target); } ArpIpTarget; -struct Bond { +typedef struct Bond { NetDev meta; BondMode mode; @@ -133,8 +132,9 @@ struct Bond { int n_arp_ip_targets; ArpIpTarget *arp_ip_targets; -}; +} Bond; +DEFINE_NETDEV_CAST(BOND, Bond); extern const NetDevVTable bond_vtable; const char *bond_mode_to_string(BondMode d) _const_; diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index 3f91b2eaea..3e44dd7960 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -22,6 +22,7 @@ #include "missing.h" #include "netlink-util.h" +#include "networkd.h" #include "networkd-netdev-bridge.h" /* callback for brige netdev's parameter set */ diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index 3f6f1d0502..b921439f02 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -19,11 +19,9 @@ along with systemd; If not, see . ***/ -typedef struct Bridge Bridge; - #include "networkd-netdev.h" -struct Bridge { +typedef struct Bridge { NetDev meta; int mcast_querier; @@ -31,6 +29,7 @@ struct Bridge { usec_t forward_delay; usec_t hello_time; usec_t max_age; -}; +} Bridge; +DEFINE_NETDEV_CAST(BRIDGE, Bridge); extern const NetDevVTable bridge_vtable; diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h index 42da62ebe4..efe302267e 100644 --- a/src/network/networkd-netdev-dummy.h +++ b/src/network/networkd-netdev-dummy.h @@ -19,12 +19,11 @@ along with systemd; If not, see . ***/ -typedef struct Dummy Dummy; - #include "networkd-netdev.h" -struct Dummy { +typedef struct Dummy { NetDev meta; -}; +} Dummy; +DEFINE_NETDEV_CAST(DUMMY, Dummy); extern const NetDevVTable dummy_vtable; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 15a787a9e3..1ebd0fdf20 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -1,11 +1,17 @@ %{ #include #include "conf-parser.h" -#include "networkd-netdev.h" -#include "networkd-netdev-tunnel.h" +#include "network-internal.h" #include "networkd-netdev-bond.h" +#include "networkd-netdev-ipvlan.h" #include "networkd-netdev-macvlan.h" -#include "network-internal.h" +#include "networkd-netdev-tunnel.h" +#include "networkd-netdev-tuntap.h" +#include "networkd-netdev-veth.h" +#include "networkd-netdev-vlan.h" +#include "networkd-netdev-vxlan.h" +#include "networkd-netdev-bridge.h" +#include "networkd-netdev.h" %} struct ConfigPerfItem; %null_strings diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h index 4bd0b67866..10d4079844 100644 --- a/src/network/networkd-netdev-ipvlan.h +++ b/src/network/networkd-netdev-ipvlan.h @@ -19,8 +19,6 @@ along with systemd; If not, see . ***/ -typedef struct IPVlan IPVlan; - #include "missing.h" #include "networkd-netdev.h" @@ -31,12 +29,13 @@ typedef enum IPVlanMode { _NETDEV_IPVLAN_MODE_INVALID = -1 } IPVlanMode; -struct IPVlan { +typedef struct IPVlan { NetDev meta; IPVlanMode mode; -}; +} IPVlan; +DEFINE_NETDEV_CAST(IPVLAN, IPVlan); extern const NetDevVTable ipvlan_vtable; const char *ipvlan_mode_to_string(IPVlanMode d) _const_; diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h index 622ef9ef53..3663f4f051 100644 --- a/src/network/networkd-netdev-macvlan.h +++ b/src/network/networkd-netdev-macvlan.h @@ -38,6 +38,8 @@ struct MacVlan { MacVlanMode mode; }; +DEFINE_NETDEV_CAST(MACVLAN, MacVlan); +DEFINE_NETDEV_CAST(MACVTAP, MacVlan); extern const NetDevVTable macvlan_vtable; extern const NetDevVTable macvtap_vtable; diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index 0d41f80a3c..7d31e7b687 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -19,7 +19,7 @@ along with systemd; If not, see . ***/ -typedef struct Tunnel Tunnel; +#include "in-addr-util.h" #include "networkd-netdev.h" @@ -37,7 +37,7 @@ typedef enum IPv6FlowLabel { _NETDEV_IPV6_FLOWLABEL_INVALID = -1, } IPv6FlowLabel; -struct Tunnel { +typedef struct Tunnel { NetDev meta; uint8_t encap_limit; @@ -56,8 +56,17 @@ struct Tunnel { bool pmtudisc; bool copy_dscp; -}; - +} Tunnel; + +DEFINE_NETDEV_CAST(IPIP, Tunnel); +DEFINE_NETDEV_CAST(GRE, Tunnel); +DEFINE_NETDEV_CAST(GRETAP, Tunnel); +DEFINE_NETDEV_CAST(IP6GRE, Tunnel); +DEFINE_NETDEV_CAST(IP6GRETAP, Tunnel); +DEFINE_NETDEV_CAST(SIT, Tunnel); +DEFINE_NETDEV_CAST(VTI, Tunnel); +DEFINE_NETDEV_CAST(VTI6, Tunnel); +DEFINE_NETDEV_CAST(IP6TNL, Tunnel); extern const NetDevVTable ipip_vtable; extern const NetDevVTable sit_vtable; extern const NetDevVTable vti_vtable; diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index 32917fe6d5..088a4d8d32 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -17,10 +17,13 @@ along with systemd; If not, see . ***/ -#include -#include +#include #include +#include #include +#include +#include +#include #include "alloc-util.h" #include "fd-util.h" diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h index cbb7ee05a6..120f00a353 100644 --- a/src/network/networkd-netdev-tuntap.h +++ b/src/network/networkd-netdev-tuntap.h @@ -34,5 +34,7 @@ struct TunTap { bool vnet_hdr; }; +DEFINE_NETDEV_CAST(TUN, TunTap); +DEFINE_NETDEV_CAST(TAP, TunTap); extern const NetDevVTable tun_vtable; extern const NetDevVTable tap_vtable; diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h index ae5785783c..e69bfbc8f0 100644 --- a/src/network/networkd-netdev-veth.h +++ b/src/network/networkd-netdev-veth.h @@ -30,4 +30,5 @@ struct Veth { struct ether_addr *mac_peer; }; +DEFINE_NETDEV_CAST(VETH, Veth); extern const NetDevVTable veth_vtable; diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h index 1de6a1cc36..73aacf4a0f 100644 --- a/src/network/networkd-netdev-vlan.h +++ b/src/network/networkd-netdev-vlan.h @@ -31,4 +31,5 @@ struct VLan { uint64_t id; }; +DEFINE_NETDEV_CAST(VLAN, VLan); extern const NetDevVTable vlan_vtable; diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index dabbd97c87..724f9861be 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -23,8 +23,10 @@ #include "conf-parser.h" #include "alloc-util.h" +#include "extract-word.h" #include "parse-util.h" #include "missing.h" + #include "networkd-link.h" #include "networkd-netdev-vxlan.h" diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index a4bb44635a..4614c66fd1 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -55,6 +55,7 @@ struct VxLan { struct ifla_vxlan_port_range port_range; }; +DEFINE_NETDEV_CAST(VXLAN, VxLan); extern const NetDevVTable vxlan_vtable; int config_parse_vxlan_group_address(const char *unit, diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 7ea825fcb4..20244c0309 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -19,15 +19,13 @@ along with systemd; If not, see . ***/ -#include "list.h" - -typedef struct NetDev NetDev; -typedef struct NetDevVTable NetDevVTable; +#include "sd-netlink.h" -#include "networkd-link.h" -#include "networkd.h" +#include "list.h" +#include "time-util.h" typedef struct netdev_join_callback netdev_join_callback; +typedef struct Link Link; struct netdev_join_callback { sd_netlink_message_handler_t callback; @@ -78,7 +76,10 @@ typedef enum NetDevCreateType { _NETDEV_CREATE_INVALID = -1, } NetDevCreateType; -struct NetDev { +typedef struct Manager Manager; +typedef struct Condition Condition; + +typedef struct NetDev { Manager *manager; int n_ref; @@ -99,20 +100,9 @@ struct NetDev { int ifindex; LIST_HEAD(netdev_join_callback, callbacks); -}; +} NetDev; -#include "networkd-netdev-bond.h" -#include "networkd-netdev-bridge.h" -#include "networkd-netdev-dummy.h" -#include "networkd-netdev-ipvlan.h" -#include "networkd-netdev-macvlan.h" -#include "networkd-netdev-tunnel.h" -#include "networkd-netdev-tuntap.h" -#include "networkd-netdev-veth.h" -#include "networkd-netdev-vlan.h" -#include "networkd-netdev-vxlan.h" - -struct NetDevVTable { +typedef struct NetDevVTable { /* How much memory does an object of this unit type need */ size_t object_size; @@ -144,14 +134,14 @@ struct NetDevVTable { /* verify that compulsory configuration options were specified */ int (*config_verify)(NetDev *netdev, const char *filename); -}; +} NetDevVTable; extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX]; #define NETDEV_VTABLE(n) netdev_vtable[(n)->kind] /* For casting a netdev into the various netdev kinds */ -#define DEFINE_CAST(UPPERCASE, MixedCase) \ +#define DEFINE_NETDEV_CAST(UPPERCASE, MixedCase) \ static inline MixedCase* UPPERCASE(NetDev *n) { \ if (_unlikely_(!n || n->kind != NETDEV_KIND_##UPPERCASE)) \ return NULL; \ @@ -162,27 +152,6 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX]; /* For casting the various netdev kinds into a netdev */ #define NETDEV(n) (&(n)->meta) -DEFINE_CAST(BRIDGE, Bridge); -DEFINE_CAST(BOND, Bond); -DEFINE_CAST(VLAN, VLan); -DEFINE_CAST(MACVLAN, MacVlan); -DEFINE_CAST(MACVTAP, MacVlan); -DEFINE_CAST(IPVLAN, IPVlan); -DEFINE_CAST(VXLAN, VxLan); -DEFINE_CAST(IPIP, Tunnel); -DEFINE_CAST(GRE, Tunnel); -DEFINE_CAST(GRETAP, Tunnel); -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); -DEFINE_CAST(TUN, TunTap); -DEFINE_CAST(TAP, TunTap); - int netdev_load(Manager *manager); void netdev_drop(NetDev *netdev); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 15417f4828..9b8096f9ae 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -19,18 +19,19 @@ along with systemd; If not, see . ***/ +#include "sd-bus.h" +#include "udev.h" + #include "condition.h" +#include "dhcp-identifier.h" +#include "hashmap.h" #include "resolve-util.h" -typedef struct Network Network; - -#include "dhcp-identifier.h" #include "networkd-address.h" #include "networkd-fdb.h" #include "networkd-netdev.h" #include "networkd-route.h" #include "networkd-util.h" -#include "networkd.h" #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 @@ -67,6 +68,8 @@ typedef enum LLDPMode { _LLDP_MODE_INVALID = -1, } LLDPMode; +typedef struct Manager Manager; + struct Network { Manager *manager; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index a4a4bf2653..59843162f0 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -22,7 +22,6 @@ typedef struct Route Route; #include "networkd-network.h" -#include "networkd.h" struct Route { Network *network; diff --git a/src/network/networkd.h b/src/network/networkd.h index 72a2438ac8..39826a440d 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -24,19 +24,30 @@ #include "sd-bus.h" #include "sd-event.h" #include "sd-netlink.h" +#include "udev.h" +#include "dhcp-identifier.h" #include "hashmap.h" #include "list.h" -#include "udev.h" -typedef struct Manager Manager; - -#include "dhcp-identifier.h" #include "networkd-address-pool.h" #include "networkd-link.h" +#include "networkd-netdev-bond.h" +#include "networkd-netdev-bridge.h" +#include "networkd-netdev-dummy.h" +#include "networkd-netdev-ipvlan.h" +#include "networkd-netdev-macvlan.h" +#include "networkd-netdev-tunnel.h" +#include "networkd-netdev-tuntap.h" +#include "networkd-netdev-veth.h" +#include "networkd-netdev-vlan.h" +#include "networkd-netdev-vlan.h" +#include "networkd-netdev-vxlan.h" #include "networkd-network.h" #include "networkd-util.h" +extern const char* const network_dirs[]; + struct Manager { sd_netlink *rtnl; sd_event *event; @@ -71,10 +82,6 @@ struct Manager { uint8_t dhcp_duid[MAX_DUID_LEN]; }; -extern const char* const network_dirs[]; - -/* Manager */ - extern const sd_bus_vtable manager_vtable[]; int manager_new(Manager **ret); -- cgit v1.2.3-54-g00ecf From 3fdf9ad7ad7610456fb3ffd8c98a359714df8e3e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 30 Apr 2016 16:12:54 -0400 Subject: core: bus_append_unit_property_assignment() was using the wrong parse function It was incorrectly using cg_cpu_weight_parse() to parse BlockIOWeight. Update it to use cg_blkio_weight_parse() instead. Signed-off-by: Tejun Heo --- src/shared/bus-unit-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 2b755cea28..e36a7741a8 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -210,7 +210,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) { uint64_t u; - r = cg_cpu_shares_parse(eq, &u); + r = cg_blkio_weight_parse(eq, &u); if (r < 0) { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; -- cgit v1.2.3-54-g00ecf From ccf78df1fcaad6b215b17981c42eaef380f69c9c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 30 Apr 2016 16:12:54 -0400 Subject: core: make unit_has_mask_realized() consider controller enable state unit_has_mask_realized() determines whether the specified unit has its cgroups set up properly given the desired target_mask; however, on the unified hierarchy, controllers need to be enabled explicitly for children and the mask of enabled controllers can deviate from target_mask. Only considering target_mask in unit_has_mask_realized() can lead to false positives and skipping enabling the requested controllers. This patch adds unit->cgroup_enabled_mask to track which controllers are enabled and updates unit_has_mask_realized() to also consider enable_mask. Signed-off-by: Tejun Heo --- src/core/cgroup.c | 13 ++++++++----- src/core/unit.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 25cc6962f9..d90b73b456 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -857,6 +857,7 @@ static int unit_create_cgroup( /* Keep track that this is now realized */ u->cgroup_realized = true; u->cgroup_realized_mask = target_mask; + u->cgroup_enabled_mask = enable_mask; if (u->type != UNIT_SLICE && !c->delegate) { @@ -886,10 +887,10 @@ int unit_attach_pids_to_cgroup(Unit *u) { return 0; } -static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) { +static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) { assert(u); - return u->cgroup_realized && u->cgroup_realized_mask == target_mask; + return u->cgroup_realized && u->cgroup_realized_mask == target_mask && u->cgroup_enabled_mask == enable_mask; } /* Check if necessary controllers and attributes for a unit are in place. @@ -910,7 +911,9 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) { } target_mask = unit_get_target_mask(u); - if (unit_has_mask_realized(u, target_mask)) + enable_mask = unit_get_enable_mask(u); + + if (unit_has_mask_realized(u, target_mask, enable_mask)) return 0; /* First, realize parents */ @@ -921,7 +924,6 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) { } /* And then do the real work */ - enable_mask = unit_get_enable_mask(u); r = unit_create_cgroup(u, target_mask, enable_mask); if (r < 0) return r; @@ -990,7 +992,7 @@ static void unit_queue_siblings(Unit *u) { /* If the unit doesn't need any new controllers * and has current ones realized, it doesn't need * any changes. */ - if (unit_has_mask_realized(m, unit_get_target_mask(m))) + if (unit_has_mask_realized(m, unit_get_target_mask(m), unit_get_enable_mask(m))) continue; unit_add_to_cgroup_queue(m); @@ -1069,6 +1071,7 @@ void unit_prune_cgroup(Unit *u) { u->cgroup_realized = false; u->cgroup_realized_mask = 0; + u->cgroup_enabled_mask = 0; } int unit_search_main_pid(Unit *u, pid_t *ret) { diff --git a/src/core/unit.h b/src/core/unit.h index 5909652976..78f950c051 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -186,6 +186,7 @@ struct Unit { /* Counterparts in the cgroup filesystem */ char *cgroup_path; CGroupMask cgroup_realized_mask; + CGroupMask cgroup_enabled_mask; CGroupMask cgroup_subtree_mask; CGroupMask cgroup_members_mask; int cgroup_inotify_wd; -- cgit v1.2.3-54-g00ecf From b79660e6acb964f94ddba0ea4e1182215934dfc3 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Apr 2016 17:07:34 -0400 Subject: architecture: Add nios2 (#3159) Add nios2 architecture support. The nios2 is a softcore by Altera. --- src/basic/architecture.c | 3 +++ src/basic/architecture.h | 4 ++++ 2 files changed, 7 insertions(+) (limited to 'src') diff --git a/src/basic/architecture.c b/src/basic/architecture.c index a9ecfc1cd6..8e2c2b02d2 100644 --- a/src/basic/architecture.c +++ b/src/basic/architecture.c @@ -121,6 +121,8 @@ int uname_architecture(void) { { "tilegx", ARCHITECTURE_TILEGX }, #elif defined(__cris__) { "crisv32", ARCHITECTURE_CRIS }, +#elif defined(__nios2__) + { "nios2", ARCHITECTURE_NIOS2 }, #else #error "Please register your architecture here!" #endif @@ -171,6 +173,7 @@ static const char *const architecture_table[_ARCHITECTURE_MAX] = { [ARCHITECTURE_M68K] = "m68k", [ARCHITECTURE_TILEGX] = "tilegx", [ARCHITECTURE_CRIS] = "cris", + [ARCHITECTURE_NIOS2] = "nios2", }; DEFINE_STRING_TABLE_LOOKUP(architecture, int); diff --git a/src/basic/architecture.h b/src/basic/architecture.h index c22cbc8279..91ec108e04 100644 --- a/src/basic/architecture.h +++ b/src/basic/architecture.h @@ -57,6 +57,7 @@ enum { ARCHITECTURE_M68K, ARCHITECTURE_TILEGX, ARCHITECTURE_CRIS, + ARCHITECTURE_NIOS2, _ARCHITECTURE_MAX, _ARCHITECTURE_INVALID = -1 }; @@ -187,6 +188,9 @@ int uname_architecture(void); #elif defined(__cris__) # define native_architecture() ARCHITECTURE_CRIS # error "Missing LIB_ARCH_TUPLE for CRIS" +#elif defined(__nios2__) +# define native_architecture() ARCHITECTURE_NIOS2 +# define LIB_ARCH_TUPLE "nios2-linux-gnu" #else # error "Please register your architecture here!" #endif -- cgit v1.2.3-54-g00ecf From 622d37058487ce955337ca9d843d92a67cd6a609 Mon Sep 17 00:00:00 2001 From: Alex Crawford Date: Sun, 1 May 2016 09:32:17 -0700 Subject: test: ensure presets are evaluated in order This tests to make sure that preset patterns are checked in the order they were declared. Both "prefix-1.service" and "prefix-2.service" match against two rules: their exact name (which enables the service) and "prefix-*.service" (which disables the service). Because of the ordering, only "prefix-1.service" should be enabled. --- src/test/test-install-root.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'src') diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 2d73c9743b..2aee33da60 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -681,6 +681,53 @@ static void test_revert(const char *root) { changes = NULL; n_changes = 0; } +static void test_preset_order(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + const char *p; + UnitFileState state; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/prefix-1.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/prefix-2.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); + assert_se(write_string_file(p, + "enable prefix-1.service\n" + "disable prefix-*.service\n" + "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/prefix-1.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +} + int main(int argc, char *argv[]) { char root[] = "/tmp/rootXXXXXX"; const char *p; @@ -709,6 +756,7 @@ int main(int argc, char *argv[]) { test_template_enable(root); test_indirect(root); test_preset_and_list(root); + test_preset_order(root); test_revert(root); assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); -- cgit v1.2.3-54-g00ecf From 8a993b61d1cd46a9c48d36fb67818883d80d9bc2 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Apr 2016 16:21:41 -0400 Subject: Move no_alias information to shared/ This way it can be used in install.c in subsequent commit. --- src/core/automount.c | 1 - src/core/busname.c | 1 - src/core/load-fragment.c | 2 +- src/core/mount.c | 1 - src/core/scope.c | 1 - src/core/slice.c | 1 - src/core/swap.c | 1 - src/core/unit.c | 4 ++-- src/core/unit.h | 3 --- src/shared/install.c | 10 ++++++++++ src/shared/install.h | 2 ++ 11 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index 7c55d7bc49..7374d50ae8 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -1050,7 +1050,6 @@ const UnitVTable automount_vtable = { "Automount\0" "Install\0", - .no_alias = true, .no_instances = true, .init = automount_init, diff --git a/src/core/busname.c b/src/core/busname.c index f4f433340c..4d43bd21e6 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -1028,7 +1028,6 @@ const UnitVTable busname_vtable = { "Install\0", .private_section = "BusName", - .no_alias = true, .no_instances = true, .init = busname_init, diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 31b995aa6a..1a8c03904c 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3612,7 +3612,7 @@ static int load_from_path(Unit *u, const char *path) { /* Hmm, no suitable file found? */ return 0; - if (UNIT_VTABLE(u)->no_alias && set_size(symlink_names) > 1) { + if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) { log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id); return -ELOOP; } diff --git a/src/core/mount.c b/src/core/mount.c index cc07873b24..adc74c3bea 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1839,7 +1839,6 @@ const UnitVTable mount_vtable = { "Install\0", .private_section = "Mount", - .no_alias = true, .no_instances = true, .init = mount_init, diff --git a/src/core/scope.c b/src/core/scope.c index 7078d1f7e9..3915e5c88c 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -569,7 +569,6 @@ const UnitVTable scope_vtable = { "Install\0", .private_section = "Scope", - .no_alias = true, .no_instances = true, .can_transient = true, diff --git a/src/core/slice.c b/src/core/slice.c index 63a77c9bca..96c7c74598 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -309,7 +309,6 @@ const UnitVTable slice_vtable = { "Install\0", .private_section = "Slice", - .no_alias = true, .no_instances = true, .can_transient = true, diff --git a/src/core/swap.c b/src/core/swap.c index d8802470d2..f486a44cf5 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1465,7 +1465,6 @@ const UnitVTable swap_vtable = { "Install\0", .private_section = "Swap", - .no_alias = true, .no_instances = true, .init = swap_init, diff --git a/src/core/unit.c b/src/core/unit.c index 4a129ffd5e..0313ee2ad3 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -202,7 +202,7 @@ int unit_add_name(Unit *u, const char *text) { if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i) return -EINVAL; - if (unit_vtable[t]->no_alias && !set_isempty(u->names)) + if (!unit_type_may_alias(t) && !set_isempty(u->names)) return -EEXIST; if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES) @@ -720,7 +720,7 @@ int unit_merge(Unit *u, Unit *other) { if (!u->instance != !other->instance) return -EINVAL; - if (UNIT_VTABLE(u)->no_alias) /* Merging only applies to unit names that support aliases */ + if (!unit_type_may_alias(u->type)) /* Merging only applies to unit names that support aliases */ return -EEXIST; if (other->load_state != UNIT_STUB && diff --git a/src/core/unit.h b/src/core/unit.h index 5909652976..6ac925a185 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -416,9 +416,6 @@ struct UnitVTable { /* The strings to print in status messages */ UnitStatusMessageFormats status_message_formats; - /* Can units of this type have multiple names? */ - bool no_alias:1; - /* Instances make no sense for this type */ bool no_instances:1; diff --git a/src/shared/install.c b/src/shared/install.c index 931d3e2907..b92afbc971 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -68,6 +68,16 @@ typedef struct { static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); +bool unit_type_may_alias(UnitType type) { + return IN_SET(type, + UNIT_SERVICE, + UNIT_SOCKET, + UNIT_TARGET, + UNIT_DEVICE, + UNIT_TIMER, + UNIT_PATH); +} + static int in_search_path(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; char **i; diff --git a/src/shared/install.h b/src/shared/install.h index 4ffc5a21f2..8a8bd09c7c 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -138,6 +138,8 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) { return !strv_isempty(i->also); } +bool unit_type_may_alias(UnitType type) _const_; + int unit_file_enable( UnitFileScope scope, bool runtime, -- cgit v1.2.3-54-g00ecf From a77245890103cae2d3ad69d3e6506cea4f7f9065 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Apr 2016 16:54:37 -0400 Subject: shared/install: ignore Alias in [Install] of units which don't allow aliases A downside is that a warning about missing [Install] is printed: $ systemctl --root=/ enable mnt-test.mount [/etc/systemd/system/mnt-test.mount:5] Aliases are not allowed for mount units, ignoring. The unit files have no installation config (WantedBy, RequiredBy, Also, Alias settings in the [Install] section, and DefaultInstance for template units). This means they are not meant to be enabled using systemctl. Possible reasons for having this kind of units are: 1) A unit may be statically enabled by being symlinked from another unit's .wants/ or .requires/ directory. 2) A unit's purpose may be to act as a helper for some other unit which has a requirement dependency on it. 3) A unit may be started when needed via activation (socket, path, timer, D-Bus, udev, scripted systemctl call, ...). 4) In case of template units, the unit is meant to be enabled with some instance name specified. That's a bit misleading, but I don't see an easy way to fix this. But the situation is similar for many other parsing errors, so maybe that's OK. --- src/shared/install.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index b92afbc971..1635f50fdb 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -908,6 +908,36 @@ fail: return r; } +static int config_parse_alias( + 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 *name; + UnitType type; + + assert(filename); + assert(lvalue); + assert(rvalue); + + name = basename(filename); + type = unit_name_to_type(name); + if (!unit_type_may_alias(type)) + return log_syntax(unit, LOG_WARNING, filename, line, 0, + "Aliases are not allowed for %s units, ignoring.", + unit_type_to_string(type)); + + return config_parse_strv(unit, filename, line, section, section_line, + lvalue, ltype, rvalue, data, userdata); +} + static int config_parse_also( const char *unit, const char *filename, @@ -993,7 +1023,7 @@ static int unit_file_load( SearchFlags flags) { const ConfigTableItem items[] = { - { "Install", "Alias", config_parse_strv, 0, &info->aliases }, + { "Install", "Alias", config_parse_alias, 0, &info->aliases }, { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by }, { "Install", "DefaultInstance", config_parse_default_instance, 0, info }, -- cgit v1.2.3-54-g00ecf From ce99c68a3362a2905743a0673a4c016f2b8ab1a6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Apr 2016 18:34:13 -0400 Subject: Move no_instances information to shared/ This way it can be used in install.c in subsequent commit. --- src/core/automount.c | 2 -- src/core/busname.c | 2 -- src/core/device.c | 2 -- src/core/mount.c | 2 -- src/core/scope.c | 1 - src/core/slice.c | 1 - src/core/swap.c | 2 -- src/core/unit.c | 2 +- src/core/unit.h | 3 --- src/shared/install.c | 9 +++++++++ src/shared/install.h | 1 + 11 files changed, 11 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index 7374d50ae8..1239a0efc6 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -1050,8 +1050,6 @@ const UnitVTable automount_vtable = { "Automount\0" "Install\0", - .no_instances = true, - .init = automount_init, .load = automount_load, .done = automount_done, diff --git a/src/core/busname.c b/src/core/busname.c index 4d43bd21e6..e7b7b5c012 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -1028,8 +1028,6 @@ const UnitVTable busname_vtable = { "Install\0", .private_section = "BusName", - .no_instances = true, - .init = busname_init, .done = busname_done, .load = busname_load, diff --git a/src/core/device.c b/src/core/device.c index d01bec53d8..16e56efcc3 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -841,8 +841,6 @@ const UnitVTable device_vtable = { "Device\0" "Install\0", - .no_instances = true, - .init = device_init, .done = device_done, .load = unit_load_fragment_and_dropin_optional, diff --git a/src/core/mount.c b/src/core/mount.c index adc74c3bea..c8a898e4dc 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1839,8 +1839,6 @@ const UnitVTable mount_vtable = { "Install\0", .private_section = "Mount", - .no_instances = true, - .init = mount_init, .load = mount_load, .done = mount_done, diff --git a/src/core/scope.c b/src/core/scope.c index 3915e5c88c..238f63a729 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -569,7 +569,6 @@ const UnitVTable scope_vtable = { "Install\0", .private_section = "Scope", - .no_instances = true, .can_transient = true, .init = scope_init, diff --git a/src/core/slice.c b/src/core/slice.c index 96c7c74598..c7700b8857 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -309,7 +309,6 @@ const UnitVTable slice_vtable = { "Install\0", .private_section = "Slice", - .no_instances = true, .can_transient = true, .init = slice_init, diff --git a/src/core/swap.c b/src/core/swap.c index f486a44cf5..c018648d87 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1465,8 +1465,6 @@ const UnitVTable swap_vtable = { "Install\0", .private_section = "Swap", - .no_instances = true, - .init = swap_init, .load = swap_load, .done = swap_done, diff --git a/src/core/unit.c b/src/core/unit.c index 0313ee2ad3..a2726f10a6 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -193,7 +193,7 @@ int unit_add_name(Unit *u, const char *text) { if (r < 0) return r; - if (i && unit_vtable[t]->no_instances) + if (i && !unit_type_may_template(t)) return -EINVAL; /* Ensure that this unit is either instanced or not instanced, diff --git a/src/core/unit.h b/src/core/unit.h index 6ac925a185..be62e88421 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -416,9 +416,6 @@ struct UnitVTable { /* The strings to print in status messages */ UnitStatusMessageFormats status_message_formats; - /* Instances make no sense for this type */ - bool no_instances:1; - /* True if transient units of this type are OK */ bool can_transient:1; }; diff --git a/src/shared/install.c b/src/shared/install.c index 1635f50fdb..cc39aaf677 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -78,6 +78,15 @@ bool unit_type_may_alias(UnitType type) { UNIT_PATH); } +bool unit_type_may_template(UnitType type) { + return IN_SET(type, + UNIT_SERVICE, + UNIT_SOCKET, + UNIT_TARGET, + UNIT_TIMER, + UNIT_PATH); +} + static int in_search_path(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; char **i; diff --git a/src/shared/install.h b/src/shared/install.h index 8a8bd09c7c..5812447c5b 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -139,6 +139,7 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) { } bool unit_type_may_alias(UnitType type) _const_; +bool unit_type_may_template(UnitType type) _const_; int unit_file_enable( UnitFileScope scope, -- cgit v1.2.3-54-g00ecf From 6597fa61173a16d9d93141a749badad67c4b4aa8 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Apr 2016 17:08:38 -0400 Subject: shared/install: warn about DefaultInstance in non-template units [/etc/systemd/system/mnt-test.mount:6] DefaultInstance only makes sense for template units, ignoring. --- src/shared/install.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index cc39aaf677..f89e2c6387 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1003,6 +1003,7 @@ static int config_parse_default_instance( void *userdata) { UnitFileInstallInfo *i = data; + const char *name; char *printed; int r; @@ -1010,6 +1011,15 @@ static int config_parse_default_instance( assert(lvalue); assert(rvalue); + name = basename(filename); + if (unit_name_is_valid(name, UNIT_NAME_INSTANCE)) + /* When enabling an instance, we might be using a template unit file, + * but we should ignore DefaultInstance silently. */ + return 0; + if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) + return log_syntax(unit, LOG_WARNING, filename, line, 0, + "DefaultInstance only makes sense for template units, ignoring."); + r = install_full_printf(i, rvalue, &printed); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 133e5b362f862ac9c9b1dd7b5de0b004cbb9af54 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 30 Apr 2016 17:52:19 -0400 Subject: shared/install: refuse template files for non-templateable units $ systemctl --root=/ enable templated@bar.mount Unit type mount cannot be templated. Failed to enable: Invalid argument. --- src/shared/install.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index f89e2c6387..f02d81504f 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1050,6 +1050,8 @@ static int unit_file_load( {} }; + const char *name; + UnitType type; _cleanup_fclose_ FILE *f = NULL; _cleanup_close_ int fd = -1; struct stat st; @@ -1059,6 +1061,12 @@ static int unit_file_load( assert(info); assert(path); + name = basename(path); + type = unit_name_to_type(name); + if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && + !unit_type_may_template(type)) + return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type)); + if (!(flags & SEARCH_LOAD)) { r = lstat(path, &st); if (r < 0) -- cgit v1.2.3-54-g00ecf From 5659958529d16f082a24d0c5b68699570b3eace3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 19:14:52 +0200 Subject: machined: run clone operation asynchronously in the background Cloning an image can be slow, if the image is not on a btrfs subvolume, hence let's make sure we do this asynchronously in a child process, so that machined isn't blocked as long as we process the client request. This adds a new, generic "Operation" object to machined, that is used to track these kind of background processes. This is inspired by the MachineOperation object that already exists to make copy operations asynchronous. A later patch will rework the MachineOperation logic to use the generic Operation instead. --- Makefile.am | 4 +- src/machine/image-dbus.c | 40 ++++++++++++++-- src/machine/machined.c | 8 ++++ src/machine/machined.h | 4 ++ src/machine/operation.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++ src/machine/operation.h | 45 ++++++++++++++++++ 6 files changed, 213 insertions(+), 6 deletions(-) create mode 100644 src/machine/operation.c create mode 100644 src/machine/operation.h (limited to 'src') diff --git a/Makefile.am b/Makefile.am index b323de55c6..8ff9eeb5a5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4942,7 +4942,9 @@ libmachine_core_la_SOURCES = \ src/machine/machine-dbus.c \ src/machine/machine-dbus.h \ src/machine/image-dbus.c \ - src/machine/image-dbus.h + src/machine/image-dbus.h \ + src/machine/operation.c \ + src/machine/operation.h libmachine_core_la_LIBADD = \ libshared.la diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index b764bc43a0..ca38f61dd3 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -20,9 +20,11 @@ #include "alloc-util.h" #include "bus-label.h" #include "bus-util.h" +#include "fd-util.h" #include "image-dbus.h" #include "io-util.h" #include "machine-image.h" +#include "process-util.h" #include "strv.h" #include "user-util.h" @@ -107,13 +109,19 @@ int bus_image_method_clone( void *userdata, sd_bus_error *error) { + _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; Image *image = userdata; Manager *m = image->userdata; const char *new_name; int r, read_only; + pid_t child; assert(message); assert(image); + assert(m); + + if (m->n_operations >= OPERATIONS_MAX) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations."); r = sd_bus_message_read(message, "sb", &new_name, &read_only); if (r < 0) @@ -136,13 +144,35 @@ int bus_image_method_clone( if (r == 0) return 1; /* Will call us back */ - r = image_clone(image, new_name, read_only); - if (r == -EOPNOTSUPP) - return sd_bus_reply_method_errnof(message, r, "Image cloning is currently only supported on btrfs file systems."); - if (r < 0) + 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) { + errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); + + r = image_clone(image, new_name, read_only); + if (r < 0) { + (void) write(errno_pipe_fd[1], &r, sizeof(r)); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); + } + + errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); + + r = operation_new(m, child, message, errno_pipe_fd[0]); + if (r < 0) { + (void) sigkill_wait(&child); return r; + } - return sd_bus_reply_method_return(message, NULL); + errno_pipe_fd[0] = -1; + + return 1; } int bus_image_method_mark_read_only( diff --git a/src/machine/machined.c b/src/machine/machined.c index f2c1966a6b..f7ceb5e603 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -70,6 +70,11 @@ void manager_free(Manager *m) { assert(m); + while (m->operations) + operation_free(m->operations); + + assert(m->n_operations == 0); + while ((machine = hashmap_first(m->machines))) machine_free(machine); @@ -336,6 +341,9 @@ int manager_startup(Manager *m) { static bool check_idle(void *userdata) { Manager *m = userdata; + if (m->operations) + return false; + manager_gc(m, true); return hashmap_isempty(m->machines); diff --git a/src/machine/machined.h b/src/machine/machined.h index e7d7dfdceb..7b9b148044 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -32,6 +32,7 @@ typedef struct Manager Manager; #include "image-dbus.h" #include "machine-dbus.h" #include "machine.h" +#include "operation.h" struct Manager { sd_event *event; @@ -49,6 +50,9 @@ struct Manager { LIST_HEAD(Machine, machine_gc_queue); Machine *host_machine; + + LIST_HEAD(Operation, operations); + unsigned n_operations; }; Manager *manager_new(void); diff --git a/src/machine/operation.c b/src/machine/operation.c new file mode 100644 index 0000000000..53e996b48f --- /dev/null +++ b/src/machine/operation.c @@ -0,0 +1,118 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "alloc-util.h" +#include "fd-util.h" +#include "operation.h" +#include "process-util.h" + +static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + Operation *o = userdata; + int r; + + assert(o); + assert(si); + + log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i", + o->pid, + sigchld_code_to_string(si->si_code), si->si_status); + + o->pid = 0; + + if (si->si_code != CLD_EXITED) { + r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child 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, "Child 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"); + + operation_free(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"); + + operation_free(o); + return 0; +} + +int operation_new(Manager *m, pid_t child, sd_bus_message *message, int errno_fd) { + Operation *o; + int r; + + o = new0(Operation, 1); + if (!o) + return -ENOMEM; + + r = sd_event_add_child(m->event, &o->event_source, child, WEXITED, operation_done, o); + if (r < 0) { + free(o); + return r; + } + + o->pid = child; + o->message = sd_bus_message_ref(message); + o->errno_fd = errno_fd; + + LIST_PREPEND(operations, m->operations, o); + m->n_operations++; + o->manager = m; + + log_debug("Started new operation " PID_FMT ".", child); + + /* At this point we took ownership of both the child and the errno file descriptor! */ + + return 0; +} + +Operation *operation_free(Operation *o) { + if (!o) + return NULL; + + sd_event_source_unref(o->event_source); + + safe_close(o->errno_fd); + + if (o->pid > 1) + (void) sigkill_wait(&o->pid); + + sd_bus_message_unref(o->message); + + if (o->manager) { + LIST_REMOVE(operations, o->manager->operations, o); + o->manager->n_operations--; + } + + free(o); + return NULL; +} diff --git a/src/machine/operation.h b/src/machine/operation.h new file mode 100644 index 0000000000..9d4c3afe45 --- /dev/null +++ b/src/machine/operation.h @@ -0,0 +1,45 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +#include "sd-bus.h" +#include "sd-event.h" + +#include "list.h" + +typedef struct Operation Operation; + +#include "machined.h" + +#define OPERATIONS_MAX 64 + +struct Operation { + Manager *manager; + pid_t pid; + sd_bus_message *message; + int errno_fd; + sd_event_source *event_source; + LIST_FIELDS(Operation, operations); +}; + +int operation_new(Manager *m, pid_t child, sd_bus_message *message, int errno_fd); +Operation *operation_free(Operation *o); -- cgit v1.2.3-54-g00ecf From 89c9030d319e118fa324fa5a1302ba53180b05b6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 19:23:23 +0200 Subject: util: rework sigkill_wait() to not require pid_t pointer Let's make sigkill_wait() take a normal pid_t, and add sigkill_waitp() that takes a pointer (which is useful for usage in _cleanup_), following the usual logic we have for this. --- src/basic/process-util.c | 12 +++++++++--- src/basic/process-util.h | 4 ++-- src/import/pull-common.c | 2 +- src/machine/image-dbus.c | 2 +- src/machine/operation.c | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index f2cea01979..4a7367cc92 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -528,14 +528,20 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod return -EPROTO; } -void sigkill_wait(pid_t *pid) { +void sigkill_wait(pid_t pid) { + assert(pid > 1); + + if (kill(pid, SIGKILL) > 0) + (void) wait_for_terminate(pid, NULL); +} + +void sigkill_waitp(pid_t *pid) { if (!pid) return; if (*pid <= 1) return; - if (kill(*pid, SIGKILL) > 0) - (void) wait_for_terminate(*pid, NULL); + sigkill_wait(*pid); } int kill_and_sigcont(pid_t pid, int sig) { diff --git a/src/basic/process-util.h b/src/basic/process-util.h index ffd4bcb0ff..9f75088796 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -58,8 +58,8 @@ int get_process_ppid(pid_t pid, pid_t *ppid); 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); -void sigkill_wait(pid_t *pid); -#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait) +void sigkill_wait(pid_t pid); +void sigkill_waitp(pid_t *pid); int kill_and_sigcont(pid_t pid, int sig); diff --git a/src/import/pull-common.c b/src/import/pull-common.c index d301d4d79e..dc4e4667a9 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -330,7 +330,7 @@ int pull_verify(PullJob *main_job, _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; + _cleanup_(sigkill_waitp) pid_t pid = 0; bool gpg_home_created = false; int r; diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index ca38f61dd3..db0ed03b69 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -166,7 +166,7 @@ int bus_image_method_clone( r = operation_new(m, child, message, errno_pipe_fd[0]); if (r < 0) { - (void) sigkill_wait(&child); + (void) sigkill_wait(child); return r; } diff --git a/src/machine/operation.c b/src/machine/operation.c index 53e996b48f..e8564c29f7 100644 --- a/src/machine/operation.c +++ b/src/machine/operation.c @@ -104,7 +104,7 @@ Operation *operation_free(Operation *o) { safe_close(o->errno_fd); if (o->pid > 1) - (void) sigkill_wait(&o->pid); + (void) sigkill_wait(o->pid); sd_bus_message_unref(o->message); -- cgit v1.2.3-54-g00ecf From 8120ee28b8d5d316d9ded9240bcccc9edb41ee06 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 19:26:54 +0200 Subject: image: enable btrfs quotas on the clone destination, not the source --- src/shared/machine-image.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index bebfc40efe..042ccc071c 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -607,9 +607,9 @@ int image_clone(Image *i, const char *new_name, bool read_only) { r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); - /* Enable "subtree" quotas for the copy, if we didn't - * copy any quota from the source. */ - (void) btrfs_subvol_auto_qgroup(i->path, 0, true); + /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */ + if (r >= 0) + (void) btrfs_subvol_auto_qgroup(new_path, 0, true); break; -- cgit v1.2.3-54-g00ecf From b498c53d80faf7ebd0df5888a48793889ee421e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 19:42:07 +0200 Subject: copy: return the right error when we can't open a file --- src/basic/copy.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index 3001234a01..c2baef6d22 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -305,6 +305,8 @@ static int fd_copy_directory( fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); else fdf = fcntl(df, F_DUPFD_CLOEXEC, 3); + if (fdf < 0) + return -errno; d = fdopendir(fdf); if (!d) -- cgit v1.2.3-54-g00ecf From 3b8483c0a3c7e2ba32c2f9b8ba36082bee3e0536 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 19:44:59 +0200 Subject: copy: adjust directory times after writing to the directory When recursively copying a directory tree, fix up the file times after having created all contents in it, so that our changes don't end up altering any of the directory times. --- src/basic/copy.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index c2baef6d22..79b9a0e1a0 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -327,22 +327,6 @@ static int fd_copy_directory( r = 0; - if (created) { - struct timespec ut[2] = { - st->st_atim, - st->st_mtim - }; - - if (fchown(fdt, st->st_uid, st->st_gid) < 0) - r = -errno; - - if (fchmod(fdt, st->st_mode & 07777) < 0) - r = -errno; - - (void) futimens(fdt, ut); - (void) copy_xattr(dirfd(d), fdt); - } - FOREACH_DIRENT_ALL(de, d, return -errno) { struct stat buf; int q; @@ -378,6 +362,22 @@ static int fd_copy_directory( r = q; } + if (created) { + struct timespec ut[2] = { + st->st_atim, + st->st_mtim + }; + + if (fchown(fdt, st->st_uid, st->st_gid) < 0) + r = -errno; + + if (fchmod(fdt, st->st_mode & 07777) < 0) + r = -errno; + + (void) copy_xattr(dirfd(d), fdt); + (void) futimens(fdt, ut); + } + return r; } @@ -409,7 +409,6 @@ int copy_tree(const char *from, const char *to, bool merge) { } int copy_directory_fd(int dirfd, const char *to, bool merge) { - struct stat st; assert(dirfd >= 0); -- cgit v1.2.3-54-g00ecf From a67d68b84801dccbbc03010c679138bb9e4f91ac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 20:05:44 +0200 Subject: tree-wide: fix invocations of chattr_path() chattr_path() takes two bitmasks, and no booleans. Fix the various invocations to do this properly. --- src/journal/journal-file.c | 2 +- src/shared/machine-image.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index c9ce5c73be..ec50333c2c 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -3293,7 +3293,7 @@ int journal_file_open_reliably( /* btrfs doesn't cope well with our write pattern and * fragments heavily. Let's defrag all files we rotate */ - (void) chattr_path(p, false, FS_NOCOW_FL); + (void) chattr_path(p, 0, FS_NOCOW_FL); (void) btrfs_defrag(p); log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 042ccc071c..eb8f6ee438 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -423,7 +423,7 @@ int image_remove(Image *i) { case IMAGE_DIRECTORY: /* Allow deletion of read-only directories */ - (void) chattr_path(i->path, false, FS_IMMUTABLE_FL); + (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL); r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); if (r < 0) return r; @@ -505,7 +505,7 @@ int image_rename(Image *i, const char *new_name) { (void) read_attr_path(i->path, &file_attr); if (file_attr & FS_IMMUTABLE_FL) - (void) chattr_path(i->path, false, FS_IMMUTABLE_FL); + (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL); /* fall through */ @@ -538,7 +538,7 @@ int image_rename(Image *i, const char *new_name) { /* Restore the immutable bit, if it was set before */ if (file_attr & FS_IMMUTABLE_FL) - (void) chattr_path(new_path, true, FS_IMMUTABLE_FL); + (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL); free(i->path); i->path = new_path; @@ -670,7 +670,7 @@ int image_read_only(Image *i, bool b) { a read-only subvolume, but at least something, and we can read the value back.*/ - r = chattr_path(i->path, b, FS_IMMUTABLE_FL); + r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 9a50e3caab82f8406ecfac6048ac8e2ce98b0ab8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 20:06:20 +0200 Subject: machined: support non-btrfs file systems with "machinectl clone" Fall back to a normal copy operation when the backing file system isn't btrfs, and hence doesn't support cheap snapshotting. Of course, this will be slow, but given that the execution is asynchronous now, this should be OK. Fixes: #1308 --- src/basic/copy.c | 15 +++++++++++++++ src/basic/copy.h | 1 + src/shared/machine-image.c | 14 +++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index 79b9a0e1a0..c3586728d0 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -423,6 +423,21 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) { return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge); } +int copy_directory(const char *from, const char *to, bool merge) { + struct stat st; + + assert(from); + assert(to); + + if (lstat(from, &st) < 0) + return -errno; + + if (!S_ISDIR(st.st_mode)) + return -ENOTDIR; + + return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge); +} + int copy_file_fd(const char *from, int fdt, bool try_reflink) { _cleanup_close_ int fdf = -1; int r; diff --git a/src/basic/copy.h b/src/basic/copy.h index 3e5eb52506..b5d08ebafe 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -30,6 +30,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace int copy_tree(const char *from, const char *to, bool merge); int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge); int copy_directory_fd(int dirfd, const char *to, bool merge); +int copy_directory(const char *from, const char *to, bool merge); int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink); int copy_times(int fdf, int fdt); int copy_xattr(int fdf, int fdt); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index eb8f6ee438..66f58ecd92 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -603,12 +603,20 @@ int image_clone(Image *i, const char *new_name, bool read_only) { case IMAGE_SUBVOLUME: case IMAGE_DIRECTORY: + /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain + * directory.*/ + new_path = strjoina("/var/lib/machines/", new_name); r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); - - /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */ - if (r >= 0) + if (r == -EOPNOTSUPP) { + /* No btrfs snapshots supported, create a normal directory then. */ + + r = copy_directory(i->path, new_path, false); + if (r >= 0) + (void) chattr_path(new_path, read_only ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL); + } else if (r >= 0) + /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */ (void) btrfs_subvol_auto_qgroup(new_path, 0, true); break; -- cgit v1.2.3-54-g00ecf From 5d2036b5f3506bd0ff07042aee8d69c26db32298 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 20:17:55 +0200 Subject: machined: also make image removal operation asynchronous If we remove a directory image (i.e. not a btrfs snapshot) then things might get quite expensive, hence run this asynchronous in a forked off process, too. --- src/machine/image-dbus.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index db0ed03b69..e07edae6ef 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -35,13 +35,18 @@ int bus_image_method_remove( void *userdata, sd_bus_error *error) { + _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; Image *image = userdata; Manager *m = image->userdata; + pid_t child; int r; assert(message); assert(image); + if (m->n_operations >= OPERATIONS_MAX) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations."); + r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, @@ -56,11 +61,35 @@ int bus_image_method_remove( if (r == 0) return 1; /* Will call us back */ - r = image_remove(image); - if (r < 0) + 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) { + errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); + + r = image_remove(image); + if (r < 0) { + (void) write(errno_pipe_fd[1], &r, sizeof(r)); + _exit(EXIT_FAILURE); + } + + _exit(EXIT_SUCCESS); + } + + errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); + + r = operation_new(m, child, message, errno_pipe_fd[0]); + if (r < 0) { + (void) sigkill_wait(child); return r; + } - return sd_bus_reply_method_return(message, NULL); + errno_pipe_fd[0] = -1; + + return 1; } int bus_image_method_rename( -- cgit v1.2.3-54-g00ecf From 795c5d31affeb3b3edbf673940cc0f16afebc7a8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 20:32:56 +0200 Subject: machined: rework copy-from/copy-to operation to use generic Operation object With this all potentially slow operations are done out-of-process, asynchronously, using the same "Operation" object. --- src/machine/image-dbus.c | 4 +-- src/machine/machine-dbus.c | 66 +++++----------------------------------------- src/machine/machine.c | 24 +---------------- src/machine/machine.h | 20 +++----------- src/machine/operation.c | 23 ++++++++++++---- src/machine/operation.h | 4 ++- 6 files changed, 33 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index e07edae6ef..0eed9b81bb 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -81,7 +81,7 @@ int bus_image_method_remove( errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - r = operation_new(m, child, message, errno_pipe_fd[0]); + r = operation_new(m, NULL, child, message, errno_pipe_fd[0]); if (r < 0) { (void) sigkill_wait(child); return r; @@ -193,7 +193,7 @@ int bus_image_method_clone( errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - r = operation_new(m, child, message, errno_pipe_fd[0]); + r = operation_new(m, NULL, child, message, errno_pipe_fd[0]); if (r < 0) { (void) sigkill_wait(child); return r; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 5121bfdd18..7b9aa66d63 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -1085,52 +1085,11 @@ finish: return r; } -static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) { - _cleanup_(sd_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, "Child 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, "Child 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; @@ -1139,7 +1098,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro assert(message); assert(m); - if (m->n_operations >= MACHINE_OPERATIONS_MAX) + if (m->manager->n_operations >= OPERATIONS_MAX) return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies."); if (m->class != MACHINE_CONTAINER) @@ -1249,27 +1208,14 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - /* Copying might take a while, hence install a watch the - * child, and return */ + /* Copying might take a while, hence install a watch on 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); + r = operation_new(m->manager, m, child, message, errno_pipe_fd[0]); if (r < 0) { - machine_operation_unref(o); - return log_oom(); + (void) sigkill_wait(child); + return r; } - - LIST_PREPEND(operations, m->operations, o); - m->n_operations++; - o->machine = m; + errno_pipe_fd[0] = -1; return 1; } diff --git a/src/machine/machine.c b/src/machine/machine.c index 7d4270a8ff..c1fae57084 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -89,7 +89,7 @@ void machine_free(Machine *m) { assert(m); while (m->operations) - machine_operation_unref(m->operations); + operation_free(m->operations); if (m->in_gc_queue) LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m); @@ -596,28 +596,6 @@ int machine_open_terminal(Machine *m, const char *path, int mode) { } } -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); diff --git a/src/machine/machine.h b/src/machine/machine.h index 1d8cc5911a..e5d75361a9 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -20,11 +20,11 @@ ***/ typedef struct Machine Machine; -typedef struct MachineOperation MachineOperation; typedef enum KillWho KillWho; #include "list.h" #include "machined.h" +#include "operation.h" typedef enum MachineState { MACHINE_OPENING, /* Machine is being registered */ @@ -49,17 +49,6 @@ 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; @@ -88,10 +77,9 @@ struct Machine { int *netif; unsigned n_netif; - LIST_FIELDS(Machine, gc_queue); + LIST_HEAD(Operation, operations); - MachineOperation *operations; - unsigned n_operations; + LIST_FIELDS(Machine, gc_queue); }; Machine* machine_new(Manager *manager, MachineClass class, const char *name); @@ -109,8 +97,6 @@ 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/operation.c b/src/machine/operation.c index e8564c29f7..e6ddc41a55 100644 --- a/src/machine/operation.c +++ b/src/machine/operation.c @@ -66,15 +66,20 @@ fail: return 0; } -int operation_new(Manager *m, pid_t child, sd_bus_message *message, int errno_fd) { +int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd) { Operation *o; int r; + assert(manager); + assert(child > 1); + assert(message); + assert(errno_fd >= 0); + o = new0(Operation, 1); if (!o) return -ENOMEM; - r = sd_event_add_child(m->event, &o->event_source, child, WEXITED, operation_done, o); + r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o); if (r < 0) { free(o); return r; @@ -84,9 +89,14 @@ int operation_new(Manager *m, pid_t child, sd_bus_message *message, int errno_fd o->message = sd_bus_message_ref(message); o->errno_fd = errno_fd; - LIST_PREPEND(operations, m->operations, o); - m->n_operations++; - o->manager = m; + LIST_PREPEND(operations, manager->operations, o); + manager->n_operations++; + o->manager = manager; + + if (machine) { + LIST_PREPEND(operations_by_machine, machine->operations, o); + o->machine = machine; + } log_debug("Started new operation " PID_FMT ".", child); @@ -113,6 +123,9 @@ Operation *operation_free(Operation *o) { o->manager->n_operations--; } + if (o->machine) + LIST_REMOVE(operations_by_machine, o->machine->operations, o); + free(o); return NULL; } diff --git a/src/machine/operation.h b/src/machine/operation.h index 9d4c3afe45..7ca47bc3af 100644 --- a/src/machine/operation.h +++ b/src/machine/operation.h @@ -34,12 +34,14 @@ typedef struct Operation Operation; struct Operation { Manager *manager; + Machine *machine; pid_t pid; sd_bus_message *message; int errno_fd; sd_event_source *event_source; LIST_FIELDS(Operation, operations); + LIST_FIELDS(Operation, operations_by_machine); }; -int operation_new(Manager *m, pid_t child, sd_bus_message *message, int errno_fd); +int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd); Operation *operation_free(Operation *o); -- cgit v1.2.3-54-g00ecf From 3d87174db439fea28e956f06a69785415bbf5826 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Apr 2016 20:57:39 +0200 Subject: machinectl: since clone/remove/copy verbs are possibly slow, turn off bus call timeout By default we timeout all bus calls, but if we know that these bus calls might be slow, let's explicitly turn the timeouts off. --- src/machine/machinectl.c | 69 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 5a68c4ceb2..1165ab5afa 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1076,6 +1076,7 @@ static int terminate_machine(int argc, char *argv[], void *userdata) { static int copy_files(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *abs_host_path = NULL; char *dest, *host_path, *container_path; sd_bus *bus = userdata; @@ -1099,18 +1100,27 @@ static int copy_files(int argc, char *argv[], void *userdata) { host_path = abs_host_path; } - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", - copy_from ? "CopyFromMachine" : "CopyToMachine", - &error, - NULL, + copy_from ? "CopyFromMachine" : "CopyToMachine"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append( + m, "sss", argv[1], copy_from ? container_path : host_path, copy_from ? host_path : container_path); + if (r < 0) + return bus_log_create_error(r); + + /* This is a slow operation, hence turn off any method call timeouts */ + r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL); if (r < 0) return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r)); @@ -1393,7 +1403,6 @@ static int shell_machine(int argc, char *argv[], void *userdata) { } static int remove_image(int argc, char *argv[], void *userdata) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1402,19 +1411,27 @@ static int remove_image(int argc, char *argv[], void *userdata) { polkit_agent_open_if_enabled(); for (i = 1; i < argc; i++) { - r = sd_bus_call_method( + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", - "RemoveImage", - &error, - NULL, - "s", argv[i]); - if (r < 0) { - log_error("Could not remove image: %s", bus_error_message(&error, -r)); - return r; - } + "RemoveImage"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "s", argv[i]); + if (r < 0) + return bus_log_create_error(r); + + /* This is a slow operation, hence turn off any method call timeouts */ + r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL); + if (r < 0) + return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r)); } return 0; @@ -1446,24 +1463,30 @@ static int rename_image(int argc, char *argv[], void *userdata) { static int clone_image(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; sd_bus *bus = userdata; int r; polkit_agent_open_if_enabled(); - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", - "CloneImage", - &error, - NULL, - "ssb", argv[1], argv[2], arg_read_only); - if (r < 0) { - log_error("Could not clone image: %s", bus_error_message(&error, -r)); - return r; - } + "CloneImage"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "ssb", argv[1], argv[2], arg_read_only); + if (r < 0) + return bus_log_create_error(r); + + /* This is a slow operation, hence turn off any method call timeouts */ + r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL); + if (r < 0) + return log_error_errno(r, "Could not clone image: %s", bus_error_message(&error, r)); return 0; } -- cgit v1.2.3-54-g00ecf From 82f8bae2113f52ac9849ca085aaaf26d8c9620aa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 11:26:40 +0200 Subject: util: don't dump /proc/cpuinfo contents in debug info This is hardly useful, it's trivial for developers to get that info by running cat /proc/cpuinfo. Fixes #3155 --- src/basic/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/virt.c b/src/basic/virt.c index e6c5a095a0..dace1f4328 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -280,7 +280,7 @@ static int detect_vm_uml(void) { return VIRTUALIZATION_UML; } - log_debug("No virtualization found in /proc/cpuinfo (%s)", cpuinfo_contents); + log_debug("No virtualization found in /proc/cpuinfo."); return VIRTUALIZATION_NONE; } -- cgit v1.2.3-54-g00ecf From 072993504e3e4206ae1019f5461a0372f7d82ddf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 13:01:26 +0200 Subject: core: move enforcement of the start limit into per-unit-type code again Let's move the enforcement of the per-unit start limit from unit.c into the type-specific files again. For unit types that know a concept of "result" codes this allows us to hook up the start limit condition to it with an explicit result code. Also, this makes sure that the state checks in clal like service_start() may be done before the start limit is checked, as the start limit really should be checked last, right before everything has been verified to be in order. The generic start limit logic is left in unit.c, but the invocation of it is moved into the per-type files, in the various xyz_start() functions, so that they may place the check at the right location. Note that this change drops the enforcement entirely from device, slice, target and scope units, since these unit types generally may not fail activation, or may only be activated a single time. This is also documented now. Note that restores the "start-limit-hit" result code that existed before 6bf0f408e4833152197fb38fb10a9989c89f3a59 already in the service code. However, it's not introduced for all units that have a result code concept. Fixes #3166. --- man/systemd.unit.xml | 4 +++- src/core/automount.c | 10 +++++++++- src/core/automount.h | 1 + src/core/busname.c | 8 ++++++++ src/core/busname.h | 1 + src/core/mount.c | 10 +++++++++- src/core/mount.h | 1 + src/core/path.c | 8 ++++++++ src/core/path.h | 1 + src/core/service.c | 9 +++++++++ src/core/service.h | 1 + src/core/socket.c | 8 ++++++++ src/core/socket.h | 1 + src/core/swap.c | 10 +++++++++- src/core/swap.h | 1 + src/core/timer.c | 10 +++++++++- src/core/timer.h | 1 + src/core/unit.c | 8 +------- src/core/unit.h | 2 ++ 19 files changed, 83 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index abd47bd237..90a1ec6b9c 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -770,7 +770,9 @@ systemctl reset-failed will cause the restart rate counter for a service to be flushed, which is useful if the administrator wants to manually start a unit and the start limit interferes with that. Note that this rate-limiting is enforced after any unit condition checks are executed, and hence unit - activations with failing conditions are not counted by this rate limiting. + activations with failing conditions are not counted by this rate limiting. Slice, target, device and scope + units do not enforce this setting, as they are unit types whose activation may either never fail, or may + succeed only a single time. diff --git a/src/core/automount.c b/src/core/automount.c index 7c55d7bc49..c871b02a94 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -751,6 +751,7 @@ fail: static int automount_start(Unit *u) { Automount *a = AUTOMOUNT(u); Unit *trigger; + int r; assert(a); assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED); @@ -766,6 +767,12 @@ static int automount_start(Unit *u) { return -ENOENT; } + r = unit_start_limit_test(u); + if (r < 0) { + automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT); + return r; + } + a->result = AUTOMOUNT_SUCCESS; automount_enter_waiting(a); return 1; @@ -1037,7 +1044,8 @@ static bool automount_supported(void) { static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { [AUTOMOUNT_SUCCESS] = "success", - [AUTOMOUNT_FAILURE_RESOURCES] = "resources" + [AUTOMOUNT_FAILURE_RESOURCES] = "resources", + [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); diff --git a/src/core/automount.h b/src/core/automount.h index cf5b1cf994..414717e5b8 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -26,6 +26,7 @@ typedef struct Automount Automount; typedef enum AutomountResult { AUTOMOUNT_SUCCESS, AUTOMOUNT_FAILURE_RESOURCES, + AUTOMOUNT_FAILURE_START_LIMIT_HIT, _AUTOMOUNT_RESULT_MAX, _AUTOMOUNT_RESULT_INVALID = -1 } AutomountResult; diff --git a/src/core/busname.c b/src/core/busname.c index f4f433340c..5600d1ac90 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -607,6 +607,7 @@ fail: static int busname_start(Unit *u) { BusName *n = BUSNAME(u); + int r; assert(n); @@ -632,6 +633,12 @@ static int busname_start(Unit *u) { assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED)); + r = unit_start_limit_test(u); + if (r < 0) { + busname_enter_dead(n, BUSNAME_FAILURE_START_LIMIT_HIT); + return r; + } + n->result = BUSNAME_SUCCESS; busname_enter_making(n); @@ -1014,6 +1021,7 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { [BUSNAME_FAILURE_EXIT_CODE] = "exit-code", [BUSNAME_FAILURE_SIGNAL] = "signal", [BUSNAME_FAILURE_CORE_DUMP] = "core-dump", + [BUSNAME_FAILURE_START_LIMIT_HIT] = "start-limit-hit", [BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit", }; diff --git a/src/core/busname.h b/src/core/busname.h index 52c4055dbb..a8562db458 100644 --- a/src/core/busname.h +++ b/src/core/busname.h @@ -32,6 +32,7 @@ typedef enum BusNameResult { BUSNAME_FAILURE_EXIT_CODE, BUSNAME_FAILURE_SIGNAL, BUSNAME_FAILURE_CORE_DUMP, + BUSNAME_FAILURE_START_LIMIT_HIT, BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT, _BUSNAME_RESULT_MAX, _BUSNAME_RESULT_INVALID = -1 diff --git a/src/core/mount.c b/src/core/mount.c index cc07873b24..aa48941f0d 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -984,6 +984,7 @@ fail: static int mount_start(Unit *u) { Mount *m = MOUNT(u); + int r; assert(m); @@ -1002,6 +1003,12 @@ static int mount_start(Unit *u) { assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED); + r = unit_start_limit_test(u); + if (r < 0) { + mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT); + return r; + } + m->result = MOUNT_SUCCESS; m->reload_result = MOUNT_SUCCESS; m->reset_cpu_usage = true; @@ -1821,7 +1828,8 @@ static const char* const mount_result_table[_MOUNT_RESULT_MAX] = { [MOUNT_FAILURE_TIMEOUT] = "timeout", [MOUNT_FAILURE_EXIT_CODE] = "exit-code", [MOUNT_FAILURE_SIGNAL] = "signal", - [MOUNT_FAILURE_CORE_DUMP] = "core-dump" + [MOUNT_FAILURE_CORE_DUMP] = "core-dump", + [MOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult); diff --git a/src/core/mount.h b/src/core/mount.h index 3b343c6b1f..da529c44f4 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -39,6 +39,7 @@ typedef enum MountResult { MOUNT_FAILURE_EXIT_CODE, MOUNT_FAILURE_SIGNAL, MOUNT_FAILURE_CORE_DUMP, + MOUNT_FAILURE_START_LIMIT_HIT, _MOUNT_RESULT_MAX, _MOUNT_RESULT_INVALID = -1 } MountResult; diff --git a/src/core/path.c b/src/core/path.c index 5e7b3eb234..0dd0d375d8 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -560,6 +560,7 @@ static void path_mkdir(Path *p) { static int path_start(Unit *u) { Path *p = PATH(u); Unit *trigger; + int r; assert(p); assert(p->state == PATH_DEAD || p->state == PATH_FAILED); @@ -570,6 +571,12 @@ static int path_start(Unit *u) { return -ENOENT; } + r = unit_start_limit_test(u); + if (r < 0) { + path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT); + return r; + } + path_mkdir(p); p->result = PATH_SUCCESS; @@ -739,6 +746,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); static const char* const path_result_table[_PATH_RESULT_MAX] = { [PATH_SUCCESS] = "success", [PATH_FAILURE_RESOURCES] = "resources", + [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); diff --git a/src/core/path.h b/src/core/path.h index bbbcebd78e..4230c8fb99 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -62,6 +62,7 @@ static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) { typedef enum PathResult { PATH_SUCCESS, PATH_FAILURE_RESOURCES, + PATH_FAILURE_START_LIMIT_HIT, _PATH_RESULT_MAX, _PATH_RESULT_INVALID = -1 } PathResult; diff --git a/src/core/service.c b/src/core/service.c index f7a3fcf2b9..7ebabca5d6 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1957,6 +1957,7 @@ fail: static int service_start(Unit *u) { Service *s = SERVICE(u); + int r; assert(s); @@ -1983,6 +1984,13 @@ static int service_start(Unit *u) { assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)); + /* Make sure we don't enter a busy loop of some kind. */ + r = unit_start_limit_test(u); + if (r < 0) { + service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false); + return r; + } + s->result = SERVICE_SUCCESS; s->reload_result = SERVICE_SUCCESS; s->main_pid_known = false; @@ -3266,6 +3274,7 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = { [SERVICE_FAILURE_SIGNAL] = "signal", [SERVICE_FAILURE_CORE_DUMP] = "core-dump", [SERVICE_FAILURE_WATCHDOG] = "watchdog", + [SERVICE_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); diff --git a/src/core/service.h b/src/core/service.h index c7f1e81bdb..4af3d40439 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -86,6 +86,7 @@ typedef enum ServiceResult { SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP, SERVICE_FAILURE_WATCHDOG, + SERVICE_FAILURE_START_LIMIT_HIT, _SERVICE_RESULT_MAX, _SERVICE_RESULT_INVALID = -1 } ServiceResult; diff --git a/src/core/socket.c b/src/core/socket.c index 7eeed068bd..c500d122d8 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2057,6 +2057,7 @@ fail: static int socket_start(Unit *u) { Socket *s = SOCKET(u); + int r; assert(s); @@ -2101,6 +2102,12 @@ static int socket_start(Unit *u) { assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED); + r = unit_start_limit_test(u); + if (r < 0) { + socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT); + return r; + } + s->result = SOCKET_SUCCESS; s->reset_cpu_usage = true; @@ -2818,6 +2825,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { [SOCKET_FAILURE_EXIT_CODE] = "exit-code", [SOCKET_FAILURE_SIGNAL] = "signal", [SOCKET_FAILURE_CORE_DUMP] = "core-dump", + [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" }; diff --git a/src/core/socket.h b/src/core/socket.h index 2a4b1bb674..0f1ac69c6f 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -52,6 +52,7 @@ typedef enum SocketResult { SOCKET_FAILURE_EXIT_CODE, SOCKET_FAILURE_SIGNAL, SOCKET_FAILURE_CORE_DUMP, + SOCKET_FAILURE_START_LIMIT_HIT, SOCKET_FAILURE_TRIGGER_LIMIT_HIT, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, _SOCKET_RESULT_MAX, diff --git a/src/core/swap.c b/src/core/swap.c index d8802470d2..300911866f 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -814,6 +814,7 @@ fail: static int swap_start(Unit *u) { Swap *s = SWAP(u), *other; + int r; assert(s); @@ -842,6 +843,12 @@ static int swap_start(Unit *u) { if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING) return -EAGAIN; + r = unit_start_limit_test(u); + if (r < 0) { + swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT); + return r; + } + s->result = SWAP_SUCCESS; s->reset_cpu_usage = true; @@ -1447,7 +1454,8 @@ static const char* const swap_result_table[_SWAP_RESULT_MAX] = { [SWAP_FAILURE_TIMEOUT] = "timeout", [SWAP_FAILURE_EXIT_CODE] = "exit-code", [SWAP_FAILURE_SIGNAL] = "signal", - [SWAP_FAILURE_CORE_DUMP] = "core-dump" + [SWAP_FAILURE_CORE_DUMP] = "core-dump", + [SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult); diff --git a/src/core/swap.h b/src/core/swap.h index ac7a63d81b..fbf66debdc 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -38,6 +38,7 @@ typedef enum SwapResult { SWAP_FAILURE_EXIT_CODE, SWAP_FAILURE_SIGNAL, SWAP_FAILURE_CORE_DUMP, + SWAP_FAILURE_START_LIMIT_HIT, _SWAP_RESULT_MAX, _SWAP_RESULT_INVALID = -1 } SwapResult; diff --git a/src/core/timer.c b/src/core/timer.c index f8f5f4b2e4..3206296f09 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -599,6 +599,7 @@ static int timer_start(Unit *u) { Timer *t = TIMER(u); TimerValue *v; Unit *trigger; + int r; assert(t); assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); @@ -609,6 +610,12 @@ static int timer_start(Unit *u) { return -ENOENT; } + r = unit_start_limit_test(u); + if (r < 0) { + timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT); + return r; + } + t->last_trigger = DUAL_TIMESTAMP_NULL; /* Reenable all timers that depend on unit activation time */ @@ -808,7 +815,8 @@ DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); static const char* const timer_result_table[_TIMER_RESULT_MAX] = { [TIMER_SUCCESS] = "success", - [TIMER_FAILURE_RESOURCES] = "resources" + [TIMER_FAILURE_RESOURCES] = "resources", + [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult); diff --git a/src/core/timer.h b/src/core/timer.h index 698e6da2f5..9c4b64f898 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -48,6 +48,7 @@ typedef struct TimerValue { typedef enum TimerResult { TIMER_SUCCESS, TIMER_FAILURE_RESOURCES, + TIMER_FAILURE_START_LIMIT_HIT, _TIMER_RESULT_MAX, _TIMER_RESULT_INVALID = -1 } TimerResult; diff --git a/src/core/unit.c b/src/core/unit.c index 64466e4fb4..fd9ecc36ce 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1462,7 +1462,7 @@ void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) { unit_status_print_starting_stopping(u, t); } -static int unit_start_limit_test(Unit *u) { +int unit_start_limit_test(Unit *u) { assert(u); if (ratelimit_test(&u->start_limit)) { @@ -1488,7 +1488,6 @@ static int unit_start_limit_test(Unit *u) { int unit_start(Unit *u) { UnitActiveState state; Unit *following; - int r; assert(u); @@ -1541,11 +1540,6 @@ int unit_start(Unit *u) { if (!UNIT_VTABLE(u)->start) return -EBADR; - /* Make sure we don't enter a busy loop of some kind. */ - r = unit_start_limit_test(u); - if (r < 0) - return r; - /* We don't suppress calls to ->start() here when we are * already starting, to allow this request to be used as a * "hurry up" call, for example when the unit is in some "auto diff --git a/src/core/unit.h b/src/core/unit.h index 5909652976..6ae1a8984a 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -617,6 +617,8 @@ static inline bool unit_supported(Unit *u) { void unit_warn_if_dir_nonempty(Unit *u, const char* where); int unit_fail_if_symlink(Unit *u, const char* where); +int unit_start_limit_test(Unit *u); + /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full(unit, level, error, ...) \ -- cgit v1.2.3-54-g00ecf From 87ec20ef2089712e6c9a9f3ddfba6c5e312694fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 14:50:27 +0200 Subject: core: fix detection whether per-unit drop-ins changed This fixes fall-out from 6d10d308c6cd16528ef58fa4f5822aef936862d3. Until that commit, do determine whether a daemon reload was required we compare the mtime of the main unit file we loaded with the mtime of it on disk for equality, but for drop-ins we only stored the newest mtime of all of them and then did a "newer-than" comparison. This was brokeni with the above commit, when all checks where changed to be for equality. With this change all checks are now done as "newer-than", fixing the drop-in mtime case. Strictly speaking this will not detect a number of changes that the code before above commit detected, but given that the mtime is unlikely to go backwards, and this is just intended to be a helpful hint anyway, this looks OK in order to keep things simple. Fixes: #3123 --- src/core/unit.c | 10 +++++----- src/systemctl/systemctl.c | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index fd9ecc36ce..b4d313a71b 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2945,7 +2945,7 @@ int unit_coldplug(Unit *u) { return 0; } -static bool fragment_mtime_changed(const char *path, usec_t mtime) { +static bool fragment_mtime_newer(const char *path, usec_t mtime) { struct stat st; if (!path) @@ -2957,7 +2957,7 @@ static bool fragment_mtime_changed(const char *path, usec_t mtime) { if (mtime > 0) /* For non-empty files check the mtime */ - return timespec_load(&st.st_mtim) != mtime; + return timespec_load(&st.st_mtim) > mtime; else if (!null_or_empty(&st)) /* For masked files check if they are still so */ return true; @@ -2972,8 +2972,8 @@ bool unit_need_daemon_reload(Unit *u) { assert(u); - if (fragment_mtime_changed(u->fragment_path, u->fragment_mtime) || - fragment_mtime_changed(u->source_path, u->source_mtime)) + if (fragment_mtime_newer(u->fragment_path, u->fragment_mtime) || + fragment_mtime_newer(u->source_path, u->source_mtime)) return true; (void) unit_find_dropin_paths(u, &t); @@ -2986,7 +2986,7 @@ bool unit_need_daemon_reload(Unit *u) { if (strv_overlap(u->dropin_paths, t)) { STRV_FOREACH(path, u->dropin_paths) - if (fragment_mtime_changed(*path, u->dropin_mtime)) + if (fragment_mtime_newer(*path, u->dropin_mtime)) return true; return false; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9af25e22a4..bec4f31b39 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2334,6 +2334,8 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) { } static void warn_unit_file_changed(const char *name) { + assert(name); + log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.", ansi_highlight_red(), ansi_normal(), -- cgit v1.2.3-54-g00ecf From ab932a622d57fd327ef95992c343fd4425324088 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 15:07:40 +0200 Subject: core: simplify unit_need_daemon_reload() a bit And let's make it more accurate: if we have acquire the list of unit drop-ins, then let's do a full comparison against the old list we already have, and if things differ in any way, we know we have to reload. This makes sure we detect changes to drop-in directories in more cases. --- src/core/unit.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index b4d313a71b..93aead0489 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2968,32 +2968,24 @@ static bool fragment_mtime_newer(const char *path, usec_t mtime) { bool unit_need_daemon_reload(Unit *u) { _cleanup_strv_free_ char **t = NULL; char **path; - unsigned loaded_cnt, current_cnt; assert(u); - if (fragment_mtime_newer(u->fragment_path, u->fragment_mtime) || - fragment_mtime_newer(u->source_path, u->source_mtime)) + if (fragment_mtime_newer(u->fragment_path, u->fragment_mtime)) return true; - (void) unit_find_dropin_paths(u, &t); - loaded_cnt = strv_length(t); - current_cnt = strv_length(u->dropin_paths); - - if (loaded_cnt == current_cnt) { - if (loaded_cnt == 0) - return false; + if (fragment_mtime_newer(u->source_path, u->source_mtime)) + return true; - if (strv_overlap(u->dropin_paths, t)) { - STRV_FOREACH(path, u->dropin_paths) - if (fragment_mtime_newer(*path, u->dropin_mtime)) - return true; + (void) unit_find_dropin_paths(u, &t); + if (!strv_equal(u->dropin_paths, t)) + return true; - return false; - } - } + STRV_FOREACH(path, u->dropin_paths) + if (fragment_mtime_newer(*path, u->dropin_mtime)) + return true; - return true; + return false; } void unit_reset_failed(Unit *u) { -- cgit v1.2.3-54-g00ecf From 7b2fd9d51259f6cf350791434e640ac3519acc6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 16:01:16 +0200 Subject: core: remove duplicate code in automount_update_mount() Also, fix indentation. --- src/core/automount.c | 39 +++++++++++---------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index c871b02a94..464d6a70c0 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -477,39 +477,22 @@ int automount_update_mount(Automount *a, MountState old_state, MountState state) if (r < 0) log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m"); 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: + + 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); + (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); 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; } -- cgit v1.2.3-54-g00ecf From 9703a8adb5c2ef16fcbf0e92189494a5a3438b06 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 16:01:39 +0200 Subject: automount: add debug message when we get notified about mount state changes --- src/core/automount.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index 464d6a70c0..d2386d04f7 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -408,7 +408,7 @@ static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, in init_autofs_dev_ioctl(¶m); param.ioctlfd = ioctl_fd; - if (status) { + if (status != 0) { param.fail.token = token; param.fail.status = status; } else @@ -435,7 +435,7 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) { if (ioctl_fd < 0) return ioctl_fd; - if (status) + if (status != 0) log_unit_debug_errno(UNIT(a), status, "Sending failure: %m"); else log_unit_debug(UNIT(a), "Sending success."); @@ -469,7 +469,10 @@ int automount_update_mount(Automount *a, MountState old_state, MountState state) assert(a); + log_unit_debug(UNIT(a), "Got notified about mount unit state change %s → %s", mount_state_to_string(old_state), mount_state_to_string(state)); + switch (state) { + case MOUNT_MOUNTED: case MOUNT_REMOUNTING: automount_send_ready(a, a->tokens, 0); -- cgit v1.2.3-54-g00ecf From bd10a84b7ffaa61b83c3cfa46fc75c69b961c360 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 16:02:02 +0200 Subject: fstab-generator: add newline before we start a new unit file section We already did this for the [Mount] section, let's do the same for [Automount]. --- src/fstab-generator/fstab-generator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 6f576b5ecf..343e3b1817 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -379,6 +379,7 @@ static int add_mount( } fprintf(f, + "\n" "[Automount]\n" "Where=%s\n", where); -- cgit v1.2.3-54-g00ecf From d14e3a0de913cd5ef52693a9466129820322cff3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 16:41:41 +0200 Subject: core: don't propagate service state to sockets as long as there's still a job for the service queued --- src/core/socket.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index c500d122d8..d3d4866fe6 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2742,17 +2742,26 @@ static void socket_trigger_notify(Unit *u, Unit *other) { assert(u); assert(other); - /* Don't propagate state changes from the service if we are - already down or accepting connections */ - if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING) || s->accept) + /* Filter out invocations with bogus state */ + if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE) + return; + + /* Don't propagate state changes from the service if we are already down */ + if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING)) return; + /* We don't care for the service state if we are in Accept=yes mode */ + if (s->accept) + return; + + /* Propagate start limit hit state */ if (other->start_limit_hit) { socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT); return; } - if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE) + /* Don't propagate anything if there's still a job queued */ + if (other->job) return; if (IN_SET(SERVICE(other)->state, -- cgit v1.2.3-54-g00ecf From fae03ed32a77934a5c39ed8e338ec6c7a75857a0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 16:51:45 +0200 Subject: automount: rework propagation between automount and mount units Port the progagation logic to the generic Unit->trigger_notify() callback logic in the unit vtable, that is called for a unit not only when the triggered unit of it changes state but also when a job for that unit finishes. This, firstly allows us to make the code a bit cleaner and more generic, but more importantly, allows us to notice correctly when a mount job fails, and propagate that back to autofs client processes. Fixes: #2181 --- src/core/automount.c | 65 +++++++++++++++++++++++++++++++++------------------- src/core/automount.h | 3 +-- src/core/mount.c | 19 --------------- 3 files changed, 42 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index d2386d04f7..5577c64255 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -464,43 +464,57 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) { static int automount_start_expire(Automount *a); -int automount_update_mount(Automount *a, MountState old_state, MountState state) { +static void automount_trigger_notify(Unit *u, Unit *other) { + Automount *a = AUTOMOUNT(u); int r; assert(a); + assert(other); + + /* Filter out invocations with bogus state */ + if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT) + return; + + /* Don't propagate state changes from the mount if we are already down */ + if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING)) + return; - log_unit_debug(UNIT(a), "Got notified about mount unit state change %s → %s", mount_state_to_string(old_state), mount_state_to_string(state)); + /* Propagate start limit hit state */ + if (other->start_limit_hit) { + automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT); + return; + } - switch (state) { + /* Don't propagate anything if there's still a job queued */ + if (other->job) + return; + + /* The mount is successfully established */ + if (IN_SET(MOUNT(other)->state, MOUNT_MOUNTED, MOUNT_REMOUNTING)) { + (void) automount_send_ready(a, a->tokens, 0); - case MOUNT_MOUNTED: - case MOUNT_REMOUNTING: - automount_send_ready(a, a->tokens, 0); r = automount_start_expire(a); if (r < 0) log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m"); - 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); + automount_set_state(a, AUTOMOUNT_RUNNING); + } - (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); - break; + /* The mount is in some unhappy state now, let's unfreeze any waiting clients */ + if (IN_SET(MOUNT(other)->state, + MOUNT_DEAD, MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED)) { - default: - break; - } + (void) automount_send_ready(a, a->tokens, -ENODEV); - return 0; + if (a->expire_event_source) + (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); + + automount_set_state(a, AUTOMOUNT_WAITING); + } } static void automount_enter_waiting(Automount *a) { @@ -1032,6 +1046,7 @@ static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { [AUTOMOUNT_SUCCESS] = "success", [AUTOMOUNT_FAILURE_RESOURCES] = "resources", [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); @@ -1066,6 +1081,8 @@ const UnitVTable automount_vtable = { .check_gc = automount_check_gc, + .trigger_notify = automount_trigger_notify, + .reset_failed = automount_reset_failed, .bus_vtable = bus_automount_vtable, diff --git a/src/core/automount.h b/src/core/automount.h index 414717e5b8..76a201178e 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -27,6 +27,7 @@ typedef enum AutomountResult { AUTOMOUNT_SUCCESS, AUTOMOUNT_FAILURE_RESOURCES, AUTOMOUNT_FAILURE_START_LIMIT_HIT, + AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT, _AUTOMOUNT_RESULT_MAX, _AUTOMOUNT_RESULT_INVALID = -1 } AutomountResult; @@ -54,7 +55,5 @@ struct Automount { extern const UnitVTable automount_vtable; -int automount_update_mount(Automount *a, MountState old_state, MountState state); - const char* automount_result_to_string(AutomountResult i) _const_; AutomountResult automount_result_from_string(const char *s) _pure_; diff --git a/src/core/mount.c b/src/core/mount.c index aa48941f0d..037f3684c7 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -584,23 +584,6 @@ static int mount_load(Unit *u) { return mount_verify(m); } -static int mount_notify_automount(Mount *m, MountState old_state, MountState state) { - Unit *p; - int r; - Iterator i; - - assert(m); - - SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i) - if (p->type == UNIT_AUTOMOUNT) { - r = automount_update_mount(AUTOMOUNT(p), old_state, state); - if (r < 0) - return r; - } - - return 0; -} - static void mount_set_state(Mount *m, MountState state) { MountState old_state; assert(m); @@ -624,8 +607,6 @@ static void mount_set_state(Mount *m, MountState state) { m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID; } - mount_notify_automount(m, old_state, state); - if (state != old_state) log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state)); -- cgit v1.2.3-54-g00ecf From dbb0578edc5ab8e11641c8b2d29904d4f5f8e1e6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 17:12:35 +0200 Subject: automount: move resetting of expiry timeout to automount_set_state() that way we can be sure that there's no expiry timeout in place at any time when we aren't in the RUNNING state. --- src/core/automount.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/automount.c b/src/core/automount.c index 5577c64255..e2590a22bc 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -75,6 +75,9 @@ 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); +static int automount_start_expire(Automount *a); +static void automount_stop_expire(Automount *a); +static int automount_send_ready(Automount *a, Set *tokens, int status); static void automount_init(Unit *u) { Automount *a = AUTOMOUNT(u); @@ -87,8 +90,6 @@ static void automount_init(Unit *u) { UNIT(a)->ignore_on_isolate = true; } -static int automount_send_ready(Automount *a, Set *tokens, int status); - static void unmount_autofs(Automount *a) { int r; @@ -235,6 +236,9 @@ static void automount_set_state(Automount *a, AutomountState state) { old_state = a->state; a->state = state; + if (state != AUTOMOUNT_RUNNING) + automount_stop_expire(a); + if (state != AUTOMOUNT_WAITING && state != AUTOMOUNT_RUNNING) unmount_autofs(a); @@ -462,8 +466,6 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) { return r; } -static int automount_start_expire(Automount *a); - static void automount_trigger_notify(Unit *u, Unit *other) { Automount *a = AUTOMOUNT(u); int r; @@ -510,9 +512,6 @@ static void automount_trigger_notify(Unit *u, Unit *other) { (void) automount_send_ready(a, a->tokens, -ENODEV); - if (a->expire_event_source) - (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); - automount_set_state(a, AUTOMOUNT_WAITING); } } @@ -699,6 +698,15 @@ static int automount_start_expire(Automount *a) { return 0; } +static void automount_stop_expire(Automount *a) { + assert(a); + + if (!a->expire_event_source) + return; + + (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); +} + static void automount_enter_runnning(Automount *a) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; struct stat st; @@ -965,7 +973,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo 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); + automount_stop_expire(a); r = set_ensure_allocated(&a->expire_tokens, NULL); if (r < 0) { -- cgit v1.2.3-54-g00ecf From 4bbc06cc9e3b8c61c1ae3c4ee72bc834efd63fea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 May 2016 18:29:28 +0200 Subject: resolved: work around broken DNS zones set up by incapdns.net incapdns.net returns NXDOMAIN for the SOA of the zone itself but is not a terminal. This is against the specs, but we really should be able to deal with this. Previously, when verifying whether an NXDOMAIN response for a SOA/NS lookup is rightfully unsigned we'd issue a SOA lookup for the parent's domain, to derive the state from that. If the parent SOA would get an NXDOMAIN, we'd continue upwards, until we hit a signed top-level domain, which suggests that the domain actually exists. With this change whenver we need to authenticate an NXDOMAIN SOA reply, we'll request the DS RR for the zone first, and use for validation, since that this must be from the parent's zone, not the incorrect lower zone. Fixes: #2894 --- src/resolve/resolved-dns-transaction.c | 65 +++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 081131ede0..a4a67623e7 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1804,7 +1804,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * - For unsigned SOA/NS we get the matching DS * - For unsigned CNAME/DNAME/DS we get the parent SOA RR * - For other unsigned RRs we get the matching SOA RR - * - For SOA/NS/DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR + * - For SOA/NS queries with no matching response RR, and no NSEC/NSEC3, the DS RR + * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR * - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR */ @@ -2038,32 +2039,42 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { return r; if (r > 0) { const char *name; + uint16_t type = 0; name = dns_resource_key_name(t->key); - /* If this was a SOA or NS request, then this - * indicates that we are not at a zone apex, hence ask - * the parent name instead. If this was a DS request, - * then it's signed when the parent zone is signed, - * hence ask the parent in that case, too. */ + /* If this was a SOA or NS request, then check if there's a DS RR for the same domain. Note that this + * could also be used as indication that we are not at a zone apex, but in real world setups there are + * too many broken DNS servers (Hello, incapdns.net!) where non-terminal zones return NXDOMAIN even + * though they have further children. If this was a DS request, then it's signed when the parent zone + * is signed, hence ask the parent SOA in that case. If this was any other RR then ask for the SOA RR, + * to see if that is signed. */ - if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) { + if (t->key->type == DNS_TYPE_DS) { r = dns_name_parent(&name); - if (r < 0) - return r; - if (r > 0) - log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS/DS response).", + if (r > 0) { + type = DNS_TYPE_SOA; + log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty DS response).", t->id, dns_resource_key_name(t->key)); - else + } else name = NULL; - } else + + } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) { + + type = DNS_TYPE_DS; + log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS response).", + t->id, dns_resource_key_name(t->key)); + + } else { + type = DNS_TYPE_SOA; log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", t->id, dns_resource_key_name(t->key)); + } if (name) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL; - soa = dns_resource_key_new(t->key->class, DNS_TYPE_SOA, name); + soa = dns_resource_key_new(t->key->class, type, name); if (!soa) return -ENOMEM; @@ -2317,11 +2328,12 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe } static int dns_transaction_requires_nsec(DnsTransaction *t) { + char key_str[DNS_RESOURCE_KEY_STRING_MAX]; DnsTransaction *dt; const char *name; + uint16_t type = 0; Iterator i; int r; - char key_str[DNS_RESOURCE_KEY_STRING_MAX]; assert(t); @@ -2355,22 +2367,25 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { name = dns_resource_key_name(t->key); - if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) { + if (t->key->type == DNS_TYPE_DS) { - /* We got a negative reply for this SOA/NS lookup? If - * so, then we are not at a zone apex, and thus should - * look at the result of the parent SOA lookup. - * - * We got a negative reply for this DS lookup? DS RRs - * are signed when their parent zone is signed, hence - * also check the parent SOA in this case. */ + /* We got a negative reply for this DS lookup? DS RRs are signed when their parent zone is signed, + * hence check the parent SOA in this case. */ r = dns_name_parent(&name); if (r < 0) return r; if (r == 0) return true; - } + + type = DNS_TYPE_SOA; + + } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) + /* We got a negative reply for this SOA/NS lookup? If so, check if there's a DS RR for this */ + type = DNS_TYPE_DS; + else + /* For all other negative replies, check for the SOA lookup */ + type = DNS_TYPE_SOA; /* For all other RRs we check the SOA on the same level to see * if it's signed. */ @@ -2379,7 +2394,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { if (dt->key->class != t->key->class) continue; - if (dt->key->type != DNS_TYPE_SOA) + if (dt->key->type != type) continue; r = dns_name_equal(dns_resource_key_name(dt->key), name); -- cgit v1.2.3-54-g00ecf From 7a40831a8a1ade7a9f0512b0bd2cb65765026d01 Mon Sep 17 00:00:00 2001 From: Sylvain Plantefève Date: Tue, 3 May 2016 01:43:37 +0200 Subject: locale: Language fallbacks for fr_(BE|CA|CH|LU) to fr_FR (#3178) --- src/locale/language-fallback-map | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/locale/language-fallback-map b/src/locale/language-fallback-map index 6aadda091a..d0b02a6b98 100644 --- a/src/locale/language-fallback-map +++ b/src/locale/language-fallback-map @@ -3,6 +3,10 @@ en_AU en_AU:en_GB en_IE en_IE:en_GB en_NZ en_NZ:en_GB en_ZA en_ZA:en_GB +fr_BE fr_BE:fr_FR +fr_CA fr_CA:fr_FR +fr_CH fr_CH:fr_FR +fr_LU fr_LU:fr_FR it_CH it_CH:it_IT mai_IN mai:hi nds_DE nds:de -- cgit v1.2.3-54-g00ecf From 4b558378a730789ed99c190182c977e2055f0c00 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 3 May 2016 11:52:44 -0400 Subject: sd-dhcp{,6}-client: use standard indentation for functions args --- src/libsystemd-network/sd-dhcp-client.c | 143 ++++++++++++++++++++----------- src/libsystemd-network/sd-dhcp6-client.c | 37 ++++---- src/systemd/sd-dhcp-client.h | 78 ++++++++++++----- src/systemd/sd-dhcp6-client.h | 61 +++++++++---- 4 files changed, 214 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 287b6e26fa..1571754355 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -115,14 +115,22 @@ static const uint8_t default_req_opts[] = { SD_DHCP_OPTION_DOMAIN_NAME_SERVER, }; -static int client_receive_message_raw(sd_event_source *s, int fd, - uint32_t revents, void *userdata); -static int client_receive_message_udp(sd_event_source *s, int fd, - uint32_t revents, void *userdata); +static int client_receive_message_raw( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata); +static int client_receive_message_udp( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata); static void client_stop(sd_dhcp_client *client, int error); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, - void *userdata) { +int sd_dhcp_client_set_callback( + sd_dhcp_client *client, + sd_dhcp_client_callback_t cb, + void *userdata) { assert_return(client, -EINVAL); client->cb = cb; @@ -171,8 +179,9 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { return 0; } -int sd_dhcp_client_set_request_address(sd_dhcp_client *client, - const struct in_addr *last_addr) { +int sd_dhcp_client_set_request_address( + sd_dhcp_client *client, + const struct in_addr *last_addr) { assert_return(client, -EINVAL); assert_return (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); @@ -196,8 +205,12 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) { return 0; } -int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type) { +int sd_dhcp_client_set_mac( + sd_dhcp_client *client, + const uint8_t *addr, + size_t addr_len, + uint16_t arp_type) { + DHCP_CLIENT_DONT_DESTROY(client); bool need_restart = false; @@ -234,8 +247,11 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, return 0; } -int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, - const uint8_t **data, size_t *data_len) { +int sd_dhcp_client_get_client_id( + sd_dhcp_client *client, + uint8_t *type, + const uint8_t **data, + size_t *data_len) { assert_return(client, -EINVAL); assert_return(type, -EINVAL); @@ -254,8 +270,12 @@ int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, return 0; } -int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, - const uint8_t *data, size_t data_len) { +int sd_dhcp_client_set_client_id( + sd_dhcp_client *client, + uint8_t type, + const uint8_t *data, + size_t data_len) { + DHCP_CLIENT_DONT_DESTROY(client); bool need_restart = false; @@ -298,8 +318,13 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, - uint16_t duid_type, uint8_t *duid, size_t duid_len) { +int sd_dhcp_client_set_iaid_duid( + sd_dhcp_client *client, + uint32_t iaid, + uint16_t duid_type, + uint8_t *duid, + size_t duid_len) { + DHCP_CLIENT_DONT_DESTROY(client); int r; assert_return(client, -EINVAL); @@ -344,8 +369,10 @@ int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, return 0; } -int sd_dhcp_client_set_hostname(sd_dhcp_client *client, - const char *hostname) { +int sd_dhcp_client_set_hostname( + sd_dhcp_client *client, + const char *hostname) { + char *new_hostname = NULL; assert_return(client, -EINVAL); @@ -368,8 +395,10 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client, return 0; } -int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, - const char *vci) { +int sd_dhcp_client_set_vendor_class_identifier( + sd_dhcp_client *client, + const char *vci) { + char *new_vci = NULL; assert_return(client, -EINVAL); @@ -452,8 +481,13 @@ static void client_stop(sd_dhcp_client *client, int error) { client_initialize(client); } -static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, - uint8_t type, size_t *_optlen, size_t *_optoffset) { +static int client_message_init( + sd_dhcp_client *client, + DHCPPacket **ret, + uint8_t type, + size_t *_optlen, + size_t *_optoffset) { + _cleanup_free_ DHCPPacket *packet = NULL; size_t optlen, optoffset, size; be16_t max_size; @@ -594,8 +628,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, return 0; } -static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset, - const char *fqdn) { +static int client_append_fqdn_option( + DHCPMessage *message, + size_t optlen, + size_t *optoffset, + const char *fqdn) { + uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH]; int r; @@ -612,8 +650,11 @@ static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t return r; } -static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, - size_t len) { +static int dhcp_client_send_raw( + sd_dhcp_client *client, + DHCPPacket *packet, + size_t len) { + dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, INADDR_BROADCAST, DHCP_PORT_SERVER, len); @@ -820,8 +861,11 @@ static int client_send_request(sd_dhcp_client *client) { static int client_start(sd_dhcp_client *client); -static int client_timeout_resend(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_resend( + sd_event_source *s, + uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); usec_t next_timeout = 0; @@ -965,8 +1009,10 @@ error: return 0; } -static int client_initialize_io_events(sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { +static int client_initialize_io_events( + sd_dhcp_client *client, + sd_event_io_handler_t io_callback) { + int r; assert(client); @@ -1033,8 +1079,7 @@ error: } -static int client_initialize_events(sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { +static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) { client_initialize_io_events(client, io_callback); client_initialize_time_events(client); @@ -1074,8 +1119,7 @@ static int client_start(sd_dhcp_client *client) { return client_start_delayed(client); } -static int client_timeout_expire(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); @@ -1115,8 +1159,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) return client_initialize_events(client, client_receive_message_raw); } -static int client_timeout_t1(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); @@ -1126,8 +1169,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, return client_initialize_time_events(client); } -static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, - size_t len) { +static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) { _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; int r; @@ -1178,8 +1220,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, return 0; } -static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, - size_t len) { +static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) { int r; r = dhcp_option_parse(force, len, NULL, NULL, NULL); @@ -1191,8 +1232,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, return 0; } -static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, - size_t len) { +static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_free_ char *error_message = NULL; int r; @@ -1420,8 +1460,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return 0; } -static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, - int len) { +static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) { DHCP_CLIENT_DONT_DESTROY(client); char time_string[FORMAT_TIMESPAN_MAX]; int r = 0, notify_event = 0; @@ -1567,8 +1606,12 @@ error: return r; } -static int client_receive_message_udp(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { +static int client_receive_message_udp( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata) { + sd_dhcp_client *client = userdata; _cleanup_free_ DHCPMessage *message = NULL; const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } }; @@ -1645,8 +1688,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd, return client_handle_message(client, message, len); } -static int client_receive_message_raw(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { +static int client_receive_message_raw( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata) { + sd_dhcp_client *client = userdata; _cleanup_free_ DHCPPacket *packet = NULL; uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index ee4fb4fc1e..7dd4990bda 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -111,7 +111,10 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); static int client_start(sd_dhcp6_client *client, enum DHCP6State state); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) { +int sd_dhcp6_client_set_callback( + sd_dhcp6_client *client, + sd_dhcp6_client_callback_t cb, + void *userdata) { assert_return(client, -EINVAL); client->cb = cb; @@ -131,7 +134,10 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { return 0; } -int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) { +int sd_dhcp6_client_set_local_address( + sd_dhcp6_client *client, + const struct in6_addr *local_address) { + assert_return(client, -EINVAL); assert_return(local_address, -EINVAL); assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL); @@ -180,8 +186,11 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, - uint8_t *duid, size_t duid_len) { +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t duid_type, + uint8_t *duid, + size_t duid_len) { int r; assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -427,8 +436,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return 0; } -static int client_timeout_t2(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; assert_return(s, -EINVAL); @@ -445,8 +453,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, return 0; } -static int client_timeout_t1(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; assert_return(s, -EINVAL); @@ -463,8 +470,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, return 0; } -static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); enum DHCP6State state; @@ -490,8 +496,7 @@ static usec_t client_timeout_compute_random(usec_t val) { (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC; } -static int client_timeout_resend(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) { int r = 0; sd_dhcp6_client *client = userdata; usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0; @@ -658,9 +663,11 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { return 0; } -static int client_parse_message(sd_dhcp6_client *client, - DHCP6Message *message, size_t len, - sd_dhcp6_lease *lease) { +static int client_parse_message( + sd_dhcp6_client *client, + DHCP6Message *message, + size_t len, + sd_dhcp6_lease *lease) { int r; uint8_t *optval, *option, *id = NULL; uint16_t optcode, status; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 374ff8774e..6fcf781d90 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -84,28 +84,57 @@ enum { typedef struct sd_dhcp_client sd_dhcp_client; -typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, - void *userdata); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, - void *userdata); - -int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); -int sd_dhcp_client_set_request_address(sd_dhcp_client *client, - const struct in_addr *last_address); -int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast); -int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index); -int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type); -int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, - const uint8_t *data, size_t data_len); -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, - uint16_t duid_type, uint8_t *duid, size_t duid_len); -int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, - const uint8_t **data, size_t *data_len); -int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); -int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname); -int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci); -int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret); +typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); +int sd_dhcp_client_set_callback( + sd_dhcp_client *client, + sd_dhcp_client_callback_t cb, + void *userdata); + +int sd_dhcp_client_set_request_option( + sd_dhcp_client *client, + uint8_t option); +int sd_dhcp_client_set_request_address( + sd_dhcp_client *client, + const struct in_addr *last_address); +int sd_dhcp_client_set_request_broadcast( + sd_dhcp_client *client, + int broadcast); +int sd_dhcp_client_set_index( + sd_dhcp_client *client, + int interface_index); +int sd_dhcp_client_set_mac( + sd_dhcp_client *client, + const uint8_t *addr, + size_t addr_len, + uint16_t arp_type); +int sd_dhcp_client_set_client_id( + sd_dhcp_client *client, + uint8_t type, + const uint8_t *data, + size_t data_len); +int sd_dhcp_client_set_iaid_duid( + sd_dhcp_client *client, + uint32_t iaid, + uint16_t duid_type, + uint8_t *duid, + size_t duid_len); +int sd_dhcp_client_get_client_id( + sd_dhcp_client *client, + uint8_t *type, + const uint8_t **data, + size_t *data_len); +int sd_dhcp_client_set_mtu( + sd_dhcp_client *client, + uint32_t mtu); +int sd_dhcp_client_set_hostname( + sd_dhcp_client *client, + const char *hostname); +int sd_dhcp_client_set_vendor_class_identifier( + sd_dhcp_client *client, + const char *vci); +int sd_dhcp_client_get_lease( + sd_dhcp_client *client, + sd_dhcp_lease **ret); int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client); @@ -115,7 +144,10 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); int sd_dhcp_client_new(sd_dhcp_client **ret); -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority); +int sd_dhcp_client_attach_event( + sd_dhcp_client *client, + sd_event *event, + int64_t priority); int sd_dhcp_client_detach_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 4604cb6382..e29bcfdb8c 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -76,29 +76,52 @@ enum { typedef struct sd_dhcp6_client sd_dhcp6_client; -typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, - void *userdata); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_callback_t cb, void *userdata); - -int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); -int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, - uint8_t *duid, size_t duid_len); -int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid); -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); -int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, - uint16_t option); - -int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret); +typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata); +int sd_dhcp6_client_set_callback( + sd_dhcp6_client *client, + sd_dhcp6_client_callback_t cb, + void *userdata); + +int sd_dhcp6_client_set_index( + sd_dhcp6_client *client, + int interface_index); +int sd_dhcp6_client_set_local_address( + sd_dhcp6_client *client, + const struct in6_addr *local_address); +int sd_dhcp6_client_set_mac( + sd_dhcp6_client *client, + const uint8_t *addr, + size_t addr_len, + uint16_t arp_type); +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t duid_type, + uint8_t *duid, + size_t duid_len); +int sd_dhcp6_client_set_iaid( + sd_dhcp6_client *client, + uint32_t iaid); +int sd_dhcp6_client_set_information_request( + sd_dhcp6_client *client, + int enabled); +int sd_dhcp6_client_get_information_request( + sd_dhcp6_client *client, + int *enabled); +int sd_dhcp6_client_set_request_option( + sd_dhcp6_client *client, + uint16_t option); + +int sd_dhcp6_client_get_lease( + sd_dhcp6_client *client, + sd_dhcp6_lease **ret); int sd_dhcp6_client_stop(sd_dhcp6_client *client); int sd_dhcp6_client_start(sd_dhcp6_client *client); int sd_dhcp6_client_is_running(sd_dhcp6_client *client); -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority); +int sd_dhcp6_client_attach_event( + sd_dhcp6_client *client, + sd_event *event, + int64_t priority); int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); -- cgit v1.2.3-54-g00ecf From f7a92d1a7e351886fc1debb7f4b448287d18c20c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 3 May 2016 12:08:56 -0400 Subject: sd-dhcp: change uint8_t *duid to const void* --- src/libsystemd-network/sd-dhcp-client.c | 2 +- src/libsystemd-network/sd-dhcp6-client.c | 3 ++- src/systemd/sd-dhcp-client.h | 2 +- src/systemd/sd-dhcp6-client.h | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 1571754355..2ca25c9b33 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -322,7 +322,7 @@ int sd_dhcp_client_set_iaid_duid( sd_dhcp_client *client, uint32_t iaid, uint16_t duid_type, - uint8_t *duid, + const void *duid, size_t duid_len) { DHCP_CLIENT_DONT_DESTROY(client); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 7dd4990bda..d3714b174f 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -189,8 +189,9 @@ static int client_ensure_duid(sd_dhcp6_client *client) { int sd_dhcp6_client_set_duid( sd_dhcp6_client *client, uint16_t duid_type, - uint8_t *duid, + const void *duid, size_t duid_len) { + int r; assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 6fcf781d90..20b8c2873f 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -116,7 +116,7 @@ int sd_dhcp_client_set_iaid_duid( sd_dhcp_client *client, uint32_t iaid, uint16_t duid_type, - uint8_t *duid, + const void *duid, size_t duid_len); int sd_dhcp_client_get_client_id( sd_dhcp_client *client, diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index e29bcfdb8c..90f62eaca4 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -96,7 +96,7 @@ int sd_dhcp6_client_set_mac( int sd_dhcp6_client_set_duid( sd_dhcp6_client *client, uint16_t duid_type, - uint8_t *duid, + const void *duid, size_t duid_len); int sd_dhcp6_client_set_iaid( sd_dhcp6_client *client, -- cgit v1.2.3-54-g00ecf From 3b6a4e97eab023f3792efde5bcb82a6e2688b15c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 29 Apr 2016 21:18:02 -0400 Subject: dhcp-identifier: un-inline dhcp_validate_duid_len After all it is used in more than one place and is not that short. Also tweak the test a bit: - do not check that duid_len > 0, because we want to allow unknown duid types, and there might be some which are fine with 0 length data, (also assert should not be called from library code), - always check that duid_len <= MAX_DUID_LEN, because we could overwrite available buffer space otherwise. --- src/libsystemd-network/dhcp-identifier.c | 31 ++++++++++++++++++++++++ src/libsystemd-network/dhcp-identifier.h | 41 +++++--------------------------- 2 files changed, 37 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 4f7d4d8bf2..a21efc4d06 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -31,6 +31,37 @@ #define SYSTEMD_PEN 43793 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { + struct duid d; + + assert_cc(sizeof(d.raw) >= MAX_DUID_LEN); + if (duid_len > MAX_DUID_LEN) + return -EINVAL; + + switch (duid_type) { + case DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} + int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { sd_id128_t machine_id; uint64_t hash; diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index e6486b78f8..dd0f926f90 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -40,27 +40,28 @@ typedef enum DUIDType { */ #define MAX_DUID_LEN 128 +/* https://tools.ietf.org/html/rfc3315#section-9.1 */ struct duid { be16_t type; union { struct { - /* DHCP6_DUID_LLT */ + /* DUID_TYPE_LLT */ uint16_t htype; uint32_t time; uint8_t haddr[0]; } _packed_ llt; struct { - /* DHCP6_DUID_EN */ + /* DUID_TYPE_EN */ uint32_t pen; uint8_t id[8]; } _packed_ en; struct { - /* DHCP6_DUID_LL */ + /* DUID_TYPE_LL */ int16_t htype; uint8_t haddr[0]; } _packed_ ll; struct { - /* DHCP6_DUID_UUID */ + /* DUID_TYPE_UUID */ sd_id128_t uuid; } _packed_ uuid; struct { @@ -69,36 +70,6 @@ struct duid { }; } _packed_; +int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len); 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, void *_id); - -static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { - struct duid d; - - assert(duid_len > 0); - - switch (duid_type) { - case DUID_TYPE_LLT: - if (duid_len <= sizeof(d.llt)) - return -EINVAL; - break; - case DUID_TYPE_EN: - if (duid_len != sizeof(d.en)) - return -EINVAL; - break; - case DUID_TYPE_LL: - if (duid_len <= sizeof(d.ll)) - return -EINVAL; - break; - case DUID_TYPE_UUID: - if (duid_len != sizeof(d.uuid)) - return -EINVAL; - break; - default: - if (duid_len > sizeof(d.raw)) - return -EINVAL; - /* accept unknown type in order to be forward compatible */ - break; - } - return 0; -} -- cgit v1.2.3-54-g00ecf From d7df2fd317bb24d4d194dbd0d391f4dfa64d6924 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 29 Apr 2016 21:18:11 -0400 Subject: dh-dhcp{,6}-client: change the semantics of DUID setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both versions of the code are changed to allow the caller to override DUID using simple rules: duid type and value may be specified, in which case the caller is responsible to providing the contents, or just duid type may be specified as DUID_TYPE_EN, in which case we we fill in the values. In the future more support for other types may be added, e.g. DUID_TYPE_LLT. There still remains and ugly discrepancy between dhcp4 and dhcp6 code: dhcp6 has sd_dhcp6_client_set_duid and sd_dhcp6_client_set_iaid and requires client->state to be DHCP6_STATE_STOPPED, while dhcp4 has sd_dhcp_client_set_iaid_duid and will reconfigure the client if it is not stopped. This commit doesn't touch that part. This addresses #3127 § 2. --- src/libsystemd-network/sd-dhcp-client.c | 38 ++++++++++++++++++++------------ src/libsystemd-network/sd-dhcp6-client.c | 20 ++++++++++++++--- src/network/networkd-manager.c | 2 +- 3 files changed, 42 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 2ca25c9b33..3846cf7476 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -318,6 +318,11 @@ int sd_dhcp_client_set_client_id( return 0; } +/** + * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid + * without further modification. Otherwise, if duid_type is supported, DUID + * is set based on that type. Otherwise, an error is returned. + */ int sd_dhcp_client_set_iaid_duid( sd_dhcp_client *client, uint32_t iaid, @@ -327,9 +332,18 @@ int sd_dhcp_client_set_iaid_duid( DHCP_CLIENT_DONT_DESTROY(client); int r; + size_t len; + assert_return(client, -EINVAL); - zero(client->client_id); + assert_return(duid_len == 0 || duid != NULL, -EINVAL); + + if (duid != NULL) { + r = dhcp_validate_duid_len(duid_type, duid_len); + if (r < 0) + return r; + } + zero(client->client_id); client->client_id.type = 255; /* If IAID is not configured, generate it. */ @@ -342,22 +356,18 @@ int sd_dhcp_client_set_iaid_duid( } else client->client_id.ns.iaid = htobe32(iaid); - /* If DUID is not configured, generate DUID-EN. */ - if (duid_len == 0) { - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, - &duid_len); - if (r < 0) - return r; - } else { - r = dhcp_validate_duid_len(client->client_id.type, duid_len); - if (r < 0) - return r; + if (duid != NULL) { client->client_id.ns.duid.type = htobe16(duid_type); memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); - duid_len += sizeof(client->client_id.ns.duid.type); - } + len = sizeof(client->client_id.ns.duid.type) + duid_len; + } else if (duid_type == DUID_TYPE_EN) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + } else + return -EOPNOTSUPP; - client->client_id_len = sizeof(client->client_id.type) + duid_len + + client->client_id_len = sizeof(client->client_id.type) + len + sizeof(client->client_id.ns.iaid); if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index d3714b174f..4adb053a57 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -186,6 +186,11 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } +/** + * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid + * without further modification. Otherwise, if duid_type is supported, DUID + * is set based on that type. Otherwise, an error is returned. + */ int sd_dhcp6_client_set_duid( sd_dhcp6_client *client, uint16_t duid_type, @@ -194,16 +199,25 @@ int sd_dhcp6_client_set_duid( int r; assert_return(client, -EINVAL); + assert_return(duid_len == 0 || duid != NULL, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - if (duid_len > 0) { + if (duid != NULL) { r = dhcp_validate_duid_len(duid_type, duid_len); if (r < 0) return r; + } + + if (duid != NULL) { client->duid.type = htobe16(duid_type); memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); - } + client->duid_len = sizeof(client->duid.type) + duid_len; + } else if (duid_type == DUID_TYPE_EN) { + r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); + if (r < 0) + return r; + } else + return -EOPNOTSUPP; return 0; } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index d355aaa19c..0cb5781c71 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,7 +1037,7 @@ int manager_new(Manager **ret) { if (r < 0) return r; - m->duid_type = _DUID_TYPE_INVALID; + m->duid_type = DUID_TYPE_EN; *ret = m; m = NULL; -- cgit v1.2.3-54-g00ecf From 8341a5c381a72d504768fe296f8e30a324eeff77 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 28 Apr 2016 23:23:45 -0400 Subject: networkd: rework duid_{type,duid_type,duid,duid_len} setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate fields are replaced with a struct. Second second duid type field is removed. The first field was used to carry the result of DUIDType= configuration, and the second was either a copy of this, or contained the type extracted from DuidRawData. The semantics are changed so that the type specified in DUIDType is always used. DUIDRawData= no longer overrides the type setting. The networkd code is now more constrained than the sd-dhcp code: DUIDRawData cannot have 0 length, length 0 is treated the same as unsetting. Likewise, it is not possible to set a DUIDType=0. If it ever becomes necessary to set type=0 or a zero-length duid, the code can be changed to support that. Nevertheless, I think that's unlikely. This addresses #3127 § 1 and 3. v2: - rename DUID.duid, DUID.duid_len to DUID.raw_data, DUID.raw_data_len --- src/network/networkd-conf.c | 87 +++++--------------------------- src/network/networkd-conf.h | 29 ++++++++--- src/network/networkd-dhcp4.c | 24 ++++----- src/network/networkd-dhcp6.c | 16 +++--- src/network/networkd-gperf.gperf | 4 +- src/network/networkd-link.c | 35 +++++-------- src/network/networkd-manager.c | 2 +- src/network/networkd-network-gperf.gperf | 4 +- src/network/networkd-network.c | 2 +- src/network/networkd-network.h | 15 +++--- src/network/networkd.h | 14 ++--- 11 files changed, 88 insertions(+), 144 deletions(-) (limited to 'src') diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 70f0121d6d..1b2047f8f4 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -41,7 +41,7 @@ static const char* const duid_type_table[_DUID_TYPE_MAX] = { [DUID_TYPE_LLT] = "link-layer-time", [DUID_TYPE_EN] = "vendor", [DUID_TYPE_LL] = "link-layer", - [DUID_TYPE_UUID] = "uuid" + [DUID_TYPE_UUID] = "uuid", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type"); @@ -58,69 +58,29 @@ int config_parse_duid_rawdata( void *data, void *userdata) { - int r; - char *cbyte; - const char *pduid = rvalue; - Manager *m = userdata; - Network *n = userdata; - DUIDType duidtype; - uint16_t dhcp_duid_type = 0; - uint8_t dhcp_duid[MAX_DUID_LEN]; - size_t len, count = 0, duid_start_offset = 0, dhcp_duid_len = 0; + DUID *ret = data; + uint8_t raw_data[MAX_DUID_LEN]; + unsigned count = 0; assert(filename); assert(lvalue); assert(rvalue); - assert(userdata); + assert(ret); - duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type : n->duid_type; - - if (duidtype == _DUID_TYPE_INVALID) - duidtype = DUID_TYPE_RAW; - - switch (duidtype) { - - case DUID_TYPE_LLT: - /* RawData contains DUID-LLT link-layer address (offset 6) */ - duid_start_offset = 6; - break; - - case DUID_TYPE_EN: - /* RawData contains DUID-EN identifier (offset 4) */ - duid_start_offset = 4; - break; - - case DUID_TYPE_LL: - /* RawData contains DUID-LL link-layer address (offset 2) */ - duid_start_offset = 2; - break; - - case DUID_TYPE_UUID: - /* RawData specifies UUID (offset 0) - fall thru */ - - case DUID_TYPE_RAW: - /* First two bytes of RawData is DUID Type - fall thru */ - - default: - break; - } - - if (duidtype != DUID_TYPE_RAW) - dhcp_duid_type = (uint16_t) duidtype; - - /* RawData contains DUID in format " NN:NN:NN... " */ + /* RawData contains DUID in format "NN:NN:NN..." */ for (;;) { - int n1, n2; + int n1, n2, len, r; uint32_t byte; + char *cbyte; - r = extract_first_word(&pduid, &cbyte, ":", 0); + r = extract_first_word(&rvalue, &cbyte, ":", 0); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue); return 0; } if (r == 0) break; - if (duid_start_offset + dhcp_duid_len >= MAX_DUID_LEN) { + if (count >= MAX_DUID_LEN) { log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue); return 0; } @@ -142,30 +102,11 @@ int config_parse_duid_rawdata( } byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2; - - /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */ - if (duidtype == DUID_TYPE_RAW && count < 2) { - dhcp_duid_type |= (byte << (8 * (1 - count))); - count++; - continue; - } - - dhcp_duid[duid_start_offset + dhcp_duid_len] = byte; - dhcp_duid_len++; - } - - if (ltype == DUID_CONFIG_SOURCE_GLOBAL) { - m->duid_type = duidtype; - m->dhcp_duid_type = dhcp_duid_type; - m->dhcp_duid_len = dhcp_duid_len; - memcpy(&m->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); - } else { - /* DUID_CONFIG_SOURCE_NETWORK */ - n->duid_type = duidtype; - n->dhcp_duid_type = dhcp_duid_type; - n->dhcp_duid_len = dhcp_duid_len; - memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len); + raw_data[count++] = byte; } + assert_cc(sizeof(raw_data) == sizeof(ret->raw_data)); + memcpy(ret->raw_data, raw_data, count); + ret->raw_data_len = count; return 0; } diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h index 671e656d7b..c7bfb42a72 100644 --- a/src/network/networkd-conf.h +++ b/src/network/networkd-conf.h @@ -21,14 +21,29 @@ #include "networkd.h" -typedef enum DuidConfigSource { - DUID_CONFIG_SOURCE_GLOBAL = 0, - DUID_CONFIG_SOURCE_NETWORK, -} DuidConfigSource; - int manager_parse_config_file(Manager *m); const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); -int config_parse_duid_type(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_duid_rawdata(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_duid_type( + 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_duid_rawdata( + 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-dhcp4.c b/src/network/networkd-dhcp4.c index d31ea4d066..89926e8a7e 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -628,28 +628,24 @@ int dhcp4_configure(Link *link) { } switch (link->network->dhcp_client_identifier) { - case DHCP_CLIENT_ID_DUID: + case DHCP_CLIENT_ID_DUID: { /* If configured, apply user specified DUID and/or IAID */ - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + const DUID *duid = link_duid(link); + + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return r; 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)); + sizeof(link->mac)); if (r < 0) return r; break; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index b9c4b8962c..ccca4e9522 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -206,6 +206,7 @@ int dhcp6_request_address(Link *link) { int dhcp6_configure(Link *link) { sd_dhcp6_client *client = NULL; int r; + const DUID *duid; assert(link); @@ -234,16 +235,11 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp6_client_set_duid(client, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp6_client_set_duid(client, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + duid = link_duid(link); + r = sd_dhcp6_client_set_duid(client, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index afc71b4cb8..3fdfe74955 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -14,5 +14,5 @@ struct ConfigPerfItem; %struct-type %includes %% -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid_type) -DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_GLOBAL, offsetof(Manager, dhcp_duid) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid.type) +DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a88e4c34ed..c646af1f1a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2879,6 +2879,8 @@ int link_update(Link *link, sd_netlink_message *m) { } if (link->dhcp_client) { + const DUID *duid = link_duid(link); + r = sd_dhcp_client_set_mac(link->dhcp_client, (const uint8_t *) &link->mac, sizeof (link->mac), @@ -2886,23 +2888,18 @@ int link_update(Link *link, sd_netlink_message *m) { if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { + const DUID* duid = link_duid(link); + r = sd_dhcp6_client_set_mac(link->dhcp6_client, (const uint8_t *) &link->mac, sizeof (link->mac), @@ -2915,16 +2912,10 @@ int link_update(Link *link, sd_netlink_message *m) { if (r < 0) return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); - if (link->network->duid_type != _DUID_TYPE_INVALID) - r = sd_dhcp6_client_set_duid(link->dhcp6_client, - link->network->dhcp_duid_type, - link->network->dhcp_duid, - link->network->dhcp_duid_len); - else - r = sd_dhcp6_client_set_duid(link->dhcp6_client, - link->manager->dhcp_duid_type, - link->manager->dhcp_duid, - link->manager->dhcp_duid_len); + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 0cb5781c71..5dcd4df536 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,7 +1037,7 @@ int manager_new(Manager **ret) { if (r < 0) return r; - m->duid_type = DUID_TYPE_EN; + m->duid.type = DUID_TYPE_EN; *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 654d6a0316..6bf57cdf99 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -83,8 +83,8 @@ DHCP.Hostname, config_parse_hostname, DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid_type) -DHCP.DUIDRawData, config_parse_duid_rawdata, DUID_CONFIG_SOURCE_NETWORK, offsetof(Network, dhcp_duid) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type) +DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 2ebcdfa744..206c270e50 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -131,7 +131,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_accept_ra = -1; network->ipv6_dad_transmits = -1; network->ipv6_hop_limit = -1; - network->duid_type = _DUID_TYPE_INVALID; + network->duid.type = _DUID_TYPE_INVALID; network->proxy_arp = -1; r = config_parse(NULL, filename, file, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 9b8096f9ae..ff2414efdd 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -68,6 +68,14 @@ typedef enum LLDPMode { _LLDP_MODE_INVALID = -1, } LLDPMode; +typedef struct DUID { + /* Value of Type in [DHCP] section */ + DUIDType type; + + uint8_t raw_data_len; + uint8_t raw_data[MAX_DUID_LEN]; +} DUID; + typedef struct Manager Manager; struct Network { @@ -150,12 +158,7 @@ struct Network { struct ether_addr *mac; unsigned mtu; uint32_t iaid; - /* Value of Type in [DUID] section */ - DUIDType duid_type; - /* DUID type code - RFC 3315 */ - uint16_t dhcp_duid_type; - size_t dhcp_duid_len; - uint8_t dhcp_duid[MAX_DUID_LEN]; + DUID duid; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.h b/src/network/networkd.h index 39826a440d..26d9e7d6e0 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -74,14 +74,16 @@ struct Manager { usec_t network_dirs_ts_usec; - /* Value of Type in [DUID] section */ - DUIDType duid_type; - /* DUID type code - RFC 3315 */ - uint16_t dhcp_duid_type; - size_t dhcp_duid_len; - uint8_t dhcp_duid[MAX_DUID_LEN]; + DUID duid; }; +static inline const DUID* link_duid(const Link *link) { + if (link->network->duid.type != _DUID_TYPE_INVALID) + return &link->network->duid; + else + return &link->manager->duid; +} + extern const sd_bus_vtable manager_vtable[]; int manager_new(Manager **ret); -- cgit v1.2.3-54-g00ecf From c41aa4b4da19688a24c04fba2562b9b2816badd6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 29 Apr 2016 18:46:53 -0400 Subject: test-networkd-conf: add tests for the parsing functions --- .gitignore | 1 + Makefile.am | 7 ++++ src/network/test-networkd-conf.c | 89 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/network/test-networkd-conf.c (limited to 'src') diff --git a/.gitignore b/.gitignore index c7eb14452d..c17f79224b 100644 --- a/.gitignore +++ b/.gitignore @@ -235,6 +235,7 @@ /test-ndisc-rs /test-netlink /test-netlink-manual +/test-netword-conf /test-network /test-network-tables /test-ns diff --git a/Makefile.am b/Makefile.am index b323de55c6..a569d9e0ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5513,6 +5513,12 @@ networkctl_LDADD = \ dist_bashcompletion_data += \ shell-completion/bash/networkctl +test_networkd_conf_SOURCES = \ + src/network/test-networkd-conf.c + +test_networkd_conf_LDADD = \ + libnetworkd-core.la + test_network_SOURCES = \ src/network/test-network.c @@ -5538,6 +5544,7 @@ test_network_tables_LDADD += \ endif tests += \ + test-networkd-conf \ test-network \ test-network-tables diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c new file mode 100644 index 0000000000..8a62a2a567 --- /dev/null +++ b/src/network/test-networkd-conf.c @@ -0,0 +1,89 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "hexdecoct.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" + +#include "networkd-conf.h" +#include "networkd-network.h" + +static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected) { + DUIDType actual = 0; + int r; + + r = config_parse_duid_type("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL); + log_info_errno(r, "\"%s\" → %d (%m)", rvalue, actual); + assert_se(r == ret); + assert_se(expected == actual); +} + +static void test_config_parse_duid_type(void) { + test_config_parse_duid_type_one("", 0, 0); + test_config_parse_duid_type_one("link-layer-time", 0, DUID_TYPE_LLT); + test_config_parse_duid_type_one("vendor", 0, DUID_TYPE_EN); + test_config_parse_duid_type_one("link-layer", 0, DUID_TYPE_LL); + test_config_parse_duid_type_one("uuid", 0, DUID_TYPE_UUID); + test_config_parse_duid_type_one("foo", 0, 0); +} + +static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, const DUID* expected) { + DUID actual = {}; + int r; + + r = config_parse_duid_rawdata("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL); + log_info_errno(r, "\"%s\" → \"%s\" (%m)", + rvalue, strnull(hexmem(actual.raw_data, actual.raw_data_len))); + assert_se(r == ret); + if (expected) { + assert_se(actual.raw_data_len == expected->raw_data_len); + assert_se(memcmp(actual.raw_data, expected->raw_data, expected->raw_data_len) == 0); + } +} + +#define BYTES_0_128 "0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e:7f:80" + +#define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80} + +static void test_config_parse_duid_rawdata(void) { + test_config_parse_duid_rawdata_one("", 0, &(DUID){}); + test_config_parse_duid_rawdata_one("00:11:22:33:44:55:66:77", 0, + &(DUID){0, 8, {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}}); + test_config_parse_duid_rawdata_one("00:11:22:", 0, + &(DUID){0, 3, {0x00,0x11,0x22}}); + test_config_parse_duid_rawdata_one("000:11:22", 0, &(DUID){}); /* error, output is all zeros */ + test_config_parse_duid_rawdata_one("00:111:22", 0, &(DUID){}); + test_config_parse_duid_rawdata_one("0:1:2:3:4:5:6:7", 0, + &(DUID){0, 8, {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}}); + test_config_parse_duid_rawdata_one("11::", 0, &(DUID){0, 1, {0x11}}); /* FIXME: should this be an error? */ + test_config_parse_duid_rawdata_one("abcdef", 0, &(DUID){}); + test_config_parse_duid_rawdata_one(BYTES_0_128, 0, &(DUID){}); + test_config_parse_duid_rawdata_one(BYTES_0_128 + 2, 0, &(DUID){0, 128, BYTES_1_128}); +} + +int main(int argc, char **argv) { + log_parse_environment(); + log_open(); + + test_config_parse_duid_type(); + test_config_parse_duid_rawdata(); + + return 0; +} -- cgit v1.2.3-54-g00ecf From 7c285c74190e827c18a336f882cf4d9dcf4ee02a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 1 May 2016 00:59:49 -0400 Subject: network: get rid of DUID_TYPE_RAW It wasn't used for anything after the recent changes. --- src/libsystemd-network/dhcp-identifier.h | 1 - src/network/networkd-conf.c | 1 - 2 files changed, 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index dd0f926f90..1cc0f9fb71 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -26,7 +26,6 @@ #include "unaligned.h" typedef enum DUIDType { - DUID_TYPE_RAW = 0, DUID_TYPE_LLT = 1, DUID_TYPE_EN = 2, DUID_TYPE_LL = 3, diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 1b2047f8f4..6072c1e2de 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -37,7 +37,6 @@ int manager_parse_config_file(Manager *m) { } static const char* const duid_type_table[_DUID_TYPE_MAX] = { - [DUID_TYPE_RAW] = "raw", [DUID_TYPE_LLT] = "link-layer-time", [DUID_TYPE_EN] = "vendor", [DUID_TYPE_LL] = "link-layer", -- cgit v1.2.3-54-g00ecf From b8cc01a2dbaf63ecd08787226dc39b27242d3d03 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 3 May 2016 22:46:50 +0530 Subject: sd-netlink: fix sd_netlink_message_append_data Also remove the braces add_rtattr not required. --- src/libsystemd/sd-netlink/netlink-message.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index f56798674c..86d8dee867 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -207,11 +207,11 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da * and gives us too little data (so don't do that) */ padding = mempcpy(RTA_DATA(rta), data, data_length); - else { + + else /* if no data was passed, make sure we still initialize the padding note that we can have data_length > 0 (used by some containers) */ padding = RTA_DATA(rta); - } /* make sure also the padding at the end of the message is initialized */ padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding; @@ -343,7 +343,7 @@ int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, c assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - r = add_rtattr(m, type, &data, len); + r = add_rtattr(m, type, data, len); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From ec1bb279316bd262346d37554f930b69b63104bb Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 3 May 2016 22:47:48 +0530 Subject: sd-netlink: introduce route attribute set API Introduce 1. sd_rtnl_message_route_set_table to set table ID 2. sd_rtnl_message_route_set_family to set family Both required to configure route properties. --- src/libsystemd/sd-netlink/rtnl-message.c | 28 ++++++++++++++++++++++++++++ src/systemd/sd-netlink.h | 2 ++ 2 files changed, 30 insertions(+) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index f251536a89..09240c7b2a 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -111,6 +111,20 @@ int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) { return 0; } +int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + rtm->rtm_table = table; + + return 0; +} + int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) { struct rtmsg *rtm; @@ -126,6 +140,20 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) { return 0; } +int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + rtm->rtm_family = family; + + return 0; +} + int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) { struct rtmsg *rtm; diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index af7a797567..3ae110c080 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -137,8 +137,10 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope); int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags); +int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table); int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags); int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family); +int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family); int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol); int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope); int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos); -- cgit v1.2.3-54-g00ecf From c953b24c651afc47abed8ea63381501aa82eb2e8 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 3 May 2016 23:18:21 +0530 Subject: networkd: add support to set route table networkd: add support to set route table 1. add support to configure the table id. if id is less than 256 we can fit this in the header of route as netlink property is a char. But in kernel this proepty is a unsigned 32. Hence if greater that 256 add this as RTA_TABLE attribute. 2. we are not setting the address family now. Now set this property. --- man/systemd.network.xml | 8 ++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-route.c | 64 +++++++++++++++++++++++++++++++- src/network/networkd-route.h | 3 +- 4 files changed, 74 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 2a20748376..1ed7b67086 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -706,6 +706,14 @@ inet_pton3. + + Table=num + + The table identifier for the route (a number between 1 and 4294967295, or 0 to unset). + The table can be retrieved using ip route show table num. + + + diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 654d6a0316..471e300fde 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -71,6 +71,7 @@ Route.Source, config_parse_destination, Route.Metric, config_parse_route_priority, 0, 0 Route.Scope, config_parse_route_scope, 0, 0 Route.PreferredSource, config_parse_preferred_src, 0, 0 +Route.Table, config_parse_route_table, 0, 0 DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns) DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp) diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index bda2707e6d..01094b20bd 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -451,6 +451,10 @@ int route_configure(Route *route, Link *link, r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); + + r = sd_rtnl_message_route_set_family(req, route->family); + if (r < 0) + return log_error_errno(r, "Could not set route family: %m"); } if (route->dst_prefixlen) { @@ -494,7 +498,26 @@ int route_configure(Route *route, Link *link, r = sd_rtnl_message_route_set_flags(req, route->flags); if (r < 0) - return log_error_errno(r, "Colud not set flags: %m"); + return log_error_errno(r, "Could not set flags: %m"); + + if (route->table != RT_TABLE_DEFAULT) { + + if (route->table < 256) { + r = sd_rtnl_message_route_set_table(req, route->table); + if (r < 0) + return log_error_errno(r, "Could not set route table: %m"); + } else { + + r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC); + if (r < 0) + return log_error_errno(r, "Could not set route table: %m"); + + /* Table attribute to allow allow more than 256. */ + r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table)); + if (r < 0) + return log_error_errno(r, "Could not append RTA_TABLE attribute: %m"); + } + } r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) @@ -777,3 +800,42 @@ int config_parse_route_scope(const char *unit, return 0; } + +int config_parse_route_table(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) { + _cleanup_route_free_ Route *n = NULL; + Network *network = userdata; + uint32_t k; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, section_line, &n); + if (r < 0) + return r; + + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + + n->table = k; + + n = NULL; + + return 0; +} diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index a4a4bf2653..3ddeea96b7 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -37,7 +37,7 @@ struct Route { unsigned char protocol; /* RTPROT_* */ unsigned char tos; uint32_t priority; /* note that ip(8) calls this 'metric' */ - unsigned char table; + uint32_t table; unsigned char pref; unsigned flags; @@ -74,3 +74,4 @@ int config_parse_preferred_src(const char *unit, const char *filename, unsigned int config_parse_destination(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_route_priority(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_route_scope(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_route_table(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); -- cgit v1.2.3-54-g00ecf From c29f959b4445dbbecc54c04d9a2a2f68da8bc262 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 3 May 2016 13:46:40 -0400 Subject: Revert "nspawn: explicitly remove veth links after use (#3111)" This reverts commit d2773e59de3dd970d861e9f996bc48de20ef4314. Merge got squashed by mistake. --- src/libsystemd/sd-netlink/rtnl-message.c | 1 + src/nspawn/nspawn-network.c | 47 -------------------------------- src/nspawn/nspawn-network.h | 2 -- src/nspawn/nspawn.c | 2 -- 4 files changed, 1 insertion(+), 51 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index f251536a89..255526bf32 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -402,6 +402,7 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret, int r; assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); + assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL); assert_return(ret, -EINVAL); r = message_new(rtnl, ret, nlmsg_type); diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index f2b7e4dd79..74a0ae865b 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -538,50 +538,3 @@ int veth_extra_parse(char ***l, const char *p) { a = b = NULL; return 0; } - -static int remove_one_veth_link(sd_netlink *rtnl, const char *name) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - int r; - - if (isempty(name)) - return 0; - - r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0); - if (r < 0) - return log_error_errno(r, "Failed to allocate netlink message: %m"); - - r = sd_netlink_message_append_string(m, IFLA_IFNAME, name); - if (r < 0) - return log_error_errno(r, "Failed to add netlink interface name: %m"); - - r = sd_netlink_call(rtnl, m, 0, NULL); - if (r == -ENODEV) /* Already gone */ - return 0; - if (r < 0) - return log_error_errno(r, "Failed to remove veth interface %s: %m", name); - - return 1; -} - -int remove_veth_links(const char *primary, char **pairs) { - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - char **a, **b; - int r; - - /* In some cases the kernel might pin the veth links between host and container even after the namespace - * died. Hence, let's better remove them explicitly too. */ - - if (isempty(primary) && strv_isempty(pairs)) - return 0; - - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); - - remove_one_veth_link(rtnl, primary); - - STRV_FOREACH_PAIR(a, b, pairs) - remove_one_veth_link(rtnl, *a); - - return 0; -} diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index c5036ab470..9ab1606d1c 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -34,5 +34,3 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces); int move_network_interfaces(pid_t pid, char **ifaces); int veth_extra_parse(char ***l, const char *p); - -int remove_veth_links(const char *primary, char **pairs); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3fc6cc955c..18fb019550 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3981,7 +3981,6 @@ int main(int argc, char *argv[]) { } expose_port_flush(arg_expose_ports, &exposed); - (void) remove_veth_links(veth_name, arg_network_veth_extra); } finish: @@ -4014,7 +4013,6 @@ finish: } expose_port_flush(arg_expose_ports, &exposed); - (void) remove_veth_links(veth_name, arg_network_veth_extra); free(arg_directory); free(arg_template); -- cgit v1.2.3-54-g00ecf From 6254be5def638194f21c2f47461d5acaa2a97b7f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 3 May 2016 14:08:16 -0400 Subject: Revert "test-dnssec: drop unused variable" This reverts commit 0bed31c1038c439cc5956fb44017ba28e503095b. --- src/resolve/test-dnssec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index b3018e8239..155be9946f 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -230,6 +230,7 @@ static void test_dnssec_verify_rrset2(void) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; DnssecResult result; + int r; nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); assert_se(nsec); -- cgit v1.2.3-54-g00ecf From d43bbb52de220e6008a649b128fe32da995b5e1e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 3 May 2016 14:08:23 -0400 Subject: Revert "Do not report masked units as changed (#2921)" This reverts commit 6d10d308c6cd16528ef58fa4f5822aef936862d3. It got squashed by mistake. --- src/core/load-fragment.c | 8 +- src/core/unit.c | 62 ++++++----- src/resolve/test-dnssec.c | 274 +++++++++++++++++++++++----------------------- 3 files changed, 171 insertions(+), 173 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 1a8c03904c..67867dfbe9 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3630,12 +3630,10 @@ static int load_from_path(Unit *u, const char *path) { if (fstat(fileno(f), &st) < 0) return -errno; - if (null_or_empty(&st)) { + if (null_or_empty(&st)) u->load_state = UNIT_MASKED; - u->fragment_mtime = 0; - } else { + else { u->load_state = UNIT_LOADED; - u->fragment_mtime = timespec_load(&st.st_mtim); /* Now, parse the file contents */ r = config_parse(u->id, filename, f, @@ -3650,6 +3648,8 @@ static int load_from_path(Unit *u, const char *path) { u->fragment_path = filename; filename = NULL; + u->fragment_mtime = timespec_load(&st.st_mtim); + if (u->source_path) { if (stat(u->source_path, &st) >= 0) u->source_mtime = timespec_load(&st.st_mtim); diff --git a/src/core/unit.c b/src/core/unit.c index 4ace6b075b..5b8b0130bd 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2951,36 +2951,34 @@ int unit_coldplug(Unit *u) { return 0; } -static bool fragment_mtime_changed(const char *path, usec_t mtime) { - struct stat st; - - if (!path) - return false; - - if (stat(path, &st) < 0) - /* What, cannot access this anymore? */ - return true; - - if (mtime > 0) - /* For non-empty files check the mtime */ - return timespec_load(&st.st_mtim) != mtime; - else if (!null_or_empty(&st)) - /* For masked files check if they are still so */ - return true; - - return false; -} - bool unit_need_daemon_reload(Unit *u) { _cleanup_strv_free_ char **t = NULL; char **path; + struct stat st; unsigned loaded_cnt, current_cnt; assert(u); - if (fragment_mtime_changed(u->fragment_path, u->fragment_mtime) || - fragment_mtime_changed(u->source_path, u->source_mtime)) - return true; + if (u->fragment_path) { + zero(st); + if (stat(u->fragment_path, &st) < 0) + /* What, cannot access this anymore? */ + return true; + + if (u->fragment_mtime > 0 && + timespec_load(&st.st_mtim) != u->fragment_mtime) + return true; + } + + if (u->source_path) { + zero(st); + if (stat(u->source_path, &st) < 0) + return true; + + if (u->source_mtime > 0 && + timespec_load(&st.st_mtim) != u->source_mtime) + return true; + } (void) unit_find_dropin_paths(u, &t); loaded_cnt = strv_length(t); @@ -2991,15 +2989,21 @@ bool unit_need_daemon_reload(Unit *u) { return false; if (strv_overlap(u->dropin_paths, t)) { - STRV_FOREACH(path, u->dropin_paths) - if (fragment_mtime_changed(*path, u->dropin_mtime)) + STRV_FOREACH(path, u->dropin_paths) { + zero(st); + if (stat(*path, &st) < 0) return true; - return false; - } - } + if (u->dropin_mtime > 0 && + timespec_load(&st.st_mtim) > u->dropin_mtime) + return true; + } - return true; + return false; + } else + return true; + } else + return true; } void unit_reset_failed(Unit *u) { diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index 155be9946f..c9b5ffa62b 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -27,89 +27,77 @@ #include "string-util.h" #include "hexdecoct.h" -static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { - char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; - - assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); - if (r < 0) - return; - - assert_se(streq(canonicalized, canonical)); -} - -static void test_dnssec_canonicalize(void) { - test_dnssec_canonicalize_one("", ".", 1); - test_dnssec_canonicalize_one(".", ".", 1); - test_dnssec_canonicalize_one("foo", "foo.", 4); - test_dnssec_canonicalize_one("foo.", "foo.", 4); - test_dnssec_canonicalize_one("FOO.", "foo.", 4); - test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); - test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); -} - -#ifdef HAVE_GCRYPT - -static void test_dnssec_verify_dns_key(void) { +static void test_dnssec_verify_rrset2(void) { - static const uint8_t ds1_fprint[] = { - 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, - 0x80, 0x67, 0x14, 0x01, - }; - static const uint8_t ds2_fprint[] = { - 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, - 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, + static const uint8_t signature_blob[] = { + 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, + 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, + 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca, + 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2, + 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda, + 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27, + 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50, + 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22, }; + static const uint8_t dnskey_blob[] = { - 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, - 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, - 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, - 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, - 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, - 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, - 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, - 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, - 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, - 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, - 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, - 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, - 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, - 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, - 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, - 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, - 0xe7, 0xea, 0x77, 0x03, + 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea, + 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3, + 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07, + 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5, + 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7, + 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56, + 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e, + 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49, + 0x74, 0x62, 0xfe, 0xd7, }; - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnssecResult result; - /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ - ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); - assert_se(ds1); + nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); + assert_se(nsec); - ds1->ds.key_tag = 47857; - ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; - ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; - ds1->ds.digest_size = sizeof(ds1_fprint); - ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); - assert_se(ds1->ds.digest); + nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov"); + assert_se(nsec->nsec.next_domain_name); - log_info("DS1: %s", strna(dns_resource_record_to_string(ds1))); + nsec->nsec.types = bitmap_new(); + assert_se(nsec->nsec.types); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0); + assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0); - ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); - assert_se(ds2); + log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec))); - ds2->ds.key_tag = 47857; - ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; - ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; - ds2->ds.digest_size = sizeof(ds2_fprint); - ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); - assert_se(ds2->ds.digest); + rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); + assert_se(rrsig); - log_info("DS2: %s", strna(dns_resource_record_to_string(ds2))); + rrsig->rrsig.type_covered = DNS_TYPE_NSEC; + rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; + rrsig->rrsig.labels = 2; + rrsig->rrsig.original_ttl = 300; + rrsig->rrsig.expiration = 0x5689002f; + rrsig->rrsig.inception = 0x56617230; + rrsig->rrsig.key_tag = 30390; + rrsig->rrsig.signer = strdup("Nasa.Gov."); + assert_se(rrsig->rrsig.signer); + rrsig->rrsig.signature_size = sizeof(signature_blob); + rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); + assert_se(rrsig->rrsig.signature); - dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); + log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); assert_se(dnskey); - dnskey->dnskey.flags = 257; + dnskey->dnskey.flags = 256; dnskey->dnskey.protocol = 3; dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; dnskey->dnskey.key_size = sizeof(dnskey_blob); @@ -119,8 +107,16 @@ static void test_dnssec_verify_dns_key(void) { log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); - assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0); - assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); + assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0); + assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); + + answer = dns_answer_new(1); + assert_se(answer); + assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + + /* Validate the RR as it if was 2015-12-11 today */ + assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); + assert_se(result == DNSSEC_VALIDATED); } static void test_dnssec_verify_rrset(void) { @@ -202,78 +198,67 @@ static void test_dnssec_verify_rrset(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_verify_rrset2(void) { +static void test_dnssec_verify_dns_key(void) { - static const uint8_t signature_blob[] = { - 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, - 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, - 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca, - 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2, - 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda, - 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27, - 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50, - 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22, + static const uint8_t ds1_fprint[] = { + 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, + 0x80, 0x67, 0x14, 0x01, + }; + static const uint8_t ds2_fprint[] = { + 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, + 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, }; - static const uint8_t dnskey_blob[] = { - 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea, - 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3, - 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07, - 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5, - 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7, - 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56, - 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e, - 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49, - 0x74, 0x62, 0xfe, 0xd7, + 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, + 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, + 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, + 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, + 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, + 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, + 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, + 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, + 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, + 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, + 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, + 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, + 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, + 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, + 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, + 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, + 0xe7, 0xea, 0x77, 0x03, }; - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - DnssecResult result; - int r; - - nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); - assert_se(nsec); + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; - nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov"); - assert_se(nsec->nsec.next_domain_name); + /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ + ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); + assert_se(ds1); - nsec->nsec.types = bitmap_new(); - assert_se(nsec->nsec.types); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0); - assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0); - assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0); + ds1->ds.key_tag = 47857; + ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; + ds1->ds.digest_size = sizeof(ds1_fprint); + ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); + assert_se(ds1->ds.digest); - log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec))); + log_info("DS1: %s", strna(dns_resource_record_to_string(ds1))); - rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); - assert_se(rrsig); + ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); + assert_se(ds2); - rrsig->rrsig.type_covered = DNS_TYPE_NSEC; - rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; - rrsig->rrsig.labels = 2; - rrsig->rrsig.original_ttl = 300; - rrsig->rrsig.expiration = 0x5689002f; - rrsig->rrsig.inception = 0x56617230; - rrsig->rrsig.key_tag = 30390; - rrsig->rrsig.signer = strdup("Nasa.Gov."); - assert_se(rrsig->rrsig.signer); - rrsig->rrsig.signature_size = sizeof(signature_blob); - rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); - assert_se(rrsig->rrsig.signature); + ds2->ds.key_tag = 47857; + ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; + ds2->ds.digest_size = sizeof(ds2_fprint); + ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); + assert_se(ds2->ds.digest); - log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + log_info("DS2: %s", strna(dns_resource_record_to_string(ds2))); - dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); assert_se(dnskey); - dnskey->dnskey.flags = 256; + dnskey->dnskey.flags = 257; dnskey->dnskey.protocol = 3; dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; dnskey->dnskey.key_size = sizeof(dnskey_blob); @@ -283,16 +268,28 @@ static void test_dnssec_verify_rrset2(void) { log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); - assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0); - assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0); + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); +} - answer = dns_answer_new(1); - assert_se(answer); - assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); +static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { + char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; - /* Validate the RR as it if was 2015-12-11 today */ - assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); - assert_se(result == DNSSEC_VALIDATED); + assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); + if (r < 0) + return; + + assert_se(streq(canonicalized, canonical)); +} + +static void test_dnssec_canonicalize(void) { + test_dnssec_canonicalize_one("", ".", 1); + test_dnssec_canonicalize_one(".", ".", 1); + test_dnssec_canonicalize_one("foo", "foo.", 4); + test_dnssec_canonicalize_one("foo.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); + test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); } static void test_dnssec_nsec3_hash(void) { @@ -327,12 +324,9 @@ static void test_dnssec_nsec3_hash(void) { assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0); } -#endif - int main(int argc, char*argv[]) { test_dnssec_canonicalize(); - #ifdef HAVE_GCRYPT test_dnssec_verify_dns_key(); test_dnssec_verify_rrset(); -- cgit v1.2.3-54-g00ecf From 9a0289a43967082e2503eca3e9cc5a9455fa0f9d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Apr 2016 13:51:28 +0200 Subject: test-dnssec: drop unused variable (zjs: the tree is now back to 0b2abe0f034f7f2d8654adb11b516d1090ec9a9c.) --- src/resolve/test-dnssec.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index 155be9946f..b3018e8239 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -230,7 +230,6 @@ static void test_dnssec_verify_rrset2(void) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; DnssecResult result; - int r; nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); assert_se(nsec); -- cgit v1.2.3-54-g00ecf From 8965d9f8b93b467c8827201b8cd55a762e406801 Mon Sep 17 00:00:00 2001 From: Alex Crawford Date: Wed, 27 Apr 2016 23:59:20 -0700 Subject: install: cache the presets before evaluating The previous implementation traversed the various config directories, walking the preset files and parsing each line to determine if a service should be enabled or disabled. It did this for every service which resulted in many more file operations than neccessary. This approach parses each of the preset entries into an array which is then used to check if each service should be enabled or disabled. --- src/shared/install.c | 146 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 121 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 1ea7e4674f..d2799bf0df 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -66,6 +66,35 @@ typedef struct { OrderedHashmap *have_processed; } InstallContext; +typedef enum { + PRESET_UNKNOWN, + PRESET_ENABLE, + PRESET_DISABLE, +} PresetAction; + +typedef struct { + char *pattern; + PresetAction action; +} PresetRule; + +typedef struct { + PresetRule *rules; + size_t n_rules; +} Presets; + +static inline void presets_freep(Presets *p) { + size_t i; + + if (!p) + return; + + for (i = 0; i < p->n_rules; i++) + free(p->rules[i].pattern); + + free(p->rules); + p->n_rules = 0; +} + static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret); static int in_search_path(const LookupPaths *p, const char *path) { @@ -2367,17 +2396,16 @@ int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char * return 1; } -int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { +static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) { + _cleanup_(presets_freep) Presets ps = {}; + size_t n_allocated = 0; _cleanup_strv_free_ char **files = NULL; char **p; int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - if (!unit_name_is_valid(name, UNIT_NAME_ANY)) - return -EINVAL; + assert(presets); if (scope == UNIT_FILE_SYSTEM) r = conf_files_list(&files, ".preset", root_dir, @@ -2394,8 +2422,11 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char "/usr/local/lib/systemd/user-preset", "/usr/lib/systemd/user-preset", NULL); - else - return 1; /* Default is "enable" */ + else { + *presets = (Presets){}; + + return 0; + } if (r < 0) return r; @@ -2414,6 +2445,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char } FOREACH_LINE(line, f, return -errno) { + PresetRule rule = {}; const char *parameter; char *l; @@ -2427,21 +2459,37 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char parameter = first_word(l, "enable"); if (parameter) { - if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { - log_debug("Preset file says enable %s.", name); - return 1; - } + char *pattern; - continue; + pattern = strdup(parameter); + if (!pattern) + return -ENOMEM; + + rule = (PresetRule) { + .pattern = pattern, + .action = PRESET_ENABLE, + }; } parameter = first_word(l, "disable"); if (parameter) { - if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { - log_debug("Preset file says disable %s.", name); - return 0; - } + char *pattern; + pattern = strdup(parameter); + if (!pattern) + return -ENOMEM; + + rule = (PresetRule) { + .pattern = pattern, + .action = PRESET_DISABLE, + }; + } + + if (rule.action) { + if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1)) + return -ENOMEM; + + ps.rules[ps.n_rules++] = rule; continue; } @@ -2449,9 +2497,49 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char } } - /* Default is "enable" */ - log_debug("Preset file doesn't say anything about %s, enabling.", name); - return 1; + *presets = ps; + ps = (Presets){}; + + return 0; +} + +static int query_presets(const char *name, const Presets presets) { + PresetAction action = PRESET_UNKNOWN; + size_t i; + + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + + for (i = 0; i < presets.n_rules; i++) + if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) { + action = presets.rules[i].action; + break; + } + + switch (action) { + case PRESET_UNKNOWN: + log_debug("Preset files don't specify rule for %s. Enabling.", name); + return 1; + case PRESET_ENABLE: + log_debug("Preset files say enable %s.", name); + return 1; + case PRESET_DISABLE: + log_debug("Preset files say disable %s.", name); + return 0; + default: + assert_not_reached("invalid preset action"); + } +} + +int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { + _cleanup_(presets_freep) Presets presets = {}; + int r; + + r = read_presets(scope, root_dir, &presets); + if (r < 0) + return r; + + return query_presets(name, presets); } static int execute_preset( @@ -2507,6 +2595,7 @@ static int preset_prepare_one( LookupPaths *paths, UnitFilePresetMode mode, const char *name, + Presets presets, UnitFileChange **changes, unsigned *n_changes) { @@ -2517,7 +2606,7 @@ static int preset_prepare_one( install_info_find(minus, name)) return 0; - r = unit_file_query_preset(scope, paths->root_dir, name); + r = query_presets(name, presets); if (r < 0) return r; @@ -2547,6 +2636,7 @@ int unit_file_preset( _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(presets_freep) Presets presets = {}; const char *config_path; char **i; int r; @@ -2561,11 +2651,12 @@ int unit_file_preset( config_path = runtime ? paths.runtime_config : paths.persistent_config; - STRV_FOREACH(i, files) { - if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) - return -EINVAL; + r = read_presets(scope, root_dir, &presets); + if (r < 0) + return r; - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, changes, n_changes); + STRV_FOREACH(i, files) { + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, presets, changes, n_changes); if (r < 0) return r; } @@ -2584,6 +2675,7 @@ int unit_file_preset_all( _cleanup_(install_context_done) InstallContext plus = {}, minus = {}; _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(presets_freep) Presets presets = {}; const char *config_path = NULL; char **i; int r; @@ -2598,6 +2690,10 @@ int unit_file_preset_all( config_path = runtime ? paths.runtime_config : paths.persistent_config; + r = read_presets(scope, root_dir, &presets); + if (r < 0) + return r; + STRV_FOREACH(i, paths.search_path) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -2621,7 +2717,7 @@ int unit_file_preset_all( continue; /* we don't pass changes[] in, because we want to handle errors on our own */ - r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, NULL, 0); + r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, presets, NULL, 0); if (r == -ERFKILL) r = unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, de->d_name, NULL); -- cgit v1.2.3-54-g00ecf From b5834a0b38c1aa7d6975d76971cd75c07455d129 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 4 May 2016 01:24:26 +0530 Subject: networkd: Add support to configure IPv6 preferred lifetime (#3102) Closes #2166. We only allow 0, infinity and forever. infinity and forever is same. --- man/systemd.network.xml | 12 ++++++++ src/network/networkd-address.c | 48 ++++++++++++++++++++++++++++++++ src/network/networkd-address.h | 1 + src/network/networkd-network-gperf.gperf | 1 + 4 files changed, 62 insertions(+) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 1ed7b67086..5e287faa6e 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -652,6 +652,18 @@ An address label. + + PreferredLifetime= + + Allows the default "preferred lifetime" of the address to be overridden. + Only three settings are accepted: forever or infinity + which is the default and means that the address never expires, and 0 which means + that the address is considered immediately "expired" and will not be used, + unless explicitly requested. A setting of PreferredLifetime=0 is useful for + addresses which are added to be used only by a specific application, + which is then configured to use them explicitly. + + diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 429319da6b..8b52a1f742 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -774,6 +774,54 @@ int config_parse_label(const char *unit, return 0; } +int config_parse_lifetime(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_address_free_ Address *n = NULL; + unsigned k; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = address_new_static(network, section_line, &n); + if (r < 0) + return r; + + if (STR_IN_SET(rvalue, "forever", "infinity")) { + n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME; + n = NULL; + + return 0; + } + + r = safe_atou(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue); + return 0; + } + + if (k != 0) + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k); + else { + n->cinfo.ifa_prefered = k; + n = NULL; + } + + return 0; +} + bool address_is_ready(const Address *a) { assert(a); diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 338f6eb9a2..3c81978fb1 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -74,3 +74,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); int config_parse_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); int config_parse_broadcast(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_label(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_lifetime(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-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 471e300fde..550b5e5240 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -65,6 +65,7 @@ Address.Address, config_parse_address, Address.Peer, config_parse_address, 0, 0 Address.Broadcast, config_parse_broadcast, 0, 0 Address.Label, config_parse_label, 0, 0 +Address.PreferredLifetime, config_parse_lifetime, 0, 0 Route.Gateway, config_parse_gateway, 0, 0 Route.Destination, config_parse_destination, 0, 0 Route.Source, config_parse_destination, 0, 0 -- cgit v1.2.3-54-g00ecf From fa394301e2119ab594b266346cdc114a67af98d9 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 3 May 2016 22:29:03 +0200 Subject: udev: fix build with DEBUG=1 Alternatively, this could perhaps be removed since it was broken for a long time and noone seemed to care. But it was helpful for me today. --- src/udev/udev-rules.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 475856db6f..26fa52cf6c 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -329,8 +329,8 @@ static void dump_token(struct udev_rules *rules, struct token *token) { enum token_type type = token->type; enum operation_type op = token->key.op; enum string_glob_type glob = token->key.glob; - const char *value = str(rules, token->key.value_off); - const char *attr = &rules->buf[token->key.attr_off]; + const char *value = rules_str(rules, token->key.value_off); + const char *attr = &rules->strbuf->buf[token->key.attr_off]; switch (type) { case TK_RULE: @@ -340,9 +340,9 @@ static void dump_token(struct udev_rules *rules, struct token *token) { unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token); log_debug("* RULE %s:%u, token: %u, count: %u, label: '%s'", - &rules->buf[token->rule.filename_off], token->rule.filename_line, + &rules->strbuf->buf[token->rule.filename_off], token->rule.filename_line, idx, token->rule.token_count, - &rules->buf[token->rule.label_off]); + &rules->strbuf->buf[token->rule.label_off]); break; } case TK_M_ACTION: @@ -439,11 +439,11 @@ static void dump_token(struct udev_rules *rules, struct token *token) { static void dump_rules(struct udev_rules *rules) { unsigned int i; - log_debug("dumping %u (%zu bytes) tokens, %u (%zu bytes) strings", + log_debug("dumping %u (%zu bytes) tokens, %zu (%zu bytes) strings", rules->token_cur, rules->token_cur * sizeof(struct token), - rules->buf_count, - rules->buf_cur); + rules->strbuf->nodes_count, + rules->strbuf->len); for (i = 0; i < rules->token_cur; i++) dump_token(rules, &rules->tokens[i]); } -- cgit v1.2.3-54-g00ecf From c45606eb95a7171b0dc801e91d35034957ad5e9e Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 3 May 2016 22:15:49 +0200 Subject: strbuf: set the proper character when creating new nodes Commit 82501b3fc added an early break when a terminal node is found to incorrect place -- before setting c. This caused trie to be built that does not correspond to what it points to in buffer, causing incorrect deduplications: # cat /etc/udev/rules.d/99-bug.rules ENV{FOO}=="0" ENV{xx0}=="BAR" ENV{BAZ}=="00" # udevadm test * RULE /etc/udev/rules.d/99-bug.rules:1, token: 0, count: 2, label: '' M ENV match 'FOO' '0'(plain) * RULE /etc/udev/rules.d/99-bug.rules:2, token: 2, count: 2, label: '' M ENV match 'xx0' 'BAR'(plain) * RULE /etc/udev/rules.d/99-bug.rules:3, token: 4, count: 2, label: '' M ENV match 'BAZ' 'x0'(plain) * END The addition of "xx0" following "0" will cause a trie like this to be created: c=\0 c=0 "0" c=0 "xx0" <-- note the c is incorrect here, causing "00" to be c=O "FOO" deduplicated to it c=R "BAR" This in effect caused the usb_modeswitch rule for Huawei modems to never match and this never be switched to serial mode from mass storage. --- src/basic/strbuf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index 797f00cf71..4bef87d3c2 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -156,12 +156,13 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { return off; } + c = s[len - 1 - depth]; + /* bsearch is not allowed on a NULL sequence */ if (node->children_count == 0) break; /* lookup child node */ - c = s[len - 1 - depth]; search.c = c; child = bsearch(&search, node->children, node->children_count, sizeof(struct strbuf_child_entry), -- cgit v1.2.3-54-g00ecf From f8e2f4d6a0c6bcb5a03abe580d657b932cdb9798 Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Wed, 4 May 2016 11:26:17 +0200 Subject: treewide: fix typos (#3187) --- src/basic/fileio.c | 2 +- src/journal/journal-file.c | 2 +- src/journal/sd-journal.c | 2 +- src/resolve/resolved-dns-query.c | 2 +- src/shared/machine-image.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 2a9b6e46ad..29f5374222 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1337,7 +1337,7 @@ int link_tmpfile(int fd, const char *path, const char *target) { * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported * on the directory, and renameat2() is used instead. * - * Note that in both cases we will not replace existing files. This is because linkat() dos not support this + * Note that in both cases we will not replace existing files. This is because linkat() does not support this * operation currently (renameat2() does), and there is no nice way to emulate this. */ if (path) { diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index ec50333c2c..7504326bff 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -3160,7 +3160,7 @@ int journal_file_open( goto fail; } - /* The file is opened now successfully, thus we take possesion of any passed in fd. */ + /* The file is opened now successfully, thus we take possession of any passed in fd. */ f->close_fd = true; *ret = f; diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 27c1dd346f..1cea68ad42 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1942,7 +1942,7 @@ _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fd return 0; fail: - /* If we fail, make sure we don't take possession of the files we managed to make use of successfuly, and they + /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they * remain open */ ORDERED_HASHMAP_FOREACH(f, j->files, iterator) f->close_fd = false; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 706f8c14ed..ea04e58d61 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -810,7 +810,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { switch (t->state) { case DNS_TRANSACTION_SUCCESS: { - /* We found a successfuly reply, merge it into the answer */ + /* We found a successfully reply, merge it into the answer */ r = dns_answer_extend(&q->answer, t->answer); if (r < 0) goto fail; diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 66f58ecd92..529d89ee2a 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -487,7 +487,7 @@ int image_rename(Image *i, const char *new_name) { /* Make sure nobody takes the new name, between the time we * checked it is currently unused in all search paths, and the - * time we take possesion of it */ + * time we take possession of it */ r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock); if (r < 0) return r; @@ -588,7 +588,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) { /* Make sure nobody takes the new name, between the time we * checked it is currently unused in all search paths, and the - * time we take possesion of it */ + * time we take possession of it */ r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From 096a4d53dcafb1181193d0c1880a8204733fa6ab Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 4 May 2016 17:43:13 -0400 Subject: core: fix segfault on "systemctl --set-property UNIT BlockIODeviceWeight=WEIGHT" bus_append_unit_property_assignment() was missing an argument for sd_bus_message_append() when processing BlockIODeviceWeight leading to segfault. Fix it. Signed-off-by: Tejun Heo --- src/shared/bus-unit-util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index e36a7741a8..ee388b82db 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -331,7 +331,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen log_error("Failed to parse %s value %s.", field, weight); return -EINVAL; } - r = sd_bus_message_append(m, "v", "a(st)", path, u); + r = sd_bus_message_append(m, "v", "a(st)", 1, path, u); } } else if (streq(field, "Nice")) { -- cgit v1.2.3-54-g00ecf From 37818090c99871577c0cfd8171901eb7e2050be9 Mon Sep 17 00:00:00 2001 From: "Thomas H. P. Andersen" Date: Thu, 5 May 2016 11:15:46 +0200 Subject: Trivial network cleanup (#3196) * gitignore: typo fix for test-networkd-conf * networkd: fix double include --- .gitignore | 2 +- src/network/networkd.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/.gitignore b/.gitignore index c17f79224b..091b400182 100644 --- a/.gitignore +++ b/.gitignore @@ -235,7 +235,7 @@ /test-ndisc-rs /test-netlink /test-netlink-manual -/test-netword-conf +/test-networkd-conf /test-network /test-network-tables /test-ns diff --git a/src/network/networkd.h b/src/network/networkd.h index 26d9e7d6e0..ab512f0d08 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -41,7 +41,6 @@ #include "networkd-netdev-tuntap.h" #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" -#include "networkd-netdev-vlan.h" #include "networkd-netdev-vxlan.h" #include "networkd-network.h" #include "networkd-util.h" -- cgit v1.2.3-54-g00ecf From d8fdc62037b5b0a9fd603ad5efd6b49f956f86b5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 May 2016 20:43:23 +0200 Subject: core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent notification dbus-daemon currently uses a backlog of 30 on its D-bus system bus socket. On overloaded systems this means that only 30 connections may be queued without dbus-daemon processing them before further connection attempts fail. Our cgroups-agent binary so far used D-Bus for its messaging, and hitting this limit hence may result in us losing cgroup empty messages. This patch adds a seperate cgroup agent socket of type AF_UNIX/SOCK_DGRAM. Since sockets of these types need no connection set up, no listen() backlog applies. Our cgroup-agent binary will hence simply block as long as it can't enqueue its datagram message, so that we won't lose cgroup empty messages as likely anymore. This also rearranges the ordering of the processing of SIGCHLD signals, service notification messages (sd_notify()...) and the two types of cgroup notifications (inotify for the unified hierarchy support, and agent for the classic hierarchy support). We now always process events for these in the following order: 1. service notification messages (SD_EVENT_PRIORITY_NORMAL-7) 2. SIGCHLD signals (SD_EVENT_PRIORITY_NORMAL-6) 3. cgroup inotify and cgroup agent (SD_EVENT_PRIORITY_NORMAL-5) This is because when receiving SIGCHLD we invalidate PID information, which we need to process the service notification messages which are bound to PIDs. Hence the order between the first two items. And we want to process SIGCHLD metadata to detect whether a service is gone, before using cgroup notifications, to decide when a service is gone, since the former carries more useful metadata. Related to this: https://bugs.freedesktop.org/show_bug.cgi?id=95264 https://github.com/systemd/systemd/issues/1961 --- src/cgroups-agent/cgroups-agent.c | 48 ++++++------ src/core/cgroup.c | 6 +- src/core/dbus.c | 73 +++++++----------- src/core/dbus.h | 2 + src/core/manager.c | 155 +++++++++++++++++++++++++++++++++++--- src/core/manager.h | 3 + 6 files changed, 209 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index aadfba0707..333ce110d3 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -18,15 +18,22 @@ ***/ #include +#include -#include "sd-bus.h" - -#include "bus-util.h" +#include "fd-util.h" #include "log.h" +#include "socket-util.h" int main(int argc, char *argv[]) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - int r; + + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/cgroups-agent", + }; + + _cleanup_close_ int fd = -1; + ssize_t n; + size_t l; if (argc != 2) { log_error("Incorrect number of arguments."); @@ -37,27 +44,22 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - /* We send this event to the private D-Bus socket and then the - * system instance will forward this to the system bus. We do - * this to avoid an activation loop when we start dbus when we - * are called when the dbus service is shut down. */ - - r = bus_connect_system_systemd(&bus); - if (r < 0) { - /* If we couldn't connect we assume this was triggered - * while systemd got restarted/transitioned from - * initrd to the system, so let's ignore this */ - log_debug_errno(r, "Failed to get D-Bus connection: %m"); + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); + if (fd < 0) { + log_debug_errno(errno, "Failed to allocate socket: %m"); + return EXIT_FAILURE; + } + + l = strlen(argv[1]); + + n = sendto(fd, argv[1], l, 0, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + if (n < 0) { + log_debug_errno(errno, "Failed to send cgroups agent message: %m"); return EXIT_FAILURE; } - r = sd_bus_emit_signal(bus, - "/org/freedesktop/systemd1/agent", - "org.freedesktop.systemd1.Agent", - "Released", - "s", argv[1]); - if (r < 0) { - log_debug_errno(r, "Failed to send signal message on private connection: %m"); + if ((size_t) n != l) { + log_debug("Datagram size mismatch"); return EXIT_FAILURE; } diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 25cc6962f9..1a94b188cb 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1312,7 +1312,9 @@ int manager_setup_cgroup(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to watch control group inotify object: %m"); - r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5); + /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also + * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */ + r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-5); if (r < 0) return log_error_errno(r, "Failed to set priority of inotify event source: %m"); @@ -1458,6 +1460,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { assert(m); assert(cgroup); + log_debug("Got cgroup empty notification for: %s", cgroup); + u = manager_get_unit_by_cgroup(m, cgroup); if (!u) return 0; diff --git a/src/core/dbus.c b/src/core/dbus.c index 263955d874..c8375a0475 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -71,28 +71,42 @@ int bus_send_queued_message(Manager *m) { return 0; } +int bus_forward_agent_released(Manager *m, const char *path) { + int r; + + assert(m); + assert(path); + + if (!MANAGER_IS_SYSTEM(m)) + return 0; + + if (!m->system_bus) + return 0; + + /* If we are running a system instance we forward the agent message on the system bus, so that the user + * instances get notified about this, too */ + + r = sd_bus_emit_signal(m->system_bus, + "/org/freedesktop/systemd1/agent", + "org.freedesktop.systemd1.Agent", + "Released", + "s", path); + if (r < 0) + return log_warning_errno(r, "Failed to propagate agent release message: %m"); + + return 1; +} + static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - const char *cgroup, *me; Manager *m = userdata; + const char *cgroup; uid_t sender_uid; - sd_bus *bus; int r; assert(message); assert(m); - /* ignore recursive events sent by us on the system/user bus */ - bus = sd_bus_message_get_bus(message); - if (!sd_bus_is_server(bus)) { - r = sd_bus_get_unique_name(bus, &me); - if (r < 0) - return r; - - if (streq_ptr(sd_bus_message_get_sender(message), me)) - return 0; - } - /* only accept org.freedesktop.systemd1.Agent from UID=0 */ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); if (r < 0) @@ -110,16 +124,6 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus } manager_notify_cgroup_empty(m, cgroup); - - /* if running as system-instance, forward under our name */ - if (MANAGER_IS_SYSTEM(m) && m->system_bus) { - r = sd_bus_message_rewind(message, 1); - if (r >= 0) - r = sd_bus_send(m->system_bus, message, NULL); - if (r < 0) - log_warning_errno(r, "Failed to forward Released message: %m"); - } - return 0; } @@ -690,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } - if (MANAGER_IS_SYSTEM(m)) { - /* When we run as system instance we get the Released - * signal via a direct connection */ - - 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 new connection bus: %m"); - return 0; - } - } - r = bus_setup_disconnected_match(m, bus); if (r < 0) return 0; @@ -906,8 +891,8 @@ static int bus_setup_system(Manager *m, sd_bus *bus) { assert(m); assert(bus); - /* On kdbus or if we are a user instance we get the Released message via the system bus */ - if (MANAGER_IS_USER(m) || m->kdbus_fd >= 0) { + /* if we are a user instance we get the Released message via the system bus */ + if (MANAGER_IS_USER(m)) { r = sd_bus_add_match( bus, NULL, diff --git a/src/core/dbus.h b/src/core/dbus.h index e16a84fbb8..6baaffbd75 100644 --- a/src/core/dbus.h +++ b/src/core/dbus.h @@ -40,3 +40,5 @@ int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_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); + +int bus_forward_agent_released(Manager *m, const char *path); diff --git a/src/core/manager.c b/src/core/manager.c index bd00c224f4..17b940c11a 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -87,6 +87,7 @@ #include "watchdog.h" #define NOTIFY_RCVBUF_SIZE (8*1024*1024) +#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024) /* Initial delay and the interval for printing status messages about running jobs */ #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) @@ -94,6 +95,7 @@ #define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3 static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); @@ -484,11 +486,11 @@ static int manager_setup_signals(Manager *m) { (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 - * message belongs, before we reap the process. */ - r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-5); + /* 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 message belongs, before we reap the + * process. Also, process this before handling cgroup notifications, so that we always collect child exit + * status information before detecting that there's no process in a cgroup. */ + r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-6); if (r < 0) return r; @@ -581,12 +583,12 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { 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->cgroup_inotify_fd = -1; + m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd = + m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd = + m->ask_password_inotify_fd = -1; m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ - m->ask_password_inotify_fd = -1; m->have_ask_password = -EINVAL; /* we don't know */ m->first_boot = -1; @@ -722,8 +724,8 @@ static int manager_setup_notify(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to allocate notify event source: %m"); - /* Process signals a bit earlier than SIGCHLD, so that we can - * still identify to which service an exit message belongs */ + /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which + * service an exit message belongs. */ r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-7); if (r < 0) return log_error_errno(r, "Failed to set priority of notify event source: %m"); @@ -734,6 +736,79 @@ static int manager_setup_notify(Manager *m) { return 0; } +static int manager_setup_cgroups_agent(Manager *m) { + + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/cgroups-agent", + }; + int r; + + /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering + * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and + * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on + * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number + * of D-Bus connections may be queued until the kernel will start dropping further incoming connections, + * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX + * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and + * we thus won't lose messages. + * + * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen + * to it. The system instance hence listens on this special socket, but the user instances listen on the system + * bus for these messages. */ + + if (m->test_run) + return 0; + + if (!MANAGER_IS_SYSTEM(m)) + return 0; + + if (cg_unified() > 0) /* We don't need this anymore on the unified hierarchy */ + return 0; + + if (m->cgroups_agent_fd < 0) { + _cleanup_close_ int fd = -1; + + /* First free all secondary fields */ + m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) + return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m"); + + fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE); + + (void) unlink(sa.un.sun_path); + + /* Only allow root to connect to this socket */ + RUN_WITH_UMASK(0077) + r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + if (r < 0) + return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); + + m->cgroups_agent_fd = fd; + fd = -1; + } + + if (!m->cgroups_agent_event_source) { + r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m); + if (r < 0) + return log_error_errno(r, "Failed to allocate cgroups agent event source: %m"); + + /* Process cgroups notifications early, but after having processed service notification messages or + * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification, + * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of + * cgroup inotify for the unified cgroup stuff. */ + r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5); + if (r < 0) + return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m"); + + (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent"); + } + + return 0; +} + static int manager_setup_kdbus(Manager *m) { _cleanup_free_ char *p = NULL; @@ -944,12 +1019,14 @@ Manager* manager_free(Manager *m) { sd_event_source_unref(m->signal_event_source); sd_event_source_unref(m->notify_event_source); + sd_event_source_unref(m->cgroups_agent_event_source); sd_event_source_unref(m->time_change_event_source); sd_event_source_unref(m->jobs_in_progress_event_source); sd_event_source_unref(m->run_queue_event_source); safe_close(m->signal_fd); safe_close(m->notify_fd); + safe_close(m->cgroups_agent_fd); safe_close(m->time_change_fd); safe_close(m->kdbus_fd); @@ -1142,6 +1219,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { if (q < 0 && r == 0) r = q; + q = manager_setup_cgroups_agent(m); + if (q < 0 && r == 0) + r = q; + /* We might have deserialized the kdbus control fd, but if we * didn't, then let's create the bus now. */ manager_setup_kdbus(m); @@ -1479,6 +1560,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { return n; } +static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + char buf[PATH_MAX+1]; + ssize_t n; + + n = recv(fd, buf, sizeof(buf), 0); + if (n < 0) + return log_error_errno(errno, "Failed to read cgroups agent message: %m"); + if (n == 0) { + log_error("Got zero-length cgroups agent message, ignoring."); + return 0; + } + if ((size_t) n >= sizeof(buf)) { + log_error("Got overly long cgroups agent message, ignoring."); + return 0; + } + + if (memchr(buf, 0, n)) { + log_error("Got cgroups agent message with embedded NUL byte, ignoring."); + return 0; + } + buf[n] = 0; + + manager_notify_cgroup_empty(m, buf); + bus_forward_agent_released(m, buf); + + return 0; +} + static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) { _cleanup_strv_free_ char **tags = NULL; @@ -2265,6 +2375,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { fprintf(f, "notify-socket=%s\n", m->notify_socket); } + if (m->cgroups_agent_fd >= 0) { + int copy; + + copy = fdset_put_dup(fds, m->cgroups_agent_fd); + if (copy < 0) + return copy; + + fprintf(f, "cgroups-agent-fd=%i\n", copy); + } + if (m->kdbus_fd >= 0) { int copy; @@ -2432,6 +2552,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { free(m->notify_socket); m->notify_socket = n; + } else if (startswith(l, "cgroups-agent-fd=")) { + int fd; + + if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_debug("Failed to parse cgroups agent fd: %s", l + 10); + else { + m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); + safe_close(m->cgroups_agent_fd); + m->cgroups_agent_fd = fdset_remove(fds, fd); + } + } else if (startswith(l, "kdbus-fd=")) { int fd; @@ -2552,6 +2683,10 @@ int manager_reload(Manager *m) { if (q < 0 && r >= 0) r = q; + q = manager_setup_cgroups_agent(m); + if (q < 0 && r >= 0) + r = q; + /* Third, fire things up! */ manager_coldplug(m); diff --git a/src/core/manager.h b/src/core/manager.h index 17f84e6963..4bccca75cb 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -132,6 +132,9 @@ struct Manager { int notify_fd; sd_event_source *notify_event_source; + int cgroups_agent_fd; + sd_event_source *cgroups_agent_event_source; + int signal_fd; sd_event_source *signal_event_source; -- cgit v1.2.3-54-g00ecf From 2679936e6881625a9a95a451b2e4d51092b8ae38 Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Thu, 5 May 2016 13:17:09 +0200 Subject: networkd: fix memleak in config_parse_duid_rawdata --- src/network/networkd-conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 6072c1e2de..b67a1f6d09 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -70,7 +70,7 @@ int config_parse_duid_rawdata( for (;;) { int n1, n2, len, r; uint32_t byte; - char *cbyte; + _cleanup_free_ char *cbyte = NULL; r = extract_first_word(&rvalue, &cbyte, ":", 0); if (r < 0) { -- cgit v1.2.3-54-g00ecf From 3eb83261621dbd398022c8d1f23c7ce68905ee1f Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Thu, 5 May 2016 13:22:35 +0200 Subject: test-networkd-conf: fix memleak --- src/network/test-networkd-conf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index 8a62a2a567..9bd30b82c6 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -47,10 +47,12 @@ static void test_config_parse_duid_type(void) { static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, const DUID* expected) { DUID actual = {}; int r; + _cleanup_free_ char *d = NULL; r = config_parse_duid_rawdata("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL); + d = hexmem(actual.raw_data, actual.raw_data_len); log_info_errno(r, "\"%s\" → \"%s\" (%m)", - rvalue, strnull(hexmem(actual.raw_data, actual.raw_data_len))); + rvalue, strnull(d)); assert_se(r == ret); if (expected) { assert_se(actual.raw_data_len == expected->raw_data_len); -- cgit v1.2.3-54-g00ecf From fc2fffe7706ef269005bf4eef56570346c9ca3da Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 May 2016 22:24:36 +0200 Subject: tree-wide: introduce new SOCKADDR_UN_LEN() macro, and use it everywhere The macro determines the right length of a AF_UNIX "struct sockaddr_un" to pass to connect() or bind(). It automatically figures out if the socket refers to an abstract namespace socket, or a socket in the file system, and properly handles the full length of the path field. This macro is not only safer, but also simpler to use, than the usual offsetof() + strlen() logic. --- src/basic/log.c | 6 +++--- src/basic/socket-util.h | 11 +++++++++++ src/cgroups-agent/cgroups-agent.c | 2 +- src/core/dbus.c | 2 +- src/core/execute.c | 2 +- src/core/manager.c | 11 +++++------ src/coredump/coredump.c | 2 +- src/fsck/fsck.c | 2 +- src/import/importd.c | 2 +- src/journal/journal-send.c | 14 +++++++------- src/journal/journald-native.c | 14 +++++++------- src/journal/journald-server.c | 2 +- src/journal/journald-stream.c | 13 ++++++------- src/journal/journald-syslog.c | 18 +++++++++--------- src/libsystemd/sd-bus/sd-bus.c | 2 +- src/libsystemd/sd-daemon/sd-daemon.c | 4 +--- src/login/pam_systemd.c | 2 +- src/reply-password/reply-password.c | 8 +++----- src/shared/ask-password-api.c | 2 +- src/socket-proxy/socket-proxyd.c | 17 ++++------------- src/test/test-socket-util.c | 17 +++++++++++++++++ src/tty-ask-password-agent/tty-ask-password-agent.c | 7 +++---- src/udev/udev-ctrl.c | 2 +- 23 files changed, 87 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/src/basic/log.c b/src/basic/log.c index d89e6f7274..3ea643b6e6 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -165,7 +165,7 @@ static int log_open_syslog(void) { goto fail; } - if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) { safe_close(syslog_fd); /* Some legacy syslog systems still use stream @@ -177,7 +177,7 @@ static int log_open_syslog(void) { goto fail; } - if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) { r = -errno; goto fail; } @@ -215,7 +215,7 @@ static int log_open_journal(void) { goto fail; } - if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { + if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) { r = -errno; goto fail; } diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index d17a2f35f8..daa4b24a37 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -137,3 +137,14 @@ ssize_t next_datagram_size_fd(int fd); #define CMSG_FOREACH(cmsg, mh) \ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) + +/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */ +#define SOCKADDR_UN_LEN(sa) \ + ({ \ + const struct sockaddr_un *_sa = &(sa); \ + assert(_sa->sun_family == AF_UNIX); \ + offsetof(struct sockaddr_un, sun_path) + \ + (_sa->sun_path[0] == 0 ? \ + 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \ + strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \ + }) diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index 333ce110d3..d7c722ac3d 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) { l = strlen(argv[1]); - n = sendto(fd, argv[1], l, 0, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + n = sendto(fd, argv[1], l, 0, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (n < 0) { log_debug_errno(errno, "Failed to send cgroups agent message: %m"); return EXIT_FAILURE; diff --git a/src/core/dbus.c b/src/core/dbus.c index c8375a0475..3422a02d68 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -975,7 +975,7 @@ static int bus_init_private(Manager *m) { return 0; strcpy(sa.un.sun_path, "/run/systemd/private"); - salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private"); + salen = SOCKADDR_UN_LEN(sa.un); } else { size_t left = sizeof(sa.un.sun_path); char *p = sa.un.sun_path; diff --git a/src/core/execute.c b/src/core/execute.c index ac2ac39892..5eb3f13695 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -271,7 +271,7 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) { } } - r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) r = -errno; diff --git a/src/core/manager.c b/src/core/manager.c index 17b940c11a..e192cd475d 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -705,7 +705,7 @@ static int manager_setup_notify(Manager *m) { (void) unlink(m->notify_socket); strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1); - r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); @@ -782,7 +782,7 @@ static int manager_setup_cgroups_agent(Manager *m) { /* Only allow root to connect to this socket */ RUN_WITH_UMASK(0077) - r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); + r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); @@ -2245,11 +2245,10 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { } void manager_send_unit_plymouth(Manager *m, Unit *u) { - union sockaddr_union sa = PLYMOUTH_SOCKET; - - int n = 0; + static const union sockaddr_union sa = PLYMOUTH_SOCKET; _cleanup_free_ char *message = NULL; _cleanup_close_ int fd = -1; + int n = 0; /* Don't generate plymouth events if the service was already * started and we're just deserializing */ @@ -2275,7 +2274,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { return; } - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { + if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) { if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED)) log_error_errno(errno, "connect() failed: %m"); diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 41fc1993d5..01fdcfa909 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -847,7 +847,7 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd) if (fd < 0) return log_error_errno(errno, "Failed to create coredump socket: %m"); - if (connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0) + if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return log_error_errno(errno, "Failed to connect to coredump service: %m"); for (i = 0; i < n_iovec; i++) { diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 6f56066da8..d32e1d923e 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -262,7 +262,7 @@ static int fsck_progress_socket(void) { 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) { + if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 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); diff --git a/src/import/importd.c b/src/import/importd.c index d2a5867a6e..956a82945c 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -677,7 +677,7 @@ static int manager_new(Manager **ret) { (void) mkdir_parents_label(sa.un.sun_path, 0755); (void) unlink(sa.un.sun_path); - if (bind(m->notify_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0) + if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return -errno; if (setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index f0959b6237..5e8a3e3200 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -208,13 +208,13 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { struct iovec *w; uint64_t *l; int i, j = 0; - struct sockaddr_un sa = { - .sun_family = AF_UNIX, - .sun_path = "/run/systemd/journal/socket", + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/socket", }; struct msghdr mh = { - .msg_name = &sa, - .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path), + .msg_name = (struct sockaddr*) &sa.sa, + .msg_namelen = SOCKADDR_UN_LEN(sa.un), }; ssize_t k; bool have_syslog_identifier = false; @@ -392,7 +392,7 @@ _public_ int sd_journal_perror(const char *message) { } _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) { - union sockaddr_union sa = { + static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/journal/stdout", }; @@ -408,7 +408,7 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve if (fd < 0) return -errno; - r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return -errno; diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index a445291a5e..0a1ce205c2 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -448,24 +448,24 @@ void server_process_native_file( } int server_open_native_socket(Server*s) { + + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/socket", + }; static const int one = 1; int r; assert(s); if (s->native_fd < 0) { - union sockaddr_union sa = { - .un.sun_family = AF_UNIX, - .un.sun_path = "/run/systemd/journal/socket", - }; - s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (s->native_fd < 0) return log_error_errno(errno, "socket() failed: %m"); - unlink(sa.un.sun_path); + (void) unlink(sa.un.sun_path); - r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + r = bind(s->native_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index e14d0ad980..8f82d2a838 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1696,7 +1696,7 @@ static int server_connect_notify(Server *s) { if (sa.un.sun_path[0] == '@') sa.un.sun_path[0] = 0; - r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e)); + r = connect(s->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return log_error_errno(errno, "Failed to connect to notify socket: %m"); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 59352bcb3f..4ad16ee41c 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -700,23 +700,22 @@ fail: } int server_open_stdout_socket(Server *s) { + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/stdout", + }; int r; assert(s); if (s->stdout_fd < 0) { - union sockaddr_union sa = { - .un.sun_family = AF_UNIX, - .un.sun_path = "/run/systemd/journal/stdout", - }; - s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (s->stdout_fd < 0) return log_error_errno(errno, "socket() failed: %m"); - unlink(sa.un.sun_path); + (void) unlink(sa.un.sun_path); - r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + r = bind(s->stdout_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index 5153fd0cce..ead47887d8 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -52,8 +52,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned .msg_iov = (struct iovec *) iovec, .msg_iovlen = n_iovec, .msg_name = (struct sockaddr*) &sa.sa, - .msg_namelen = offsetof(union sockaddr_union, un.sun_path) - + strlen("/run/systemd/journal/syslog"), + .msg_namelen = SOCKADDR_UN_LEN(sa.un), }; struct cmsghdr *cmsg; union { @@ -383,24 +382,24 @@ void server_process_syslog_message( } int server_open_syslog_socket(Server *s) { + + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/journal/dev-log", + }; static const int one = 1; int r; assert(s); if (s->syslog_fd < 0) { - static const union sockaddr_union sa = { - .un.sun_family = AF_UNIX, - .un.sun_path = "/run/systemd/journal/dev-log", - }; - s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (s->syslog_fd < 0) return log_error_errno(errno, "socket() failed: %m"); - unlink(sa.un.sun_path); + (void) unlink(sa.un.sun_path); - r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); + r = bind(s->syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); @@ -437,6 +436,7 @@ int server_open_syslog_socket(Server *s) { void server_maybe_warn_forward_syslog_missed(Server *s) { usec_t n; + assert(s); if (s->n_forward_syslog_missed <= 0) diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 04da94e7e3..ed5f94e136 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -836,7 +836,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) b->sockaddr.un.sun_family = AF_UNIX; strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path)); - b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen("/var/run/dbus/system_bus_socket"); + b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un); return 0; } diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index bd1c7f15ff..4da9dbfd63 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -458,9 +458,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char if (sockaddr.un.sun_path[0] == '@') sockaddr.un.sun_path[0] = 0; - msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); - if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) - msghdr.msg_namelen = sizeof(struct sockaddr_un); + msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un); have_pid = pid != 0 && pid != getpid(); diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 40e246bb06..98dc201340 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -150,7 +150,7 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_ if (fd < 0) return -errno; - if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) + if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return -errno; r = getpeercred(fd, &ucred); diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c index e291758969..17eab9772e 100644 --- a/src/reply-password/reply-password.c +++ b/src/reply-password/reply-password.c @@ -26,14 +26,12 @@ #include "fd-util.h" #include "log.h" #include "macro.h" +#include "socket-util.h" #include "string-util.h" #include "util.h" static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) { - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa = { + union sockaddr_union sa = { .un.sun_family = AF_UNIX, }; @@ -43,7 +41,7 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); - if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) + if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return log_error_errno(errno, "Failed to send: %m"); return 0; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 6805873f9e..4a4bd8d3b8 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -431,7 +431,7 @@ static int create_socket(char **name) { snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()); RUN_WITH_UMASK(0177) { - if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) + if (bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return -errno; } diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index 1157a0c72e..52b4db8875 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -400,28 +400,19 @@ static int resolve_remote(Connection *c) { union sockaddr_union sa = {}; const char *node, *service; - socklen_t salen; int r; if (path_is_absolute(arg_remote_host)) { sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)-1); - sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0; - - salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path); - - return connection_start(c, &sa.sa, salen); + strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)); + return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un)); } if (arg_remote_host[0] == '@') { sa.un.sun_family = AF_UNIX; sa.un.sun_path[0] = 0; - strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-2); - sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0; - - salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa.un.sun_path + 1); - - return connection_start(c, &sa.sa, salen); + strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-1); + return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un)); } service = strrchr(arg_remote_host, ':'); diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 33ff3755bc..9e01f3afd4 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -343,6 +343,21 @@ static void test_sockaddr_equal(void) { assert_se(!sockaddr_equal(&b, &c)); } +static void test_sockaddr_un_len(void) { + static const struct sockaddr_un fs = { + .sun_family = AF_UNIX, + .sun_path = "/foo/bar/waldo", + }; + + static const struct sockaddr_un abstract = { + .sun_family = AF_UNIX, + .sun_path = "\0foobar", + }; + + assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path)); + assert_se(SOCKADDR_UN_LEN(abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1)); +} + int main(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); @@ -363,5 +378,7 @@ int main(int argc, char *argv[]) { test_sockaddr_equal(); + test_sockaddr_un_len(); + return 0; } 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 c7ded451a2..ee879c7b89 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -65,8 +65,8 @@ static int ask_password_plymouth( const char *flag_file, char ***ret) { + static const union sockaddr_union sa = PLYMOUTH_SOCKET; _cleanup_close_ int fd = -1, notify = -1; - union sockaddr_union sa = PLYMOUTH_SOCKET; _cleanup_free_ char *packet = NULL; ssize_t k; int r, n; @@ -94,7 +94,7 @@ static int ask_password_plymouth( if (fd < 0) return -errno; - r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)); + r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return -errno; @@ -269,8 +269,7 @@ static int send_passwords(const char *socket_name, char **passwords) { strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); - r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, - offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)); + r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) r = log_debug_errno(errno, "sendto(): %m"); diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 962de22f43..f68a09d7a8 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -105,7 +105,7 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) { 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); + uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un); return uctrl; } -- cgit v1.2.3-54-g00ecf From 23be5709e10b3b88a9908f3005351ccba9e5d48b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 May 2016 22:26:09 +0200 Subject: journald: stack allocation cannot fail No need to check whether alloca() failed... --- src/journal/journald-syslog.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index ead47887d8..0609b4b694 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -315,12 +315,12 @@ static void syslog_skip_date(char **buf) { } void server_process_syslog_message( - Server *s, - const char *buf, - const struct ucred *ucred, - const struct timeval *tv, - const char *label, - size_t label_len) { + Server *s, + const char *buf, + const struct ucred *ucred, + const struct timeval *tv, + const char *label, + size_t label_len) { char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)], syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)]; @@ -364,14 +364,12 @@ void server_process_syslog_message( if (identifier) { syslog_identifier = strjoina("SYSLOG_IDENTIFIER=", identifier); - if (syslog_identifier) - IOVEC_SET_STRING(iovec[n++], syslog_identifier); + IOVEC_SET_STRING(iovec[n++], syslog_identifier); } if (pid) { syslog_pid = strjoina("SYSLOG_PID=", pid); - if (syslog_pid) - IOVEC_SET_STRING(iovec[n++], syslog_pid); + IOVEC_SET_STRING(iovec[n++], syslog_pid); } message = strjoina("MESSAGE=", buf); -- cgit v1.2.3-54-g00ecf From 1f15ce28461ec54f85908efc063f99dc5a65b4ca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 May 2016 13:39:31 +0200 Subject: core: change default trigger limits for socket units Let's lower the default values a bit, and pick different defaults for Accept=yes and Accept=no sockets. Fixes: #3167 --- man/systemd.socket.xml | 13 +++++++------ src/core/socket.c | 22 +++++++++++++++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 735268c79d..5bf54d8ef3 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -814,13 +814,14 @@ Configures a limit on how often this socket unit my be activated within a specific time interval. The TriggerLimitIntervalSec= may be used to configure the length of the time interval in the usual time units us, ms, s, - min, h, … and defaults to 5s (See + min, h, … and defaults to 2s (See systemd.time7 for details on - the various time units available). The TriggerLimitBurst= setting takes an integer value and - specifies the numer of permitted activations per time interval, and defaults to 2500 (thus by default - permitting 2500 activations per 5s). Set either to 0 to disable any form of trigger rate limiting. If the limit - is hit, the socket unit is placed into a failure mode, and will not be connectible anymore until - restarted. Note that this limit is enforced before the service activation is enqueued. + the various time units understood). The TriggerLimitBurst= setting takes a positive integer + value and specifies the number of permitted activations per time interval, and defaults to 200 for + Accept=yes sockets (thus by default permitting 200 activations per 2s), and 20 otherwise (20 + activations per 2s). Set either to 0 to disable any form of trigger rate limiting. If the limit is hit, the + socket unit is placed into a failure mode, and will not be connectible anymore until restarted. Note that this + limit is enforced before the service activation is enqueued. diff --git a/src/core/socket.c b/src/core/socket.c index d3d4866fe6..4fc66af0b8 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -100,7 +100,8 @@ static void socket_init(Unit *u) { s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; - RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500); + s->trigger_limit.interval = USEC_INFINITY; + s->trigger_limit.burst = (unsigned) -1; } static void socket_unwatch_control_pid(Socket *s) { @@ -328,6 +329,25 @@ static int socket_add_extras(Socket *s) { assert(s); + /* Pick defaults for the trigger limit, if nothing was explicitly configured. We pick a relatively high limit + * in Accept=yes mode, and a lower limit for Accept=no. Reason: in Accept=yes mode we are invoking accept() + * ourselves before the trigger limit can hit, thus incoming connections are taken off the socket queue quickly + * and reliably. This is different for Accept=no, where the spawned service has to take the incoming traffic + * off the queues, which it might not necessarily do. Moreover, while Accept=no services are supposed to + * process whatever is queued in one go, and thus should normally never have to be started frequently. This is + * different for Accept=yes where each connection is processed by a new service instance, and thus frequent + * service starts are typical. */ + + if (s->trigger_limit.interval == USEC_INFINITY) + s->trigger_limit.interval = 2 * USEC_PER_SEC; + + if (s->trigger_limit.burst == (unsigned) -1) { + if (s->accept) + s->trigger_limit.burst = 200; + else + s->trigger_limit.burst = 20; + } + if (have_non_accept_socket(s)) { if (!UNIT_DEREF(s->service)) { -- cgit v1.2.3-54-g00ecf From d2a50e3b5279714218b76f30c29ecfb90b5fb15a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 May 2016 13:45:18 +0200 Subject: core: fix owner user/group output in socket dump The unit file settings are called SocketUser= and SocketGroup= hence name these fields that way in the "systemd-analyze dump" output too. https://github.com/systemd/systemd/issues/3171#issuecomment-216216995 --- src/core/socket.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index 4fc66af0b8..016df40b8c 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -640,8 +640,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { if (!isempty(s->user) || !isempty(s->group)) fprintf(f, - "%sOwnerUser: %s\n" - "%sOwnerGroup: %s\n", + "%sSocketUser: %s\n" + "%sSocketGroup: %s\n", prefix, strna(s->user), prefix, strna(s->group)); @@ -1291,11 +1291,13 @@ static int socket_open_fds(Socket *s) { /* Apply the socket protocol */ switch(p->address.type) { + case SOCK_STREAM: case SOCK_SEQPACKET: if (p->socket->socket_protocol == IPPROTO_SCTP) p->address.protocol = p->socket->socket_protocol; break; + case SOCK_DGRAM: if (p->socket->socket_protocol == IPPROTO_UDPLITE) p->address.protocol = p->socket->socket_protocol; @@ -1359,8 +1361,7 @@ static int socket_open_fds(Socket *s) { } break; - case SOCKET_USB_FUNCTION: - { + case SOCKET_USB_FUNCTION: { _cleanup_free_ char *ep = NULL; ep = path_make_absolute("ep0", p->path); -- cgit v1.2.3-54-g00ecf From 13c31542cc57e1454dccd6383bfdac98cbee5bb1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 5 May 2016 16:42:55 -0400 Subject: core: add io controller support on the unified hierarchy On the unified hierarchy, blkio controller is renamed to io and the interface is changed significantly. * blkio.weight and blkio.weight_device are consolidated into io.weight which uses the standardized weight range [1, 10000] with 100 as the default value. * blkio.throttle.{read|write}_{bps|iops}_device are consolidated into io.max. Expansion of throttling features is being worked on to support work-conserving absolute limits (io.low and io.high). * All stats are consolidated into io.stats. This patchset adds support for the new interface. As the interface has been revamped and new features are expected to be added, it seems best to treat it as a separate controller rather than trying to expand the blkio settings although we might add automatic translation if only blkio settings are specified. * io.weight handling is mostly identical to blkio.weight[_device] handling except that the weight range is different. * Both read and write bandwidth settings are consolidated into CGroupIODeviceLimit which describes all limits applicable to the device. This makes it less painful to add new limits. * "max" can be used to specify the maximum limit which is equivalent to no config for max limits and treated as such. If a given CGroupIODeviceLimit doesn't contain any non-default configs, the config struct is discarded once the no limit config is applied to cgroup. * lookup_blkio_device() is renamed to lookup_block_device(). Signed-off-by: Tejun Heo --- man/systemd.resource-control.xml | 108 +++++++++++- src/basic/cgroup-util.c | 25 ++- src/basic/cgroup-util.h | 18 ++ src/cgtop/cgtop.c | 50 ++++-- src/core/cgroup.c | 147 +++++++++++++++- src/core/cgroup.h | 26 +++ src/core/dbus-cgroup.c | 308 ++++++++++++++++++++++++++++++++++ src/core/load-fragment-gperf.gperf.m4 | 6 + src/core/load-fragment.c | 193 +++++++++++++++++++++ src/core/load-fragment.h | 3 + src/core/main.c | 3 + src/core/manager.h | 1 + src/core/system.conf | 1 + src/core/unit.c | 2 + src/shared/bus-unit-util.c | 30 +++- src/systemctl/systemctl.c | 5 +- 16 files changed, 892 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index fd6f7a1b69..4edb1a25a8 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -248,10 +248,104 @@ + + IOAccounting= + + + Turn on Block I/O accounting for this unit on unified + hierarchy. Takes a boolean argument. Note that turning on + block I/O accounting for one unit will also implicitly turn + it on for all units contained in the same slice and all for + its parent slices and the units contained therein. The + system default for this setting may be controlled with + DefaultIOAccounting= in + systemd-system.conf5. + + + + + IOWeight=weight + StartupIOWeight=weight + + + Set the default overall block I/O weight for the + executed processes on unified hierarchy. Takes a single + weight value (between 1 and 10000) to set the default block + I/O weight. This controls the io.weight + control group attribute, which defaults to 100. For details + about this control group attribute, see cgroup-v2.txt. + The available I/O bandwidth is split up among all units + within one slice relative to their block I/O weight. + + While StartupIOWeight= only applies + to the startup phase of the system, + IOWeight= applies to the later runtime of + the system, and if the former is not set also to the startup + phase. This allows prioritizing specific services at boot-up + differently than during runtime. + + Implies IOAccounting=true. + + + + + IODeviceWeight=device weight + + + Set the per-device overall block I/O weight for the + executed processes on unified hierarchy. Takes a + space-separated pair of a file path and a weight value to + specify the device specific weight value, between 1 and + 10000. (Example: "/dev/sda 1000"). The file path may be + specified as path to a block device node or as any other + file, in which case the backing block device of the file + system of the file is determined. This controls the + io.weight control group attribute, which + defaults to 100. Use this option multiple times to set + weights for multiple devices. For details about this control + group attribute, see cgroup-v2.txt. + + Implies IOAccounting=true. + + + + + IOReadBandwidthMax=device bytes + IOWriteBandwidthMax=device bytes + + + Set the per-device overall block I/O bandwidth maximum + limit for the executed processes on unified hierarchy. This + limit is not work-conserving and the executed processes are + not allowed to use more even if the device has idle + capacity. Takes a space-separated pair of a file path and a + bandwidth value (in bytes per second) to specify the device + specific bandwidth. The file path may be a path to a block + device node, or as any other file in which case the backing + block device of the file system of the file is used. If the + bandwidth is suffixed with K, M, G, or T, the specified + bandwidth is parsed as Kilobytes, Megabytes, Gigabytes, or + Terabytes, respectively, to the base of 1000. (Example: + "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This + controls the io.max control group + attributes. Use this option multiple times to set bandwidth + limits for multiple devices. For details about this control + group attribute, see cgroup-v2.txt. + + + Implies IOAccounting=true. + + + BlockIOAccounting= + Use IOAccounting on unified hierarchy. + Turn on Block I/O accounting for this unit. Takes a boolean argument. Note that turning on block I/O accounting for one unit will also implicitly turn it on for all units @@ -267,9 +361,12 @@ BlockIOWeight=weight StartupBlockIOWeight=weight - Set the default overall block I/O weight for - the executed processes. Takes a single weight value (between - 10 and 1000) to set the default block I/O weight. This controls + Use IOWeight and StartupIOWeight on unified + hierarchy. + + Set the default overall block I/O weight for the + executed processes. Takes a single weight value (between 10 + and 1000) to set the default block I/O weight. This controls the blkio.weight control group attribute, which defaults to 500. For details about this control group attribute, see BlockIODeviceWeight=device weight + Use IODeviceWeight on unified hierarchy. + Set the per-device overall block I/O weight for the executed processes. Takes a space-separated pair of a file path and a weight value to specify the device specific @@ -317,6 +416,9 @@ BlockIOWriteBandwidth=device bytes + Use IOReadBandwidthMax and IOWriteBandwidthMax on + unified hierarchy. + Set the per-device overall block I/O bandwidth limit for the executed processes. Takes a space-separated pair of a file path and a bandwidth value (in bytes per second) to diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 5043180747..ff57cf30b7 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2060,10 +2060,10 @@ int cg_mask_supported(CGroupMask *ret) { mask |= CGROUP_CONTROLLER_TO_MASK(v); } - /* Currently, we only support the memory and pids + /* Currently, we only support the memory, io and pids * controller in the unified hierarchy, mask * everything else off. */ - mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS; + mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS; } else { CGroupController c; @@ -2249,6 +2249,26 @@ bool cg_is_legacy_wanted(void) { return !cg_is_unified_wanted(); } +int cg_weight_parse(const char *s, uint64_t *ret) { + uint64_t u; + int r; + + if (isempty(s)) { + *ret = CGROUP_WEIGHT_INVALID; + return 0; + } + + r = safe_atou64(s, &u); + if (r < 0) + return r; + + if (u < CGROUP_WEIGHT_MIN || u > CGROUP_WEIGHT_MAX) + return -ERANGE; + + *ret = u; + return 0; +} + int cg_cpu_shares_parse(const char *s, uint64_t *ret) { uint64_t u; int r; @@ -2292,6 +2312,7 @@ int cg_blkio_weight_parse(const char *s, uint64_t *ret) { static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { [CGROUP_CONTROLLER_CPU] = "cpu", [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", + [CGROUP_CONTROLLER_IO] = "io", [CGROUP_CONTROLLER_BLKIO] = "blkio", [CGROUP_CONTROLLER_MEMORY] = "memory", [CGROUP_CONTROLLER_DEVICES] = "devices", diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 4254e51e5d..a696c1fa60 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -34,6 +34,7 @@ typedef enum CGroupController { CGROUP_CONTROLLER_CPU, CGROUP_CONTROLLER_CPUACCT, + CGROUP_CONTROLLER_IO, CGROUP_CONTROLLER_BLKIO, CGROUP_CONTROLLER_MEMORY, CGROUP_CONTROLLER_DEVICES, @@ -48,6 +49,7 @@ typedef enum CGroupController { typedef enum CGroupMask { CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU), CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT), + CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO), CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO), CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY), CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES), @@ -55,6 +57,21 @@ typedef enum CGroupMask { _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1 } CGroupMask; +/* Special values for all weight knobs on unified hierarchy */ +#define CGROUP_WEIGHT_INVALID ((uint64_t) -1) +#define CGROUP_WEIGHT_MIN UINT64_C(1) +#define CGROUP_WEIGHT_MAX UINT64_C(10000) +#define CGROUP_WEIGHT_DEFAULT UINT64_C(100) + +#define CGROUP_LIMIT_MIN UINT64_C(0) +#define CGROUP_LIMIT_MAX ((uint64_t) -1) + +static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) { + return + x == CGROUP_WEIGHT_INVALID || + (x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX); +} + /* Special values for the cpu.shares attribute */ #define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) #define CGROUP_CPU_SHARES_MIN UINT64_C(2) @@ -190,5 +207,6 @@ bool cg_is_legacy_wanted(void); const char* cgroup_controller_to_string(CGroupController c) _const_; CGroupController cgroup_controller_from_string(const char *s) _pure_; +int cg_weight_parse(const char *s, uint64_t *ret); int cg_cpu_shares_parse(const char *s, uint64_t *ret); int cg_blkio_weight_parse(const char *s, uint64_t *ret); diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 14eb46c8db..e088e4b197 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -269,13 +269,15 @@ static int process( if (g->memory > 0) g->memory_valid = true; - } else if (streq(controller, "blkio") && cg_unified() <= 0) { + } else if ((streq(controller, "io") && cg_unified() > 0) || + (streq(controller, "blkio") && cg_unified() <= 0)) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; + bool unified = cg_unified() > 0; uint64_t wr = 0, rd = 0; nsec_t timestamp; - r = cg_get_path(controller, path, "blkio.io_service_bytes", &p); + r = cg_get_path(controller, path, unified ? "io.stat" : "blkio.io_service_bytes", &p); if (r < 0) return r; @@ -293,25 +295,38 @@ static int process( if (!fgets(line, sizeof(line), f)) break; + /* Trim and skip the device */ l = strstrip(line); l += strcspn(l, WHITESPACE); l += strspn(l, WHITESPACE); - if (first_word(l, "Read")) { - l += 4; - q = &rd; - } else if (first_word(l, "Write")) { - l += 5; - q = ≀ - } else - continue; - - l += strspn(l, WHITESPACE); - r = safe_atou64(l, &k); - if (r < 0) - continue; + if (unified) { + while (!isempty(l)) { + if (sscanf(l, "rbytes=%" SCNu64, &k)) + rd += k; + else if (sscanf(l, "wbytes=%" SCNu64, &k)) + wr += k; - *q += k; + l += strcspn(l, WHITESPACE); + l += strspn(l, WHITESPACE); + } + } else { + if (first_word(l, "Read")) { + l += 4; + q = &rd; + } else if (first_word(l, "Write")) { + l += 5; + q = ≀ + } else + continue; + + l += strspn(l, WHITESPACE); + r = safe_atou64(l, &k); + if (r < 0) + continue; + + *q += k; + } } timestamp = now_nsec(CLOCK_MONOTONIC); @@ -437,6 +452,9 @@ static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration) if (r < 0) return r; r = refresh_one("memory", root, a, b, iteration, 0, NULL); + if (r < 0) + return r; + r = refresh_one("io", root, a, b, iteration, 0, NULL); if (r < 0) return r; r = refresh_one("blkio", root, a, b, iteration, 0, NULL); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 25cc6962f9..44106e52ea 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -32,6 +32,7 @@ #include "special.h" #include "string-table.h" #include "string-util.h" +#include "stdio-util.h" #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC) @@ -47,6 +48,9 @@ void cgroup_context_init(CGroupContext *c) { c->memory_limit = (uint64_t) -1; + c->io_weight = CGROUP_WEIGHT_INVALID; + c->startup_io_weight = CGROUP_WEIGHT_INVALID; + c->blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID; c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID; @@ -62,6 +66,24 @@ void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) { free(a); } +void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w) { + assert(c); + assert(w); + + LIST_REMOVE(device_weights, c->io_device_weights, w); + free(w->path); + free(w); +} + +void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l) { + assert(c); + assert(l); + + LIST_REMOVE(device_limits, c->io_device_limits, l); + free(l->path); + free(l); +} + void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) { assert(c); assert(w); @@ -83,6 +105,12 @@ void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockI void cgroup_context_done(CGroupContext *c) { assert(c); + while (c->io_device_weights) + cgroup_context_free_io_device_weight(c, c->io_device_weights); + + while (c->io_device_limits) + cgroup_context_free_io_device_limit(c, c->io_device_limits); + while (c->blockio_device_weights) cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); @@ -94,6 +122,8 @@ void cgroup_context_done(CGroupContext *c) { } void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + CGroupIODeviceLimit *il; + CGroupIODeviceWeight *iw; CGroupBlockIODeviceBandwidth *b; CGroupBlockIODeviceWeight *w; CGroupDeviceAllow *a; @@ -106,12 +136,15 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { fprintf(f, "%sCPUAccounting=%s\n" + "%sIOAccounting=%s\n" "%sBlockIOAccounting=%s\n" "%sMemoryAccounting=%s\n" "%sTasksAccounting=%s\n" "%sCPUShares=%" PRIu64 "\n" "%sStartupCPUShares=%" PRIu64 "\n" "%sCPUQuotaPerSecSec=%s\n" + "%sIOWeight=%" PRIu64 "\n" + "%sStartupIOWeight=%" PRIu64 "\n" "%sBlockIOWeight=%" PRIu64 "\n" "%sStartupBlockIOWeight=%" PRIu64 "\n" "%sMemoryLimit=%" PRIu64 "\n" @@ -119,12 +152,15 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sDevicePolicy=%s\n" "%sDelegate=%s\n", prefix, yes_no(c->cpu_accounting), + prefix, yes_no(c->io_accounting), prefix, yes_no(c->blockio_accounting), prefix, yes_no(c->memory_accounting), prefix, yes_no(c->tasks_accounting), prefix, c->cpu_shares, prefix, c->startup_cpu_shares, prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1), + prefix, c->io_weight, + prefix, c->startup_io_weight, prefix, c->blockio_weight, prefix, c->startup_blockio_weight, prefix, c->memory_limit, @@ -139,6 +175,31 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); + LIST_FOREACH(device_weights, iw, c->io_device_weights) + fprintf(f, + "%sIODeviceWeight=%s %" PRIu64, + prefix, + iw->path, + iw->weight); + + LIST_FOREACH(device_limits, il, c->io_device_limits) { + char buf[FORMAT_BYTES_MAX]; + + if (il->rbps_max != CGROUP_LIMIT_MAX) + fprintf(f, + "%sIOReadBandwidthMax=%s %s\n", + prefix, + il->path, + format_bytes(buf, sizeof(buf), il->rbps_max)); + + if (il->wbps_max != CGROUP_LIMIT_MAX) + fprintf(f, + "%sIOWriteBandwidthMax=%s %s\n", + prefix, + il->path, + format_bytes(buf, sizeof(buf), il->wbps_max)); + } + LIST_FOREACH(device_weights, w, c->blockio_device_weights) fprintf(f, "%sBlockIODeviceWeight=%s %" PRIu64, @@ -158,7 +219,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { } } -static int lookup_blkio_device(const char *p, dev_t *dev) { +static int lookup_block_device(const char *p, dev_t *dev) { struct stat st; int r; @@ -343,6 +404,77 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M "Failed to set cpu.cfs_quota_us on %s: %m", path); } + if (mask & CGROUP_MASK_IO) { + CGroupIODeviceWeight *w; + CGroupIODeviceLimit *l, *next; + + if (!is_root) { + char buf[MAX(8+DECIMAL_STR_MAX(uint64_t)+1, + DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; + uint64_t weight = CGROUP_WEIGHT_DEFAULT; + + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + c->startup_io_weight != CGROUP_WEIGHT_INVALID) + weight = c->startup_io_weight; + else if (c->io_weight != CGROUP_WEIGHT_INVALID) + weight = c->io_weight; + + xsprintf(buf, "default %" PRIu64 "\n", weight); + r = cg_set_attribute("io", path, "io.weight", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.weight on %s: %m", path); + + /* FIXME: no way to reset this list */ + LIST_FOREACH(device_weights, w, c->io_device_weights) { + dev_t dev; + + r = lookup_block_device(w->path, &dev); + if (r < 0) + continue; + + xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight); + r = cg_set_attribute("io", path, "io.weight", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.weight on %s: %m", path); + } + } + + LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { + char rbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max"; + char wbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max"; + char buf[DECIMAL_STR_MAX(dev_t)*2+2+(5+DECIMAL_STR_MAX(uint64_t)+1)*2]; + dev_t dev; + unsigned n = 0; + + r = lookup_block_device(l->path, &dev); + if (r < 0) + continue; + + if (l->rbps_max != CGROUP_LIMIT_MAX) { + xsprintf(rbps_buf, "%" PRIu64, l->rbps_max); + n++; + } + + if (l->wbps_max != CGROUP_LIMIT_MAX) { + xsprintf(wbps_buf, "%" PRIu64, l->wbps_max); + n++; + } + + xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev), rbps_buf, wbps_buf); + r = cg_set_attribute("io", path, "io.max", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.max on %s: %m", path); + + /* If @l contained no config, we just cleared the kernel + counterpart too. No reason to keep @l around. */ + if (!n) + cgroup_context_free_io_device_limit(c, l); + } + } + if (mask & CGROUP_MASK_BLKIO) { char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1, DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; @@ -362,7 +494,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M LIST_FOREACH(device_weights, w, c->blockio_device_weights) { dev_t dev; - r = lookup_blkio_device(w->path, &dev); + r = lookup_block_device(w->path, &dev); if (r < 0) continue; @@ -379,7 +511,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M const char *a; dev_t dev; - r = lookup_blkio_device(b->path, &dev); + r = lookup_block_device(b->path, &dev); if (r < 0) continue; @@ -506,6 +638,13 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) { c->cpu_quota_per_sec_usec != USEC_INFINITY) mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU; + if (c->io_accounting || + c->io_weight != CGROUP_WEIGHT_INVALID || + c->startup_io_weight != CGROUP_WEIGHT_INVALID || + c->io_device_weights || + c->io_device_limits) + mask |= CGROUP_MASK_IO; + if (c->blockio_accounting || c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || @@ -1608,7 +1747,7 @@ void manager_invalidate_startup_units(Manager *m) { assert(m); SET_FOREACH(u, m->startup_units, i) - unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_BLKIO); + unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_BLKIO); } static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = { diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 360bbca30f..a533923072 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -26,6 +26,8 @@ typedef struct CGroupContext CGroupContext; typedef struct CGroupDeviceAllow CGroupDeviceAllow; +typedef struct CGroupIODeviceWeight CGroupIODeviceWeight; +typedef struct CGroupIODeviceLimit CGroupIODeviceLimit; typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight; typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth; @@ -53,6 +55,19 @@ struct CGroupDeviceAllow { bool m:1; }; +struct CGroupIODeviceWeight { + LIST_FIELDS(CGroupIODeviceWeight, device_weights); + char *path; + uint64_t weight; +}; + +struct CGroupIODeviceLimit { + LIST_FIELDS(CGroupIODeviceLimit, device_limits); + char *path; + uint64_t rbps_max; + uint64_t wbps_max; +}; + struct CGroupBlockIODeviceWeight { LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights); char *path; @@ -68,10 +83,18 @@ struct CGroupBlockIODeviceBandwidth { struct CGroupContext { bool cpu_accounting; + bool io_accounting; bool blockio_accounting; bool memory_accounting; bool tasks_accounting; + /* For unified hierarchy */ + uint64_t io_weight; + uint64_t startup_io_weight; + LIST_HEAD(CGroupIODeviceWeight, io_device_weights); + LIST_HEAD(CGroupIODeviceLimit, io_device_limits); + + /* For legacy hierarchies */ uint64_t cpu_shares; uint64_t startup_cpu_shares; usec_t cpu_quota_per_sec_usec; @@ -86,6 +109,7 @@ struct CGroupContext { CGroupDevicePolicy device_policy; LIST_HEAD(CGroupDeviceAllow, device_allow); + /* Common */ uint64_t tasks_max; bool delegate; @@ -102,6 +126,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M CGroupMask cgroup_context_get_mask(CGroupContext *c); void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a); +void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w); +void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l); void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w); void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 859d155ec1..a2a4a6249c 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -28,6 +28,76 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); +static int property_get_io_device_weight( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + CGroupContext *c = userdata; + CGroupIODeviceWeight *w; + int r; + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; + + LIST_FOREACH(device_weights, w, c->io_device_weights) { + r = sd_bus_message_append(reply, "(st)", w->path, w->weight); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_io_device_limits( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + CGroupContext *c = userdata; + CGroupIODeviceLimit *l; + int r; + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "(st)"); + if (r < 0) + return r; + + LIST_FOREACH(device_limits, l, c->io_device_limits) { + uint64_t v; + + if (streq(property, "IOReadBandwidthMax")) + v = l->rbps_max; + else + v = l->wbps_max; + + if (v == CGROUP_LIMIT_MAX) + continue; + + r = sd_bus_message_append(reply, "(st)", l->path, v); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + static int property_get_blockio_device_weight( sd_bus *bus, const char *path, @@ -141,6 +211,12 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0), SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0), SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0), + SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0), + SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0), + SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0), + SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0), + SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0), + SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0), SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0), SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0), @@ -281,6 +357,238 @@ int bus_cgroup_set_property( return 1; + } else if (streq(name, "IOAccounting")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->io_accounting = b; + unit_invalidate_cgroup(u, CGROUP_MASK_IO); + unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no"); + } + + return 1; + + } else if (streq(name, "IOWeight")) { + uint64_t weight; + + r = sd_bus_message_read(message, "t", &weight); + if (r < 0) + return r; + + if (!CGROUP_WEIGHT_IS_OK(weight)) + return sd_bus_error_set_errnof(error, EINVAL, "IOWeight value out of range"); + + if (mode != UNIT_CHECK) { + c->io_weight = weight; + unit_invalidate_cgroup(u, CGROUP_MASK_IO); + + if (weight == CGROUP_WEIGHT_INVALID) + unit_write_drop_in_private(u, mode, name, "IOWeight="); + else + unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight); + } + + return 1; + + } else if (streq(name, "StartupIOWeight")) { + uint64_t weight; + + r = sd_bus_message_read(message, "t", &weight); + if (r < 0) + return r; + + if (CGROUP_WEIGHT_IS_OK(weight)) + return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight value out of range"); + + if (mode != UNIT_CHECK) { + c->startup_io_weight = weight; + unit_invalidate_cgroup(u, CGROUP_MASK_IO); + + if (weight == CGROUP_WEIGHT_INVALID) + unit_write_drop_in_private(u, mode, name, "StartupIOWeight="); + else + unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight); + } + + return 1; + + } else if (streq(name, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax")) { + const char *path; + bool read = true; + unsigned n = 0; + uint64_t u64; + + if (streq(name, "IOWriteBandwidthMax")) + read = false; + + r = sd_bus_message_enter_container(message, 'a', "(st)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { + + if (mode != UNIT_CHECK) { + CGroupIODeviceLimit *a = NULL, *b; + + LIST_FOREACH(device_limits, b, c->io_device_limits) { + if (path_equal(path, b->path)) { + a = b; + break; + } + } + + if (!a) { + a = new0(CGroupIODeviceLimit, 1); + if (!a) + return -ENOMEM; + + a->path = strdup(path); + if (!a->path) { + free(a); + return -ENOMEM; + } + + a->rbps_max = CGROUP_LIMIT_MAX; + a->wbps_max = CGROUP_LIMIT_MAX; + + LIST_PREPEND(device_limits, c->io_device_limits, a); + } + + if (read) + a->rbps_max = u64; + else + a->wbps_max = u64; + } + + n++; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + CGroupIODeviceLimit *a; + _cleanup_free_ char *buf = NULL; + _cleanup_fclose_ FILE *f = NULL; + size_t size = 0; + + if (n == 0) { + LIST_FOREACH(device_limits, a, c->io_device_limits) + if (read) + a->rbps_max = CGROUP_LIMIT_MAX; + else + a->wbps_max = CGROUP_LIMIT_MAX; + } + + unit_invalidate_cgroup(u, CGROUP_MASK_IO); + + f = open_memstream(&buf, &size); + if (!f) + return -ENOMEM; + + if (read) { + fputs("IOReadBandwidthMax=\n", f); + LIST_FOREACH(device_limits, a, c->io_device_limits) + if (a->rbps_max != CGROUP_LIMIT_MAX) + fprintf(f, "IOReadBandwidthMax=%s %" PRIu64 "\n", a->path, a->rbps_max); + } else { + fputs("IOWriteBandwidthMax=\n", f); + LIST_FOREACH(device_limits, a, c->io_device_limits) + if (a->wbps_max != CGROUP_LIMIT_MAX) + fprintf(f, "IOWriteBandwidthMax=%s %" PRIu64 "\n", a->path, a->wbps_max); + } + + r = fflush_and_check(f); + if (r < 0) + return r; + unit_write_drop_in_private(u, mode, name, buf); + } + + return 1; + + } else if (streq(name, "IODeviceWeight")) { + const char *path; + uint64_t weight; + unsigned n = 0; + + r = sd_bus_message_enter_container(message, 'a', "(st)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { + + if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID) + return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight out of range"); + + if (mode != UNIT_CHECK) { + CGroupIODeviceWeight *a = NULL, *b; + + LIST_FOREACH(device_weights, b, c->io_device_weights) { + if (path_equal(b->path, path)) { + a = b; + break; + } + } + + if (!a) { + a = new0(CGroupIODeviceWeight, 1); + if (!a) + return -ENOMEM; + + a->path = strdup(path); + if (!a->path) { + free(a); + return -ENOMEM; + } + LIST_PREPEND(device_weights,c->io_device_weights, a); + } + + a->weight = weight; + } + + n++; + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *buf = NULL; + _cleanup_fclose_ FILE *f = NULL; + CGroupIODeviceWeight *a; + size_t size = 0; + + if (n == 0) { + while (c->io_device_weights) + cgroup_context_free_io_device_weight(c, c->io_device_weights); + } + + unit_invalidate_cgroup(u, CGROUP_MASK_IO); + + f = open_memstream(&buf, &size); + if (!f) + return -ENOMEM; + + fputs("IODeviceWeight=\n", f); + LIST_FOREACH(device_weights, a, c->io_device_weights) + fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight); + + r = fflush_and_check(f); + if (r < 0) + return r; + unit_write_drop_in_private(u, mode, name, buf); + } + + return 1; + } else if (streq(name, "BlockIOAccounting")) { int b; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 928b913c7b..ad45611d9d 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -120,6 +120,12 @@ $1.MemoryAccounting, config_parse_bool, 0, $1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context) $1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy) +$1.IOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.io_accounting) +$1.IOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.io_weight) +$1.StartupIOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.startup_io_weight) +$1.IODeviceWeight, config_parse_io_device_weight, 0, offsetof($1, cgroup_context) +$1.IOReadBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context) +$1.IOWriteBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context) $1.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting) $1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.blockio_weight) $1.StartupBlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.startup_blockio_weight) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 1a8c03904c..9d7329e924 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2904,6 +2904,196 @@ int config_parse_device_allow( return 0; } +int config_parse_io_weight( + 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) { + + uint64_t *weight = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = cg_weight_parse(rvalue, weight); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue); + return 0; + } + + return 0; +} + +int config_parse_io_device_weight( + 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) { + + _cleanup_free_ char *path = NULL; + CGroupIODeviceWeight *w; + CGroupContext *c = data; + const char *weight; + uint64_t u; + size_t n; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + while (c->io_device_weights) + cgroup_context_free_io_device_weight(c, c->io_device_weights); + + return 0; + } + + n = strcspn(rvalue, WHITESPACE); + weight = rvalue + n; + weight += strspn(weight, WHITESPACE); + + if (isempty(weight)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring."); + return 0; + } + + path = strndup(rvalue, n); + if (!path) + return log_oom(); + + if (!path_startswith(path, "/dev")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); + return 0; + } + + r = cg_weight_parse(weight, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight); + return 0; + } + + assert(u != CGROUP_WEIGHT_INVALID); + + w = new0(CGroupIODeviceWeight, 1); + if (!w) + return log_oom(); + + w->path = path; + path = NULL; + + w->weight = u; + + LIST_PREPEND(device_weights, c->io_device_weights, w); + return 0; +} + +int config_parse_io_limit( + 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) { + + _cleanup_free_ char *path = NULL; + CGroupIODeviceLimit *l = NULL, *t; + CGroupContext *c = data; + const char *limit; + uint64_t num; + bool read; + size_t n; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + read = streq("IOReadBandwidthMax", lvalue); + + if (isempty(rvalue)) { + LIST_FOREACH(device_limits, l, c->io_device_limits) + if (read) + l->rbps_max = CGROUP_LIMIT_MAX; + else + l->wbps_max = CGROUP_LIMIT_MAX; + return 0; + } + + n = strcspn(rvalue, WHITESPACE); + limit = rvalue + n; + limit += strspn(limit, WHITESPACE); + + if (!*limit) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring."); + return 0; + } + + path = strndup(rvalue, n); + if (!path) + return log_oom(); + + if (!path_startswith(path, "/dev")) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); + return 0; + } + + if (streq("max", limit)) { + num = CGROUP_LIMIT_MAX; + } else { + r = parse_size(limit, 1000, &num); + if (r < 0 || num <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue); + return 0; + } + } + + LIST_FOREACH(device_limits, t, c->io_device_limits) { + if (path_equal(path, t->path)) { + l = t; + break; + } + } + + if (!l) { + l = new0(CGroupIODeviceLimit, 1); + if (!l) + return log_oom(); + + l->path = path; + path = NULL; + l->rbps_max = CGROUP_LIMIT_MAX; + l->wbps_max = CGROUP_LIMIT_MAX; + + LIST_PREPEND(device_limits, c->io_device_limits, l); + } + + if (read) + l->rbps_max = num; + else + l->wbps_max = num; + + return 0; +} + int config_parse_blockio_weight( const char *unit, const char *filename, @@ -3824,6 +4014,9 @@ void unit_dump_config_items(FILE *f) { { config_parse_memory_limit, "LIMIT" }, { config_parse_device_allow, "DEVICE" }, { config_parse_device_policy, "POLICY" }, + { config_parse_io_limit, "LIMIT" }, + { config_parse_io_weight, "WEIGHT" }, + { config_parse_io_device_weight, "DEVICEWEIGHT" }, { config_parse_blockio_bandwidth, "BANDWIDTH" }, { config_parse_blockio_weight, "WEIGHT" }, { config_parse_blockio_device_weight, "DEVICEWEIGHT" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 34f15afa62..b36a2e3a02 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -86,6 +86,9 @@ int config_parse_memory_limit(const char *unit, const char *filename, unsigned l int config_parse_tasks_max(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_device_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_device_allow(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_io_weight(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_io_device_weight(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_io_limit(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_blockio_weight(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_blockio_device_weight(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_blockio_bandwidth(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/core/main.c b/src/core/main.c index ed4d42c8cc..6397aadc73 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -122,6 +122,7 @@ static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE; static Set* arg_syscall_archs = NULL; static FILE* arg_serialization = NULL; static bool arg_default_cpu_accounting = false; +static bool arg_default_io_accounting = false; static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; static bool arg_default_tasks_accounting = true; @@ -691,6 +692,7 @@ static int parse_config_file(void) { { "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit }, { "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit }, { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting }, + { "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting }, { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, @@ -733,6 +735,7 @@ static void manager_set_defaults(Manager *m) { m->default_start_limit_interval = arg_default_start_limit_interval; m->default_start_limit_burst = arg_default_start_limit_burst; m->default_cpu_accounting = arg_default_cpu_accounting; + m->default_io_accounting = arg_default_io_accounting; m->default_blockio_accounting = arg_default_blockio_accounting; m->default_memory_accounting = arg_default_memory_accounting; m->default_tasks_accounting = arg_default_tasks_accounting; diff --git a/src/core/manager.h b/src/core/manager.h index 17f84e6963..f23e4056c4 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -252,6 +252,7 @@ struct Manager { bool default_cpu_accounting; bool default_memory_accounting; + bool default_io_accounting; bool default_blockio_accounting; bool default_tasks_accounting; diff --git a/src/core/system.conf b/src/core/system.conf index eacd7ee282..db8b7acd78 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -38,6 +38,7 @@ #DefaultStartLimitBurst=5 #DefaultEnvironment= #DefaultCPUAccounting=no +#DefaultIOAccounting=no #DefaultBlockIOAccounting=no #DefaultMemoryAccounting=no #DefaultTasksAccounting=yes diff --git a/src/core/unit.c b/src/core/unit.c index 8153515e89..04addc1f70 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -132,6 +132,7 @@ static void unit_init(Unit *u) { * been initialized */ cc->cpu_accounting = u->manager->default_cpu_accounting; + cc->io_accounting = u->manager->default_io_accounting; cc->blockio_accounting = u->manager->default_blockio_accounting; cc->memory_accounting = u->manager->default_memory_accounting; cc->tasks_accounting = u->manager->default_tasks_accounting; @@ -1213,6 +1214,7 @@ static int unit_add_startup_units(Unit *u) { return 0; if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID && + c->startup_io_weight == CGROUP_WEIGHT_INVALID && c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID) return 0; diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 2b755cea28..94d1c1d63c 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -154,7 +154,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur); } else if (STR_IN_SET(field, - "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting", + "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", "TasksAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", @@ -207,6 +207,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "t", u); + } else if (STR_IN_SET(field, "IOWeight", "StartupIOWeight")) { + uint64_t u; + + r = cg_weight_parse(eq, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", u); + } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) { uint64_t u; @@ -273,7 +284,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm); } - } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { + } else if (STR_IN_SET(field, "IOReadBandwidthMax", "IOWriteBandwidthMax", + "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(st)", 0); @@ -295,16 +307,20 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } - r = parse_size(bandwidth, 1000, &bytes); - if (r < 0) { - log_error("Failed to parse byte value %s.", bandwidth); - return -EINVAL; + if (streq(bandwidth, "max")) { + bytes = CGROUP_LIMIT_MAX; + } else { + r = parse_size(bandwidth, 1000, &bytes); + if (r < 0) { + log_error("Failed to parse byte value %s.", bandwidth); + return -EINVAL; + } } r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes); } - } else if (streq(field, "BlockIODeviceWeight")) { + } else if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(st)", 0); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index bec4f31b39..387de025c5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4428,7 +4428,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return 0; - } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) { + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "IODeviceWeight") || streq(name, "BlockIODeviceWeight"))) { const char *path; uint64_t weight; @@ -4447,7 +4447,8 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return 0; - } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) { + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax") || + streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) { const char *path; uint64_t bandwidth; -- cgit v1.2.3-54-g00ecf From 183e0738427b83667512276a3e8c10274c0824cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 May 2016 18:57:15 +0200 Subject: logind: enforce a limit on current user sessions We really should put limits on all resources we manage, hence add one to the number of concurrent sessions, too. This was previously unbounded, hence set a relatively high limit of 8K by default. Note that most PAM setups will actually invoke pam_systemd prefixed with "-", so that the return code of pam_systemd is ignored, and the login attempt succeeds anyway. On systems like this the session will be created but is not tracked by systemd. --- man/logind.conf.xml | 9 +++++++++ src/login/logind-dbus.c | 23 +++++++++++++++++++++++ src/login/logind-gperf.gperf | 1 + src/login/logind.c | 1 + src/login/logind.conf.in | 1 + src/login/logind.h | 1 + 6 files changed, 36 insertions(+) (limited to 'src') diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 6ba35414be..405dcf9041 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -296,6 +296,15 @@ memory as is needed. + + SessionsMax= + + Controls the maximum number of concurrent user sessions to manage. Defaults to 8192 + (8K). Depending on how the pam_systemd.so module is included in the PAM stack + configuration, further login sessions will either be refused, or permitted but not tracked by + systemd-logind. + + UserTasksMax= diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index a281f99a34..5067e5d1a8 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -265,6 +265,24 @@ static int property_get_docked( return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m)); } +static int property_get_current_sessions( + 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; + + assert(bus); + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions)); +} + static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *p = NULL; Manager *m = userdata; @@ -725,6 +743,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus m->seat0->positions[vtnr]->class != SESSION_GREETER) return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session"); + if (hashmap_size(m->sessions) >= m->sessions_max) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max); + audit_session_from_pid(leader, &audit_id); if (audit_id > 0) { /* Keep our session IDs and the audit session IDs in sync */ @@ -2512,6 +2533,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0), SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0), SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0), + SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 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), diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 8552c464cc..1d57681260 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -34,4 +34,5 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec) Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size) Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc) +Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max) Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max) diff --git a/src/login/logind.c b/src/login/logind.c index a48e2fc61e..39f53cab36 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -63,6 +63,7 @@ static void manager_reset_config(Manager *m) { m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ m->user_tasks_max = UINT64_C(12288); + m->sessions_max = UINT64_C(8192); m->kill_user_processes = KILL_USER_PROCESSES; diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 3c96def45d..6284218625 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -32,4 +32,5 @@ #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=yes +#SessionsMax=8192 #UserTasksMax=12288 diff --git a/src/login/logind.h b/src/login/logind.h index 6748af3c07..23c3e2963a 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -133,6 +133,7 @@ struct Manager { size_t runtime_dir_size; uint64_t user_tasks_max; + uint64_t sessions_max; }; int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device); -- cgit v1.2.3-54-g00ecf From e11544a8305ab9dea097c74bb16e296150c9cc10 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 May 2016 19:01:56 +0200 Subject: logind: process session/inhibitor fds at higher priority Let's make sure we process session and inhibitor pipe fds (that signal sessions/inhibtors going away) at a higher priority than new bus calls that might create new sessions or inhibitors. This helps ensuring that the number of open sessions stays minimal. --- src/login/logind-inhibit.c | 2 +- src/login/logind-session.c | 4 +++- src/login/logind.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index a0e3ba2b7c..6c78e0dddc 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -317,7 +317,7 @@ int inhibitor_create_fifo(Inhibitor *i) { if (r < 0) return r; - r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE); + r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10); if (r < 0) return r; } diff --git a/src/login/logind-session.c b/src/login/logind-session.c index a8b1d5943d..d2f1f7bc62 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -897,7 +897,9 @@ int session_create_fifo(Session *s) { if (r < 0) return r; - r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); + /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new + * sessions). */ + r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10); if (r < 0) return r; } diff --git a/src/login/logind.c b/src/login/logind.c index 39f53cab36..64bd1ca582 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -687,7 +687,7 @@ static int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register name: %m"); - r = sd_bus_attach_event(m->bus, m->event, 0); + r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); -- cgit v1.2.3-54-g00ecf From 91ab7b01f883e75257189f71006ea1e7261a88dd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 May 2016 19:05:18 +0200 Subject: logind: don't include session lists in PropertyChanged messages If we have a lot of simultaneous sessions we really shouldn't send the full list of active sessions with each PropertyChanged message for user and seat objects, as that can become quite substantial data, we probably shouldn't dump on the bus on each login and logout. Note that the global list of sessions doesn't send out changes like this either, it only supports requesting the session list with ListSessions(). If cients want to get notified about sessions coming and going they should subscribe to SessionNew and SessionRemoved signals, and clients generally do that already. This is kind of an API break, but then again the fact that this was included was never documented. --- src/login/logind-seat-dbus.c | 2 +- src/login/logind-user-dbus.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 3cee10d009..f934a5326a 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -306,7 +306,7 @@ const sd_bus_vtable seat_vtable[] = { SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), - SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0), 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), diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index b73f9ea69e..af6392e025 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -245,7 +245,7 @@ const sd_bus_vtable user_vtable[] = { SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0), - SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0), 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), -- cgit v1.2.3-54-g00ecf From 6d97d3c648e590fe05a5fd12d06e0ddb9dc9da2f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 May 2016 19:22:30 +0200 Subject: logind: expose more configuration settings as bus properties --- src/login/logind-dbus.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 5067e5d1a8..d249bff2d9 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2533,8 +2533,11 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0), SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0), SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0), + SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0), + SD_BUS_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST), 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), -- cgit v1.2.3-54-g00ecf From c5a11ae268cf4188caf74d1acfd506a606e85967 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 May 2016 19:40:05 +0200 Subject: logind: enforce a limit on inhibitors we hand out For similar reasons as the recent addition of a limit on sessions. Note that we don't enforce a limit on inhibitors per-user currently, but there's an implicit one, since each inhibitor takes up one fd, and fds are limited via RLIMIT_NOFILE, and the limit on the number of processes per user. --- man/logind.conf.xml | 7 +++++++ src/login/logind-dbus.c | 23 +++++++++++++++++++++++ src/login/logind-gperf.gperf | 1 + src/login/logind.c | 1 + src/login/logind.conf.in | 1 + src/login/logind.h | 1 + 6 files changed, 34 insertions(+) (limited to 'src') diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 405dcf9041..fe92277a1f 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -296,6 +296,13 @@ memory as is needed. + + InhibitorsMax= + + Controls the maximum number of concurrent inhibitors to permit. Defaults to 8192 + (8K). + + SessionsMax= diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index d249bff2d9..0a84d75e24 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -283,6 +283,24 @@ static int property_get_current_sessions( return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions)); } +static int property_get_current_inhibitors( + 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; + + assert(bus); + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->inhibitors)); +} + static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *p = NULL; Manager *m = userdata; @@ -2463,6 +2481,9 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error if (r < 0) return r; + if (hashmap_size(m->inhibitors) >= m->inhibitors_max) + return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max); + do { id = mfree(id); @@ -2535,6 +2556,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0), SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_current_inhibitors, 0, 0), SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0), SD_BUS_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 1d57681260..6bd08adc05 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -34,5 +34,6 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec) Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size) Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc) +Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max) Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max) Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max) diff --git a/src/login/logind.c b/src/login/logind.c index 64bd1ca582..1cbc8f9fcc 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -64,6 +64,7 @@ static void manager_reset_config(Manager *m) { m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ m->user_tasks_max = UINT64_C(12288); m->sessions_max = UINT64_C(8192); + m->inhibitors_max = UINT64_C(8192); m->kill_user_processes = KILL_USER_PROCESSES; diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 6284218625..32c0844cb6 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -32,5 +32,6 @@ #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=yes +#InhibitorsMax=8192 #SessionsMax=8192 #UserTasksMax=12288 diff --git a/src/login/logind.h b/src/login/logind.h index 23c3e2963a..90431eb4b0 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -134,6 +134,7 @@ struct Manager { size_t runtime_dir_size; uint64_t user_tasks_max; uint64_t sessions_max; + uint64_t inhibitors_max; }; int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device); -- cgit v1.2.3-54-g00ecf From 64b5689647c7e12522ead1108037afe0b58b0dfd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 May 2016 22:49:25 +0200 Subject: logind: drop pointless UINT64_C() macro use --- src/login/logind.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/login/logind.c b/src/login/logind.c index 1cbc8f9fcc..caf149cfb7 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -62,9 +62,9 @@ static void manager_reset_config(Manager *m) { m->idle_action = HANDLE_IGNORE; m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ - m->user_tasks_max = UINT64_C(12288); - m->sessions_max = UINT64_C(8192); - m->inhibitors_max = UINT64_C(8192); + m->user_tasks_max = 12288; + m->sessions_max = 8192; + m->inhibitors_max = 8192; m->kill_user_processes = KILL_USER_PROCESSES; -- cgit v1.2.3-54-g00ecf From 93e2822684b37a4eeef03775a7a1f44a3055d7b2 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Fri, 6 May 2016 09:37:31 +0530 Subject: networkd: cleanup FOREACH_WORD --- src/libsystemd-network/network-internal.c | 77 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 99b3a1d01f..182d08c50d 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -225,8 +225,6 @@ int config_parse_ifnames(const char *unit, void *userdata) { char ***sv = data; - const char *word, *state; - size_t l; int r; assert(filename); @@ -234,22 +232,25 @@ int config_parse_ifnames(const char *unit, assert(rvalue); assert(data); - FOREACH_WORD(word, l, rvalue, state) { - char *n; + for (;;) { + _cleanup_free_ char *word = NULL; - n = strndup(word, l); - if (!n) - return log_oom(); + r = extract_first_word(&rvalue, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; - if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { + if (!ascii_is_valid(word) || strlen(word) >= IFNAMSIZ) { log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - free(n); return 0; } - r = strv_consume(sv, n); + r = strv_push(sv, word); if (r < 0) return log_oom(); + + word = NULL; } return 0; @@ -380,28 +381,28 @@ void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { int deserialize_in_addrs(struct in_addr **ret, const char *string) { _cleanup_free_ struct in_addr *addresses = NULL; int size = 0; - const char *word, *state; - size_t len; assert(ret); assert(string); - FOREACH_WORD(word, len, string, state) { - _cleanup_free_ char *addr_str = NULL; + for (;;) { + _cleanup_free_ char *word = NULL; struct in_addr *new_addresses; int r; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr)); if (!new_addresses) return -ENOMEM; else addresses = new_addresses; - addr_str = strndup(word, len); - if (!addr_str) - return -ENOMEM; - - r = inet_pton(AF_INET, addr_str, &(addresses[size])); + r = inet_pton(AF_INET, word, &(addresses[size])); if (r <= 0) continue; @@ -431,28 +432,28 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { _cleanup_free_ struct in6_addr *addresses = NULL; int size = 0; - const char *word, *state; - size_t len; assert(ret); assert(string); - FOREACH_WORD(word, len, string, state) { - _cleanup_free_ char *addr_str = NULL; + for (;;) { + _cleanup_free_ char *word = NULL; struct in6_addr *new_addresses; int r; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr)); if (!new_addresses) return -ENOMEM; else addresses = new_addresses; - addr_str = strndup(word, len); - if (!addr_str) - return -ENOMEM; - - r = inet_pton(AF_INET6, addr_str, &(addresses[size])); + r = inet_pton(AF_INET6, word, &(addresses[size])); if (r <= 0) continue; @@ -493,29 +494,29 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) { _cleanup_free_ struct sd_dhcp_route *routes = NULL; size_t size = 0, allocated = 0; - const char *word, *state; - size_t len; assert(ret); assert(ret_size); assert(ret_allocated); assert(string); - FOREACH_WORD(word, len, string, state) { - /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ - _cleanup_free_ char* entry = NULL; + /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ + for (;;) { + _cleanup_free_ char *word = NULL; char *tok, *tok_end; unsigned n; int r; - if (!GREEDY_REALLOC(routes, allocated, size + 1)) - return -ENOMEM; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; - entry = strndup(word, len); - if (!entry) + if (!GREEDY_REALLOC(routes, allocated, size + 1)) return -ENOMEM; - tok = entry; + tok = word; /* get the subnet */ tok_end = strchr(tok, '/'); -- cgit v1.2.3-54-g00ecf From 06976f5b2a052e2e2fb9c3dc3d72133c2ce58ddf Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Fri, 6 May 2016 09:49:49 +0530 Subject: networkd: route fix comment --- src/network/networkd-route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 01094b20bd..43f37266d8 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -512,7 +512,7 @@ int route_configure(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not set route table: %m"); - /* Table attribute to allow allow more than 256. */ + /* Table attribute to allow more than 256. */ r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table)); if (r < 0) return log_error_errno(r, "Could not append RTA_TABLE attribute: %m"); -- cgit v1.2.3-54-g00ecf From d24e561d96ba4a2272e26f6a245f032b32aa6992 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 12:16:58 +0200 Subject: core: split out selinux label retrieval logic into a function of its own This should bring no behavioural change. --- src/core/socket.c | 79 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index 016df40b8c..89bfb8b99f 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1241,6 +1241,45 @@ fail: return r; } +static int socket_determine_selinux_label(Socket *s, char **ret) { + ExecCommand *c; + int r; + + assert(s); + assert(ret); + + if (s->selinux_context_from_net) { + /* If this is requested, get label from the network label */ + + r = mac_selinux_get_our_label(ret); + if (r == -EOPNOTSUPP) + goto no_label; + + } else { + /* Otherwise, get it from the executable we are about to start */ + r = socket_instantiate_service(s); + if (r < 0) + return r; + + if (!UNIT_ISSET(s->service)) + goto no_label; + + c = SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]; + if (!c) + goto no_label; + + r = mac_selinux_get_create_label_from_exe(c->path, ret); + if (r == -EPERM || r == -EOPNOTSUPP) + goto no_label; + } + + return r; + +no_label: + *ret = NULL; + return 0; +} + static int socket_open_fds(Socket *s) { _cleanup_(mac_selinux_freep) char *label = NULL; bool know_label = false; @@ -1259,48 +1298,28 @@ static int socket_open_fds(Socket *s) { case SOCKET_SOCKET: if (!know_label) { - /* Figure out label, if we don't it know - * yet. We do it once, for the first - * socket where we need this and - * remember it for the rest. */ - - if (s->selinux_context_from_net) { - /* Get it from the network label */ - - r = mac_selinux_get_our_label(&label); - if (r < 0 && r != -EOPNOTSUPP) - goto rollback; - - } else { - /* Get it from the executable we are about to start */ - - r = socket_instantiate_service(s); - if (r < 0) - goto rollback; + /* Figure out label, if we don't it know yet. We do it once, for the first socket where + * we need this and remember it for the rest. */ - if (UNIT_ISSET(s->service) && - SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) { - r = mac_selinux_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label); - if (r < 0 && r != -EPERM && r != -EOPNOTSUPP) - goto rollback; - } - } + r = socket_determine_selinux_label(s, &label); + if (r < 0) + goto rollback; know_label = true; } /* Apply the socket protocol */ - switch(p->address.type) { + switch (p->address.type) { case SOCK_STREAM: case SOCK_SEQPACKET: - if (p->socket->socket_protocol == IPPROTO_SCTP) - p->address.protocol = p->socket->socket_protocol; + if (s->socket_protocol == IPPROTO_SCTP) + p->address.protocol = s->socket_protocol; break; case SOCK_DGRAM: - if (p->socket->socket_protocol == IPPROTO_UDPLITE) - p->address.protocol = p->socket->socket_protocol; + if (s->socket_protocol == IPPROTO_UDPLITE) + p->address.protocol = s->socket_protocol; break; } -- cgit v1.2.3-54-g00ecf From 01a8b4675739463b8d6abf0931099b244c6f072b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 13:01:17 +0200 Subject: core: don't implicit open missing socket fds on daemon reload Previously, when the daemon was reloaded and the configuration of a socket unit file was changed so that a different set of socket ports was defined for the socket we'd simply reopen the socket fds not yet open. This is problematic however, as this means the SOCKET_CHOWN state is not run for them, and thus their UID/GID is not corrected. With this change, don't open the missing file descriptors, but log about this issue, and ask the user to restart the socket explicit, to make sure all missing fds are opened. Fixes: #3171 --- src/core/socket.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index 89bfb8b99f..50912c33dd 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1463,6 +1463,34 @@ fail: return r; } +enum { + SOCKET_OPEN_NONE, + SOCKET_OPEN_SOME, + SOCKET_OPEN_ALL, +}; + +static int socket_check_open(Socket *s) { + bool have_open = false, have_closed = false; + SocketPort *p; + + assert(s); + + LIST_FOREACH(port, p, s->ports) { + if (p->fd < 0) + have_closed = true; + else + have_open = true; + + if (have_open && have_closed) + return SOCKET_OPEN_SOME; + } + + if (have_open) + return SOCKET_OPEN_ALL; + + return SOCKET_OPEN_NONE; +} + static void socket_set_state(Socket *s, SocketState state) { SocketState old_state; assert(s); @@ -1542,14 +1570,24 @@ static int socket_coldplug(Unit *u) { SOCKET_START_CHOWN, SOCKET_START_POST, SOCKET_LISTENING, - SOCKET_RUNNING, - SOCKET_STOP_PRE, - SOCKET_STOP_PRE_SIGTERM, - SOCKET_STOP_PRE_SIGKILL)) { - - r = socket_open_fds(s); - if (r < 0) - return r; + SOCKET_RUNNING)) { + + /* Originally, we used to simply reopen all sockets here that we didn't have file descriptors + * for. However, this is problematic, as we won't traverse throught the SOCKET_START_CHOWN state for + * them, and thus the UID/GID wouldn't be right. Hence, instead simply check if we have all fds open, + * and if there's a mismatch, warn loudly. */ + + r = socket_check_open(s); + if (r == SOCKET_OPEN_NONE) + log_unit_warning(UNIT(s), + "Socket unit configuration has changed while unit has been running, " + "no open socket file descriptor left. " + "The socket unit is not functional until restarted."); + else if (r == SOCKET_OPEN_SOME) + log_unit_warning(UNIT(s), + "Socket unit configuration has changed while unit has been running, " + "and some socket file descriptors have not been opened yet. " + "The socket unit is not fully functional until restarted."); } if (s->deserialized_state == SOCKET_LISTENING) { -- cgit v1.2.3-54-g00ecf From 60d9771c593e0702a892a4372443e63b38cdbcba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 13:29:26 +0200 Subject: core: rework how we flush incoming traffic when a socket unit goes down Previously, we'd simply close and reopen the socket file descriptors. This is problematic however, as we won't transition through the SOCKET_CHOWN state then, and thus the file ownership won't be correct for the sockets. Rework the flushing logic, and actually read any queued data from the sockets for flushing, and accept any queued messages and disconnect them. --- src/basic/io-util.c | 5 +++++ src/basic/socket-util.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/basic/socket-util.h | 2 ++ src/core/socket.c | 39 +++++++++++++++++++-------------------- 4 files changed, 66 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 0037a37f2a..cc6dfa8c1b 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -33,6 +33,11 @@ int flush_fd(int fd) { .events = POLLIN, }; + /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything + * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read + * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used + * was set to non-blocking too. */ + for (;;) { char buf[LINE_MAX]; ssize_t l; diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 0f38f9a0f3..c634f1d564 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -970,3 +971,42 @@ fallback: return (ssize_t) k; } + +int flush_accept(int fd) { + + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + int r; + + + /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */ + + for (;;) { + int cfd; + + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; + + return -errno; + + } else if (r == 0) + return 0; + + cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (cfd < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + return 0; + + return -errno; + } + + close(cfd); + } +} diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index d17a2f35f8..9f6a301368 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -135,5 +135,7 @@ int receive_one_fd(int transport_fd, int flags); ssize_t next_datagram_size_fd(int fd); +int flush_accept(int fd); + #define CMSG_FOREACH(cmsg, mh) \ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) diff --git a/src/core/socket.c b/src/core/socket.c index 50912c33dd..091567ed4f 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -28,7 +28,6 @@ #include #include -#include "sd-event.h" #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" @@ -38,6 +37,7 @@ #include "exit-status.h" #include "fd-util.h" #include "formats-util.h" +#include "io-util.h" #include "label.h" #include "log.h" #include "missing.h" @@ -1960,6 +1960,21 @@ fail: socket_enter_dead(s, SOCKET_FAILURE_RESOURCES); } +static void flush_ports(Socket *s) { + SocketPort *p; + + /* Flush all incoming traffic, regardless if actual bytes or new connections, so that this socket isn't busy + * anymore */ + + LIST_FOREACH(port, p, s->ports) { + if (p->fd < 0) + continue; + + (void) flush_accept(p->fd); + (void) flush_fd(p->fd); + } +} + static void socket_enter_running(Socket *s, int cfd) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; @@ -1969,31 +1984,15 @@ static void socket_enter_running(Socket *s, int cfd) { assert(s); - /* We don't take connections anymore if we are supposed to - * shut down anyway */ + /* We don't take connections anymore if we are supposed to shut down anyway */ if (unit_stop_pending(UNIT(s))) { log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled."); if (cfd >= 0) cfd = safe_close(cfd); - else { - /* Flush all sockets by closing and reopening them */ - socket_close_fds(s); - - r = socket_open_fds(s); - if (r < 0) { - 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), r, "Failed to watch sockets: %m"); - socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES); - } - } + else + flush_ports(s); return; } -- cgit v1.2.3-54-g00ecf From baa9ecc1ee63bd5d31adc74f0021d27a65ff3e77 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 16:58:01 +0200 Subject: systemctl: indentation fix --- src/systemctl/systemctl.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index bec4f31b39..7d0d4966d5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1711,21 +1711,22 @@ static int list_dependencies_one( const char *on; (void) get_state_one_unit(bus, *c, &active_state); + switch (active_state) { - case UNIT_ACTIVE: - case UNIT_RELOADING: - case UNIT_ACTIVATING: - on = ansi_highlight_green(); - break; - - case UNIT_INACTIVE: - case UNIT_DEACTIVATING: - on = ansi_normal(); - break; - - default: - on = ansi_highlight_red(); - break; + case UNIT_ACTIVE: + case UNIT_RELOADING: + case UNIT_ACTIVATING: + on = ansi_highlight_green(); + break; + + case UNIT_INACTIVE: + case UNIT_DEACTIVATING: + on = ansi_normal(); + break; + + default: + on = ansi_highlight_red(); + break; } printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal()); -- cgit v1.2.3-54-g00ecf From d05def163ea09bc2e617703546e5f9db95e27e5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 17:04:05 +0200 Subject: networkd: move the IAID configuration option into the [DHCP] section It's only relevant to DHCP, and it should be where the DUID is configured too. --- man/systemd.network.xml | 13 +++++++------ src/network/networkd-network-gperf.gperf | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 3ee80a64a0..40e40b8308 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -206,12 +206,6 @@ below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value. - - IAID= - - Identity Association Identifier for the interface, a 32-bit unsigned integer. - - Note that an interface without any static IPv6 addresses configured, and neither @@ -867,6 +861,13 @@ + + IAID= + + The DHCP Identity Association Identifier (IAID) for the interface, a 32-bit unsigned integer. + + + RequestBroadcast= diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 51e750b299..a9a541559e 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -27,7 +27,6 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) -Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) @@ -89,6 +88,7 @@ DHCP.DUIDType, config_parse_duid_type, DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) +DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) -- cgit v1.2.3-54-g00ecf From f76707da45a83df858e8752a2006a8c025da1a8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 18:22:22 +0200 Subject: core: update the right mtime after finishing writing of transient units (#3203) Fixes: #3194 --- src/core/unit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index 8153515e89..d8ab5781b0 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1247,7 +1247,7 @@ int unit_load(Unit *u) { fclose(u->transient_file); u->transient_file = NULL; - u->dropin_mtime = now(CLOCK_REALTIME); + u->fragment_mtime = now(CLOCK_REALTIME); } if (UNIT_VTABLE(u)->load) { -- cgit v1.2.3-54-g00ecf From 5d105c4a4ff94a61c38854d1388461b587cb55f3 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Fri, 6 May 2016 20:08:28 +0000 Subject: core: expose TriggerLimitIntervalUSec Before: $ systemctl show --property TriggerLimitIntervalSec test.socket TriggerLimitIntervalSec=2000000 After: $ systemctl show --property TriggerLimitIntervalUSec test.socket TriggerLimitIntervalUSec=2s --- src/core/dbus-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index bb09a515f8..961340608d 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -149,7 +149,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0), SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0), SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("TriggerLimitIntervalSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), -- cgit v1.2.3-54-g00ecf From 1745fa70e79e16954e8c0eb4c9c9b80eb9d5bfc0 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Fri, 6 May 2016 21:03:16 +0000 Subject: core: dump TriggerLimitIntervalSec and TriggerLimitBurst too --- src/core/socket.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/core/socket.c b/src/core/socket.c index 016df40b8c..d4b409ef53 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -690,6 +690,12 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sListenFIFO: %s\n", prefix, p->path); } + fprintf(f, + "%sTriggerLimitIntervalSec: %s\n" + "%sTriggerLimitBurst: %u\n", + prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->trigger_limit.interval, USEC_PER_SEC), + prefix, s->trigger_limit.burst); + exec_context_dump(&s->exec_context, f, prefix); kill_context_dump(&s->kill_context, f, prefix); -- cgit v1.2.3-54-g00ecf From 0da999fada225d2d74b62ec758cd437a3e2f6ebb Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 24 Apr 2016 21:50:25 -0400 Subject: systemctl: rewrite code to explicitly take care of n_units==0 case Coverity was complaing, but it was a false positive (CID #1354669). Nevertheless, it's better to rewrite the code so that units is never null. --- src/systemctl/systemctl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 7d0d4966d5..75248c83b3 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1422,8 +1422,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { n_units = hashmap_size(h); - units = new(UnitFileList, n_units); - if (!units && n_units > 0) { + units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */ + if (!units) { unit_file_list_free(h); return log_oom(); } @@ -1519,10 +1519,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list); output_unit_file_list(units, c); - if (install_client_side()) { + if (install_client_side()) for (unit = units; unit < units + c; unit++) free(unit->path); - } return 0; } -- cgit v1.2.3-54-g00ecf From 11690bcc5051e777ff2ff78e5bd6c089c6bd8aba Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 24 Apr 2016 21:54:52 -0400 Subject: systemctl: do not print header if no units will be listed "0 units listed." is still printed. --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 75248c83b3..639080bc66 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1355,7 +1355,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { } else id_cols = max_id_len; - if (!arg_no_legend) + if (!arg_no_legend && c > 0) printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE"); -- cgit v1.2.3-54-g00ecf From 94ad3616c8b01d07eb8bf4b111e81c89e6cd57f9 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 3 May 2016 15:57:36 -0400 Subject: core/mount: add helper function for mount states --- src/core/mount.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/core/mount.c b/src/core/mount.c index 5a8c26b9e1..665a60bb55 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -121,6 +121,20 @@ static bool mount_is_automount(const MountParameters *p) { "x-systemd.automount\0"); } +static bool mount_state_active(MountState state) { + return IN_SET(state, + MOUNT_MOUNTING, + MOUNT_MOUNTING_DONE, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, + MOUNT_MOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL); +} + static bool needs_quota(const MountParameters *p) { assert(p); @@ -591,16 +605,7 @@ static void mount_set_state(Mount *m, MountState state) { old_state = m->state; m->state = state; - if (state != MOUNT_MOUNTING && - state != MOUNT_MOUNTING_DONE && - state != MOUNT_REMOUNTING && - state != MOUNT_UNMOUNTING && - state != MOUNT_MOUNTING_SIGTERM && - state != MOUNT_MOUNTING_SIGKILL && - state != MOUNT_UNMOUNTING_SIGTERM && - state != MOUNT_UNMOUNTING_SIGKILL && - state != MOUNT_REMOUNTING_SIGTERM && - state != MOUNT_REMOUNTING_SIGKILL) { + if (!mount_state_active(state)) { m->timer_event_source = sd_event_source_unref(m->timer_event_source); mount_unwatch_control_pid(m); m->control_command = NULL; @@ -632,17 +637,7 @@ static int mount_coldplug(Unit *u) { if (m->control_pid > 0 && pid_is_unwaited(m->control_pid) && - IN_SET(new_state, - MOUNT_MOUNTING, - MOUNT_MOUNTING_DONE, - MOUNT_REMOUNTING, - MOUNT_UNMOUNTING, - MOUNT_MOUNTING_SIGTERM, - MOUNT_MOUNTING_SIGKILL, - MOUNT_UNMOUNTING_SIGTERM, - MOUNT_UNMOUNTING_SIGKILL, - MOUNT_REMOUNTING_SIGTERM, - MOUNT_REMOUNTING_SIGKILL)) { + mount_state_active(new_state)) { r = unit_watch_pid(UNIT(m), m->control_pid); if (r < 0) -- cgit v1.2.3-54-g00ecf From 0155928c3cc1792b50ab031d08b6152e2ae260f6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 4 May 2016 10:04:08 -0400 Subject: shared/install: simplify error handling conditionals in a few places --- src/shared/install.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index cc36da1853..f0b63506a9 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1247,18 +1247,15 @@ static int unit_file_search( return -ENOMEM; r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags); - if (r < 0) { - if (r != -ENOENT) - return r; - } else { + if (r >= 0) { info->path = path; path = NULL; return r; - } + } else if (r != -ENOENT) + return r; } 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 * possible to load template unit file. */ @@ -1277,14 +1274,12 @@ static int unit_file_search( return -ENOMEM; r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags); - if (r < 0) { - if (r != -ENOENT) - return r; - } else { + if (r >= 0) { info->path = path; path = NULL; return r; - } + } else if (r != -ENOENT) + return r; } } @@ -1355,13 +1350,10 @@ static int install_info_traverse( } r = install_info_follow(c, i, paths->root_dir, flags); - if (r < 0) { + if (r == -EXDEV) { _cleanup_free_ char *buffer = NULL; const char *bn; - if (r != -EXDEV) - return r; - /* Target has a different name, create a new * install info object for that, and continue * with that. */ @@ -1388,12 +1380,12 @@ static int install_info_traverse( if (r < 0) return r; + /* Try again, with the new target we found. */ r = unit_file_search(c, i, paths, flags); - if (r < 0) - return r; } - /* Try again, with the new target we found. */ + if (r < 0) + return r; } if (ret) -- cgit v1.2.3-54-g00ecf From ef76dff225a00008fe0edd1f528c9096f1a91179 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 20:58:32 +0200 Subject: util-lib: add new ifname_valid() call that validates interface names Make use of this in nspawn at a couple of places. A later commit should port more code over to this, including networkd. --- src/basic/socket-util.c | 38 ++++++++++++++++++++++++++++++++++++++ src/basic/socket-util.h | 2 ++ src/nspawn/nspawn-network.c | 6 ++++-- src/nspawn/nspawn.c | 24 ++++++++++++++++++++++++ src/test/test-socket-util.c | 25 +++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index c634f1d564..c8769a54f4 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -43,7 +43,9 @@ #include "socket-util.h" #include "string-table.h" #include "string-util.h" +#include "strv.h" #include "user-util.h" +#include "utf8.h" #include "util.h" int socket_address_parse(SocketAddress *a, const char *s) { @@ -795,6 +797,42 @@ static const char* const ip_tos_table[] = { DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); +bool ifname_valid(const char *p) { + bool numeric = true; + + /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources + * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We + * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */ + + if (isempty(p)) + return false; + + if (strlen(p) >= IFNAMSIZ) + return false; + + if (STR_IN_SET(p, ".", "..")) + return false; + + while (*p) { + if ((unsigned char) *p >= 127U) + return false; + + if ((unsigned char) *p <= 32U) + return false; + + if (*p == ':' || *p == '/') + return false; + + numeric = numeric && (*p >= '0' && *p <= '9'); + p++; + } + + if (numeric) + return false; + + return true; +} + int getpeercred(int fd, struct ucred *ucred) { socklen_t n = sizeof(struct ucred); struct ucred u; diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 160f7c484b..e9230e4a9f 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -123,6 +123,8 @@ int fd_inc_rcvbuf(int fd, size_t n); int ip_tos_to_string_alloc(int i, char **s); int ip_tos_from_string(const char *s); +bool ifname_valid(const char *p); + int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index f2b7e4dd79..9938fce503 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -29,6 +29,8 @@ #include "netlink-util.h" #include "nspawn-network.h" #include "siphash24.h" +#include "socket-util.h" +#include "stat-util.h" #include "string-util.h" #include "udev-util.h" #include "util.h" @@ -515,13 +517,13 @@ int veth_extra_parse(char ***l, const char *p) { r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS); if (r < 0) return r; - if (r == 0 || isempty(a)) + if (r == 0 || !ifname_valid(a)) return -EINVAL; r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS); if (r < 0) return r; - if (r == 0 || isempty(b)) { + if (r == 0 || !ifname_valid(b)) { free(b); b = strdup(a); if (!b) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3fc6cc955c..643f459851 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -467,6 +467,12 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NETWORK_BRIDGE: + + if (!ifname_valid(optarg)) { + log_error("Bridge interface name not valid: %s", optarg); + return -EINVAL; + } + r = free_and_strdup(&arg_network_bridge, optarg); if (r < 0) return log_oom(); @@ -489,6 +495,12 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NETWORK_INTERFACE: + + if (!ifname_valid(optarg)) { + log_error("Network interface name not valid: %s", optarg); + return -EINVAL; + } + if (strv_extend(&arg_network_interfaces, optarg) < 0) return log_oom(); @@ -497,6 +509,12 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NETWORK_MACVLAN: + + if (!ifname_valid(optarg)) { + log_error("MACVLAN network interface name not valid: %s", optarg); + return -EINVAL; + } + if (strv_extend(&arg_network_macvlan, optarg) < 0) return log_oom(); @@ -505,6 +523,12 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NETWORK_IPVLAN: + + if (!ifname_valid(optarg)) { + log_error("IPVLAN network interface name not valid: %s", optarg); + return -EINVAL; + } + if (strv_extend(&arg_network_ipvlan, optarg) < 0) return log_oom(); diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 9e01f3afd4..b480fdaa9c 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -27,6 +27,29 @@ #include "string-util.h" #include "util.h" +static void test_ifname_valid(void) { + assert(ifname_valid("foo")); + assert(ifname_valid("eth0")); + + assert(!ifname_valid("0")); + assert(!ifname_valid("99")); + assert(ifname_valid("a99")); + assert(ifname_valid("99a")); + + assert(!ifname_valid(NULL)); + assert(!ifname_valid("")); + assert(!ifname_valid(" ")); + assert(!ifname_valid(" foo")); + assert(!ifname_valid("bar\n")); + assert(!ifname_valid(".")); + assert(!ifname_valid("..")); + assert(ifname_valid("foo.bar")); + assert(!ifname_valid("x:y")); + + assert(ifname_valid("xxxxxxxxxxxxxxx")); + assert(!ifname_valid("xxxxxxxxxxxxxxxx")); +} + static void test_socket_address_parse(void) { SocketAddress a; @@ -362,6 +385,8 @@ int main(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); + test_ifname_valid(); + test_socket_address_parse(); test_socket_address_parse_netlink(); test_socket_address_equal(); -- cgit v1.2.3-54-g00ecf From 22b28dfdc78680a5c03e6af3b0ce6bc96f8174a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 21:00:27 +0200 Subject: nspawn: add new --network-zone= switch for automatically managed bridge devices This adds a new concept of network "zones", which are little more than bridge devices that are automatically managed by nspawn: when the first container referencing a bridge is started, the bridge device is created, when the last container referencing it is removed the bridge device is removed again. Besides this logic --network-zone= is pretty much identical to --network-bridge=. The usecase for this is to make it easy to run multiple related containers (think MySQL in one and Apache in another) in a common, named virtual Ethernet broadcast zone, that only exists as long as one of them is running, and fully automatically managed otherwise. --- src/nspawn/nspawn-gperf.gperf | 1 + src/nspawn/nspawn-network.c | 181 +++++++++++++++++++++++++++++++++--------- src/nspawn/nspawn-network.h | 3 +- src/nspawn/nspawn-settings.c | 40 +++++++++- src/nspawn/nspawn-settings.h | 2 + src/nspawn/nspawn.c | 51 +++++++++++- 6 files changed, 235 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 34e1310e29..1d3f0b40bf 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -40,4 +40,5 @@ Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth) Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0 Network.Bridge, config_parse_string, 0, offsetof(Settings, network_bridge) +Network.Zone, config_parse_network_zone, 0, 0 Network.Port, config_parse_expose_port, 0, 0 diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 9938fce503..8da47a2ca6 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -26,6 +26,7 @@ #include "alloc-util.h" #include "ether-addr-util.h" +#include "lockfile-util.h" #include "netlink-util.h" #include "nspawn-network.h" #include "siphash24.h" @@ -41,6 +42,30 @@ #define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59) #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f) +static int remove_one_link(sd_netlink *rtnl, const char *name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + if (isempty(name)) + return 0; + + r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0); + if (r < 0) + return log_error_errno(r, "Failed to allocate netlink message: %m"); + + r = sd_netlink_message_append_string(m, IFLA_IFNAME, name); + if (r < 0) + return log_error_errno(r, "Failed to add netlink interface name: %m"); + + r = sd_netlink_call(rtnl, m, 0, NULL); + if (r == -ENODEV) /* Already gone */ + return 0; + if (r < 0) + return log_error_errno(r, "Failed to remove interface %s: %m", name); + + return 1; +} + static int generate_mac( const char *machine_name, struct ether_addr *mac, @@ -240,45 +265,149 @@ int setup_veth_extra( return 0; } -int setup_bridge(const char *veth_name, const char *bridge_name) { +static int join_bridge(sd_netlink *rtnl, const char *veth_name, const char *bridge_name) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int r, bridge_ifi; + assert(rtnl); assert(veth_name); assert(bridge_name); bridge_ifi = (int) if_nametoindex(bridge_name); if (bridge_ifi <= 0) - return log_error_errno(errno, "Failed to resolve interface %s: %m", bridge_name); - - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); + return -errno; r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0); if (r < 0) - return log_error_errno(r, "Failed to allocate netlink message: %m"); + return r; r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP); if (r < 0) - return log_error_errno(r, "Failed to set IFF_UP flag: %m"); + return r; r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name); if (r < 0) - return log_error_errno(r, "Failed to add netlink interface name field: %m"); + return r; r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi); if (r < 0) - return log_error_errno(r, "Failed to add netlink master field: %m"); + return r; r = sd_netlink_call(rtnl, m, 0, NULL); if (r < 0) - return log_error_errno(r, "Failed to add veth interface to bridge: %m"); + return r; return bridge_ifi; } +static int create_bridge(sd_netlink *rtnl, const char *bridge_name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, IFLA_IFNAME, bridge_name); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(m, IFLA_LINKINFO); + if (r < 0) + return r; + + r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "bridge"); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); + if (r < 0) + return r; + + r = sd_netlink_call(rtnl, m, 0, NULL); + if (r < 0) + return r; + + return 0; +} + +int setup_bridge(const char *veth_name, const char *bridge_name, bool create) { + _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + int r, bridge_ifi; + unsigned n = 0; + + assert(veth_name); + assert(bridge_name); + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + if (create) { + /* We take a system-wide lock here, so that we can safely check whether there's still a member in the + * bridge before removing it, without risking interferance from other nspawn instances. */ + + r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock); + if (r < 0) + return log_error_errno(r, "Failed to take network zone lock: %m"); + } + + for (;;) { + bridge_ifi = join_bridge(rtnl, veth_name, bridge_name); + if (bridge_ifi >= 0) + return bridge_ifi; + if (bridge_ifi != -ENODEV || !create || n > 10) + return log_error_errno(bridge_ifi, "Failed to add interface %s to bridge %s: %m", veth_name, bridge_name); + + /* Count attempts, so that we don't enter an endless loop here. */ + n++; + + /* The bridge doesn't exist yet. Let's create it */ + r = create_bridge(rtnl, bridge_name); + if (r < 0) + return log_error_errno(r, "Failed to create bridge interface %s: %m", bridge_name); + + /* Try again, now that the bridge exists */ + } +} + +int remove_bridge(const char *bridge_name) { + _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + const char *path; + int r; + + /* Removes the specified bridge, but only if it is currently empty */ + + if (isempty(bridge_name)) + return 0; + + r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock); + if (r < 0) + return log_error_errno(r, "Failed to take network zone lock: %m"); + + path = strjoina("/sys/class/net/", bridge_name, "/brif"); + + r = dir_is_empty(path); + if (r == -ENOENT) /* Already gone? */ + return 0; + if (r < 0) + return log_error_errno(r, "Can't detect if bridge %s is empty: %m", bridge_name); + if (r == 0) /* Still populated, leave it around */ + return 0; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + return remove_one_link(rtnl, bridge_name); +} + static int parse_interface(struct udev *udev, const char *name) { _cleanup_udev_device_unref_ struct udev_device *d = NULL; char ifi_str[2 + DECIMAL_STR_MAX(int)]; @@ -541,30 +670,6 @@ int veth_extra_parse(char ***l, const char *p) { return 0; } -static int remove_one_veth_link(sd_netlink *rtnl, const char *name) { - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - int r; - - if (isempty(name)) - return 0; - - r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0); - if (r < 0) - return log_error_errno(r, "Failed to allocate netlink message: %m"); - - r = sd_netlink_message_append_string(m, IFLA_IFNAME, name); - if (r < 0) - return log_error_errno(r, "Failed to add netlink interface name: %m"); - - r = sd_netlink_call(rtnl, m, 0, NULL); - if (r == -ENODEV) /* Already gone */ - return 0; - if (r < 0) - return log_error_errno(r, "Failed to remove veth interface %s: %m", name); - - return 1; -} - int remove_veth_links(const char *primary, char **pairs) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; char **a, **b; @@ -580,10 +685,10 @@ int remove_veth_links(const char *primary, char **pairs) { if (r < 0) return log_error_errno(r, "Failed to connect to netlink: %m"); - remove_one_veth_link(rtnl, primary); + remove_one_link(rtnl, primary); STRV_FOREACH_PAIR(a, b, pairs) - remove_one_veth_link(rtnl, *a); + remove_one_link(rtnl, *a); return 0; } diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index c5036ab470..3d8861e1e5 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -26,7 +26,8 @@ int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge); int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs); -int setup_bridge(const char *veth_name, const char *bridge_name); +int setup_bridge(const char *veth_name, const char *bridge_name, bool create); +int remove_bridge(const char *bridge_name); int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces); int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces); diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index b98a79fd09..5f1522cfb6 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -24,10 +24,11 @@ #include "nspawn-settings.h" #include "parse-util.h" #include "process-util.h" +#include "socket-util.h" +#include "string-util.h" #include "strv.h" #include "user-util.h" #include "util.h" -#include "string-util.h" int settings_load(FILE *f, const char *path, Settings **ret) { _cleanup_(settings_freep) Settings *s = NULL; @@ -96,6 +97,7 @@ Settings* settings_free(Settings *s) { strv_free(s->network_ipvlan); strv_free(s->network_veth_extra); free(s->network_bridge); + free(s->network_zone); expose_port_free_all(s->expose_ports); custom_mount_free_all(s->custom_mounts, s->n_custom_mounts); @@ -111,6 +113,7 @@ bool settings_private_network(Settings *s) { s->private_network > 0 || s->network_veth > 0 || s->network_bridge || + s->network_zone || s->network_interfaces || s->network_macvlan || s->network_ipvlan || @@ -122,7 +125,8 @@ bool settings_network_veth(Settings *s) { return s->network_veth > 0 || - s->network_bridge; + s->network_bridge || + s->network_zone; } DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode"); @@ -319,6 +323,38 @@ int config_parse_veth_extra( return 0; } +int config_parse_network_zone( + 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) { + + Settings *settings = data; + _cleanup_free_ char *j = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + + j = strappend("vz-", rvalue); + if (!ifname_valid(j)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid network zone name %s, ignoring: %m", rvalue); + return 0; + } + + free(settings->network_zone); + settings->network_zone = j; + j = NULL; + + return 0; +} + int config_parse_boot( const char *unit, const char *filename, diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index e12e91b886..1c47e37912 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -85,6 +85,7 @@ typedef struct Settings { int private_network; int network_veth; char *network_bridge; + char *network_zone; char **network_interfaces; char **network_macvlan; char **network_ipvlan; @@ -109,6 +110,7 @@ int config_parse_volatile_mode(const char *unit, const char *filename, unsigned int config_parse_bind(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_tmpfs(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_veth_extra(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_network_zone(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_boot(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_pid2(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_private_users(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/nspawn/nspawn.c b/src/nspawn/nspawn.c index 643f459851..efda7d66d7 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -176,6 +176,7 @@ static char **arg_network_ipvlan = NULL; static bool arg_network_veth = false; static char **arg_network_veth_extra = NULL; static char *arg_network_bridge = NULL; +static char *arg_network_zone = NULL; static unsigned long arg_personality = PERSONALITY_INVALID; static char *arg_image = NULL; static VolatileMode arg_volatile_mode = VOLATILE_NO; @@ -234,6 +235,8 @@ static void help(void) { " Add a virtual Ethernet connection between host\n" " and container and add it to an existing bridge on\n" " the host\n" + " --network-zone=NAME Add a virtual Ethernet connection to the container,\n" + " and add it to an automatically managed bridge interface\n" " -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n" " Expose a container IP port on the host\n" " -Z --selinux-context=SECLABEL\n" @@ -357,6 +360,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_NETWORK_MACVLAN, ARG_NETWORK_IPVLAN, ARG_NETWORK_BRIDGE, + ARG_NETWORK_ZONE, ARG_NETWORK_VETH_EXTRA, ARG_PERSONALITY, ARG_VOLATILE, @@ -404,6 +408,7 @@ static int parse_argv(int argc, char *argv[]) { { "network-veth", no_argument, NULL, 'n' }, { "network-veth-extra", required_argument, NULL, ARG_NETWORK_VETH_EXTRA}, { "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE }, + { "network-zone", required_argument, NULL, ARG_NETWORK_ZONE }, { "personality", required_argument, NULL, ARG_PERSONALITY }, { "image", required_argument, NULL, 'i' }, { "volatile", optional_argument, NULL, ARG_VOLATILE }, @@ -466,6 +471,28 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_USER; break; + case ARG_NETWORK_ZONE: { + char *j; + + j = strappend("vz-", optarg); + if (!j) + return log_oom(); + + if (!ifname_valid(j)) { + log_error("Network zone name not valid: %s", j); + free(j); + return -EINVAL; + } + + free(arg_network_zone); + arg_network_zone = j; + + arg_network_veth = true; + arg_private_network = true; + arg_settings_mask |= SETTING_NETWORK; + break; + } + case ARG_NETWORK_BRIDGE: if (!ifname_valid(optarg)) { @@ -1027,6 +1054,11 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } + if (arg_network_bridge && arg_network_zone) { + log_error("--network-bridge= and --network-zone= may not be combined."); + return -EINVAL; + } + if (argc > optind) { arg_parameters = strv_copy(argv + optind); if (!arg_parameters) @@ -3295,6 +3327,7 @@ static int load_settings(void) { (settings->private_network >= 0 || settings->network_veth >= 0 || settings->network_bridge || + settings->network_zone || settings->network_interfaces || settings->network_macvlan || settings->network_ipvlan || @@ -3325,6 +3358,10 @@ static int load_settings(void) { free(arg_network_bridge); arg_network_bridge = settings->network_bridge; settings->network_bridge = NULL; + + free(arg_network_zone); + arg_network_zone = settings->network_zone; + settings->network_zone = NULL; } } @@ -3824,14 +3861,23 @@ int main(int argc, char *argv[]) { goto finish; if (arg_network_veth) { - r = setup_veth(arg_machine, pid, veth_name, !!arg_network_bridge); + r = setup_veth(arg_machine, pid, veth_name, + arg_network_bridge || arg_network_zone); if (r < 0) goto finish; else if (r > 0) ifi = r; if (arg_network_bridge) { - r = setup_bridge(veth_name, arg_network_bridge); + /* Add the interface to a bridge */ + r = setup_bridge(veth_name, arg_network_bridge, false); + if (r < 0) + goto finish; + if (r > 0) + ifi = r; + } else if (arg_network_zone) { + /* Add the interface to a bridge, possibly creating it */ + r = setup_bridge(veth_name, arg_network_zone, true); if (r < 0) goto finish; if (r > 0) @@ -4039,6 +4085,7 @@ finish: expose_port_flush(arg_expose_ports, &exposed); (void) remove_veth_links(veth_name, arg_network_veth_extra); + (void) remove_bridge(arg_network_zone); free(arg_directory); free(arg_template); -- cgit v1.2.3-54-g00ecf From d31645adefb3462d168b44bb950f92654c395021 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 21:20:59 +0200 Subject: tree-wide: port more code to use ifname_valid() --- src/core/load-fragment.c | 26 ++++++++----- src/libsystemd-network/network-internal.c | 64 +++++++------------------------ src/libsystemd-network/network-internal.h | 4 -- src/network/networkd-address.c | 27 +++++-------- src/nspawn/nspawn-gperf.gperf | 2 +- src/shared/conf-parser.c | 38 ++++++++++++++++++ src/shared/conf-parser.h | 1 + src/shared/firewall-util.c | 6 +-- 8 files changed, 83 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 1a8c03904c..a12dd38c60 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -732,16 +732,17 @@ int config_parse_exec( DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type"); DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier"); -int config_parse_socket_bindtodevice(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_socket_bindtodevice( + 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) { Socket *s = data; char *n; @@ -752,6 +753,11 @@ int config_parse_socket_bindtodevice(const char* unit, assert(data); if (rvalue[0] && !streq(rvalue, "*")) { + if (!ifname_valid(rvalue)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue); + return 0; + } + n = strdup(rvalue); if (!n) return log_oom(); diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 182d08c50d..929f066fa0 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -32,6 +32,7 @@ #include "network-internal.h" #include "parse-util.h" #include "siphash24.h" +#include "socket-util.h" #include "string-util.h" #include "strv.h" #include "utf8.h" @@ -175,54 +176,17 @@ int config_parse_net_condition(const char *unit, return 0; } -int config_parse_ifname(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) { - - char **s = data; - _cleanup_free_ char *n = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return log_oom(); - - if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - return 0; - } - - free(*s); - if (*n) { - *s = n; - n = NULL; - } else - *s = NULL; - - return 0; -} - -int config_parse_ifnames(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_ifnames( + 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) { char ***sv = data; int r; @@ -241,8 +205,8 @@ int config_parse_ifnames(const char *unit, if (r == 0) break; - if (!ascii_is_valid(word) || strlen(word) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + if (!ifname_valid(word)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue); return 0; } diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 72432774d7..5bcd577167 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -50,10 +50,6 @@ int config_parse_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_ifname(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_ifnames(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-address.c b/src/network/networkd-address.c index 8b52a1f742..4eb0d927a6 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -27,6 +27,7 @@ #include "networkd.h" #include "parse-util.h" #include "set.h" +#include "socket-util.h" #include "string-util.h" #include "utf8.h" #include "util.h" @@ -726,7 +727,8 @@ int config_parse_address(const char *unit, return 0; } -int config_parse_label(const char *unit, +int config_parse_label( + const char *unit, const char *filename, unsigned line, const char *section, @@ -736,9 +738,9 @@ int config_parse_label(const char *unit, const char *rvalue, void *data, void *userdata) { - Network *network = userdata; + _cleanup_address_free_ Address *n = NULL; - char *label; + Network *network = userdata; int r; assert(filename); @@ -751,23 +753,14 @@ int config_parse_label(const char *unit, if (r < 0) return r; - label = strdup(rvalue); - if (!label) - return log_oom(); - - if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - free(label); + if (!ifname_valid(rvalue)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not valid or too long, ignoring assignment: %s", rvalue); return 0; } - free(n->label); - if (*label) - n->label = label; - else { - free(label); - n->label = NULL; - } + r = free_and_strdup(&n->label, rvalue); + if (r < 0) + return log_oom(); n = NULL; diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 1d3f0b40bf..2b5d452662 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -39,6 +39,6 @@ Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan) Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth) Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0 -Network.Bridge, config_parse_string, 0, offsetof(Settings, network_bridge) +Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge) Network.Zone, config_parse_network_zone, 0, 0 Network.Port, config_parse_expose_port, 0, 0 diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 1141f9964f..83be79a4f5 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -37,6 +37,7 @@ #include "path-util.h" #include "process-util.h" #include "signal-util.h" +#include "socket-util.h" #include "string-util.h" #include "strv.h" #include "syslog-util.h" @@ -873,3 +874,40 @@ int config_parse_personality( *personality = p; return 0; } + +int config_parse_ifname( + 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) { + + char **s = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *s = mfree(*s); + return 0; + } + + if (!ifname_valid(rvalue)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue); + return 0; + } + + r = free_and_strdup(s, rvalue); + if (r < 0) + return log_oom(); + + return 0; +} diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 73fb132413..f6964e3fd4 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -125,6 +125,7 @@ int config_parse_log_facility(const char *unit, const char *filename, unsigned l 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 config_parse_signal(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_personality(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_ifname(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); #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ int function(const char *unit, \ diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index ade2de7727..97865eac4a 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -44,6 +44,7 @@ #include "firewall-util.h" #include "in-addr-util.h" #include "macro.h" +#include "socket-util.h" DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free); @@ -59,10 +60,9 @@ static int entry_fill_basics( assert(entry); - if (out_interface && strlen(out_interface) >= IFNAMSIZ) + if (out_interface && !ifname_valid(out_interface)) return -EINVAL; - - if (in_interface && strlen(in_interface) >= IFNAMSIZ) + if (in_interface && !ifname_valid(in_interface)) return -EINVAL; entry->ip.proto = protocol; -- cgit v1.2.3-54-g00ecf From 7272b25e163d1c7395ff0da1397511c7946c0873 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 6 May 2016 21:27:36 +0200 Subject: networkd: reworkd LLDP emission to allow control of propagation level This allows selecting the propagation level of emitted LLDP packets (specifically: the destination MAC address of the packets). This is useful because it allows generating LLDP packets that optionally cross certain types of bridges. See 802.11ab-2009, Table 7-1 for details. --- man/systemd.network.xml | 28 ++++++--- src/network/networkd-link.c | 16 ++--- src/network/networkd-link.h | 2 +- src/network/networkd-lldp-tx.c | 102 +++++++++++++++++++++++++------ src/network/networkd-lldp-tx.h | 14 ++++- src/network/networkd-network-gperf.gperf | 2 +- src/network/networkd-network.h | 3 +- 7 files changed, 126 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 6d45d6c807..70e3804746 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -363,18 +363,26 @@ EmitLLDP= - Controls support for Ethernet LLDP packet emission. Accepts a boolean parameter and defaults to - false. If enabled a short LLDP packet with information about the local system is sent out in regular - intervals on the link. The LLDP packet will contain information about the local host name, the local - machine ID (as stored in - machine-id5) and the + Controls support for Ethernet LLDP packet emission. Accepts a boolean parameter or the special values + nearest-bridge, non-tpmr-bridge and + customer-bridge. Defaults to false, which turns off LLDP packet emission. If not false, + a short LLDP packet with information about the local system is sent out in regular intervals on the + link. The LLDP packet will contain information about the local host name, the local machine ID (as stored + in machine-id5) and the local interface name, as well as the pretty hostname of the system (as set in machine-info5). LLDP - emission is only available on Ethernet links. Note that this setting passed data suitable for - identification of host to the network and should thus not be used on untrusted networks, where such - identification data should not be made available. Use this option to enable other systems to identify on - which interface they are connected to this system. See LLDP= above for an option to - enable LLDP reception. + emission is only available on Ethernet links. Note that this setting passes data suitable for + identification of host to the network and should thus not be enabled on untrusted networks, where such + identification data should not be made available. Use this option to permit other systems to identify on + which interfaces they are connected to this system. The three special values control propagation of the + LLDP packets. The nearest-bridge setting permits propagation only to the nearest + connected bridge, non-tpmr-bridge permits propagation across Two-Port MAC Relays, but + not any other bridges, and customer-bridge permits propagation until a customer bridge + is reached. For details about these concepts, see IEEE 802.1AB-2009. Note that + configuring this setting to true is equivalent to nearest-bridge, the recommended and + most restricted level of propagation. See LLDP= above for an option to enable LLDP + reception. diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c646af1f1a..4e3f62cf51 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -131,7 +131,7 @@ static bool link_lldp_rx_enabled(Link *link) { return link->network->lldp_mode != LLDP_MODE_NO; } -static bool link_lldp_tx_enabled(Link *link) { +static bool link_lldp_emit_enabled(Link *link) { assert(link); if (link->flags & IFF_LOOPBACK) @@ -143,7 +143,7 @@ static bool link_lldp_tx_enabled(Link *link) { if (!link->network) return false; - return link->network->lldp_emit; + return link->network->lldp_emit != LLDP_EMIT_NO; } static bool link_ipv4_forward_enabled(Link *link) { @@ -491,7 +491,7 @@ static void link_free(Link *link) { sd_dhcp_client_unref(link->dhcp_client); sd_dhcp_lease_unref(link->dhcp_lease); - link_lldp_tx_stop(link); + link_lldp_emit_stop(link); free(link->lease_file); @@ -618,7 +618,7 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } - link_lldp_tx_stop(link); + link_lldp_emit_stop(link); return r; } @@ -1411,12 +1411,12 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n (void) link_lldp_save(link); - if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) { + if (link_lldp_emit_enabled(link) && event == SD_LLDP_EVENT_ADDED) { /* If we received information about a new neighbor, restart the LLDP "fast" logic */ log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission."); - r = link_lldp_tx_start(link); + r = link_lldp_emit_start(link); if (r < 0) log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m"); } @@ -1501,8 +1501,8 @@ static int link_acquire_conf(Link *link) { return r; } - if (link_lldp_tx_enabled(link)) { - r = link_lldp_tx_start(link); + if (link_lldp_emit_enabled(link)) { + r = link_lldp_emit_start(link); if (r < 0) return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m"); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 86139be557..14c4a02c7e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -121,7 +121,7 @@ typedef struct Link { /* This is about LLDP transmission */ unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */ - sd_event_source *lldp_tx_event_source; + sd_event_source *lldp_emit_event_source; Hashmap *bound_by_links; Hashmap *bound_to_links; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index 03b694c3f1..3aa768388b 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -25,16 +25,14 @@ #include "fd-util.h" #include "fileio.h" #include "hostname-util.h" +#include "networkd-lldp-tx.h" +#include "networkd.h" +#include "parse-util.h" #include "random-util.h" #include "socket-util.h" #include "string-util.h" #include "unaligned.h" -#include "networkd.h" -#include "networkd-lldp-tx.h" - -#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } - /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */ #define LLDP_TX_FAST_INIT 4U @@ -50,6 +48,12 @@ /* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */ #define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2) +static const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = { + [LLDP_EMIT_NEAREST_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }}, + [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }}, + [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }}, +}; + static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) { assert(p); @@ -66,6 +70,7 @@ static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) { } static int lldp_make_packet( + LLDPEmit mode, const struct ether_addr *hwaddr, const char *machine_id, const char *ifname, @@ -84,6 +89,8 @@ static int lldp_make_packet( size_t l; int r; + assert(mode > LLDP_EMIT_NO); + assert(mode < _LLDP_EMIT_MAX); assert(hwaddr); assert(machine_id); assert(ifname); @@ -132,7 +139,7 @@ static int lldp_make_packet( h = (struct ether_header*) packet; h->ether_type = htobe16(ETHERTYPE_LLDP); - memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN); + memcpy(h->ether_dhost, lldp_multicast_addr + mode, ETH_ALEN); memcpy(h->ether_shost, hwaddr, ETH_ALEN); p = (uint8_t*) packet + sizeof(struct ether_header); @@ -197,22 +204,28 @@ static int lldp_make_packet( return 0; } -static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) { +static int lldp_send_packet( + int ifindex, + const struct ether_addr *address, + const void *packet, + size_t packet_size) { union sockaddr_union sa = { .ll.sll_family = AF_PACKET, .ll.sll_protocol = htobe16(ETHERTYPE_LLDP), .ll.sll_ifindex = ifindex, .ll.sll_halen = ETH_ALEN, - .ll.sll_addr = LLDP_MULTICAST_ADDR, }; _cleanup_close_ int fd = -1; ssize_t l; assert(ifindex > 0); + assert(address); assert(packet || packet_size <= 0); + memcpy(sa.ll.sll_addr, address, ETH_ALEN); + fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW); if (fd < 0) return -errno; @@ -237,6 +250,13 @@ static int link_send_lldp(Link *link) { usec_t ttl; int r; + assert(link); + + if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) + return 0; + + assert(link->network->lldp_emit < _LLDP_EMIT_MAX); + r = sd_id128_get_machine(&machine_id); if (r < 0) return r; @@ -251,7 +271,8 @@ static int link_send_lldp(Link *link) { SD_LLDP_SYSTEM_CAPABILITIES_ROUTER : SD_LLDP_SYSTEM_CAPABILITIES_STATION; - r = lldp_make_packet(&link->mac, + r = lldp_make_packet(link->network->lldp_emit, + &link->mac, sd_id128_to_string(machine_id, machine_id_string), link->ifname, (uint16_t) ttl, @@ -264,7 +285,7 @@ static int link_send_lldp(Link *link) { if (r < 0) return r; - return lldp_send_packet(link->ifindex, packet, packet_size); + return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size); } static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { @@ -300,12 +321,17 @@ static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) { return 0; } -int link_lldp_tx_start(Link *link) { +int link_lldp_emit_start(Link *link) { usec_t next; int r; assert(link); + if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) { + link_lldp_emit_stop(link); + return 0; + } + /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */ link->lldp_tx_fast = LLDP_TX_FAST_INIT; @@ -313,22 +339,22 @@ int link_lldp_tx_start(Link *link) { next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC), (usec_t) random_u64() % LLDP_JITTER_USEC); - if (link->lldp_tx_event_source) { + if (link->lldp_emit_event_source) { usec_t old; /* Lower the timeout, maybe */ - r = sd_event_source_get_time(link->lldp_tx_event_source, &old); + r = sd_event_source_get_time(link->lldp_emit_event_source, &old); if (r < 0) return r; if (old <= next) return 0; - return sd_event_source_set_time(link->lldp_tx_event_source, next); + return sd_event_source_set_time(link->lldp_emit_event_source, next); } else { r = sd_event_add_time( link->manager->event, - &link->lldp_tx_event_source, + &link->lldp_emit_event_source, clock_boottime_or_monotonic(), next, 0, @@ -337,14 +363,54 @@ int link_lldp_tx_start(Link *link) { if (r < 0) return r; - (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx"); + (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx"); } return 0; } -void link_lldp_tx_stop(Link *link) { +void link_lldp_emit_stop(Link *link) { assert(link); - link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source); + link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source); +} + +int config_parse_lldp_emit( + 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) { + + LLDPEmit *emit = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) + *emit = LLDP_EMIT_NO; + else if (streq(rvalue, "nearest-bridge")) + *emit = LLDP_EMIT_NEAREST_BRIDGE; + else if (streq(rvalue, "non-tpmr-bridge")) + *emit = LLDP_EMIT_NON_TPMR_BRIDGE; + else if (streq(rvalue, "customer-bridge")) + *emit = LLDP_EMIT_CUSTOMER_BRIDGE; + else { + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue); + return 0; + } + + *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO; + } + + return 0; } diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h index 8c7f403005..4680c9d950 100644 --- a/src/network/networkd-lldp-tx.h +++ b/src/network/networkd-lldp-tx.h @@ -21,5 +21,15 @@ #include "networkd-link.h" -int link_lldp_tx_start(Link *link); -void link_lldp_tx_stop(Link *link); +typedef enum LLDPEmit { + LLDP_EMIT_NO, + LLDP_EMIT_NEAREST_BRIDGE, + LLDP_EMIT_NON_TPMR_BRIDGE, + LLDP_EMIT_CUSTOMER_BRIDGE, + _LLDP_EMIT_MAX, +} LLDPEmit; + +int link_lldp_emit_start(Link *link); +void link_lldp_emit_stop(Link *link); + +int config_parse_lldp_emit(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-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a9a541559e..4425ee4e2f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -42,7 +42,7 @@ Network.LinkLocalAddressing, config_parse_address_family_boolean, Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) -Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit) +Network.EmitLLDP, config_parse_lldp_emit, 0, offsetof(Network, lldp_emit) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index ff2414efdd..4cd0fa4ab8 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -29,6 +29,7 @@ #include "networkd-address.h" #include "networkd-fdb.h" +#include "networkd-lldp-tx.h" #include "networkd-netdev.h" #include "networkd-route.h" #include "networkd-util.h" @@ -161,7 +162,7 @@ struct Network { DUID duid; LLDPMode lldp_mode; /* LLDP reception */ - bool lldp_emit; /* LLDP transmission */ + LLDPEmit lldp_emit; /* LLDP transmission */ LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); -- cgit v1.2.3-54-g00ecf From a9dd908d093e76f5c19829b6aadd0868bb663c9e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 9 May 2016 15:42:23 +0200 Subject: network: Make sure we log about parse errors for ifname lists Fix-up for 93e2822684b37a4eeef03775a7a1f44a3055d7b2 --- src/libsystemd-network/network-internal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 929f066fa0..2badcdff58 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -200,8 +200,10 @@ int config_parse_ifnames( _cleanup_free_ char *word = NULL; r = extract_first_word(&rvalue, &word, NULL, 0); - if (r < 0) - return r; + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue); + return 0; + } if (r == 0) break; -- cgit v1.2.3-54-g00ecf From 7513c5b89ffbc0f86befca1d76917cd1aa6ff197 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 9 May 2016 15:43:51 +0200 Subject: nspawn: only remove veth links we created ourselves Let's make sure we don't remove veth links that existed before nspawn was invoked. https://github.com/systemd/systemd/pull/3209#discussion_r62439999 --- src/nspawn/nspawn.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index efda7d66d7..0479389682 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3407,7 +3407,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; + bool interactive, veth_created = false; log_parse_environment(); log_open(); @@ -3889,6 +3889,12 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; + /* We created the primary and extra veth links now; let's remember this, so that we know to + remove them later on. Note that we don't bother with removing veth links that were created + here when their setup failed half-way, because in that case the kernel should be able to + remove them on its own, since they cannot be referenced by anything yet. */ + veth_created = true; + r = setup_macvlan(arg_machine, pid, arg_network_macvlan); if (r < 0) goto finish; @@ -4051,7 +4057,9 @@ int main(int argc, char *argv[]) { } expose_port_flush(arg_expose_ports, &exposed); + (void) remove_veth_links(veth_name, arg_network_veth_extra); + veth_created = false; } finish: @@ -4084,7 +4092,9 @@ finish: } expose_port_flush(arg_expose_ports, &exposed); - (void) remove_veth_links(veth_name, arg_network_veth_extra); + + if (veth_created) + (void) remove_veth_links(veth_name, arg_network_veth_extra); (void) remove_bridge(arg_network_zone); free(arg_directory); -- cgit v1.2.3-54-g00ecf From 64f9280ef0cd38e5c548ebfcc9a8e05d977234a5 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 4 May 2016 10:09:52 -0400 Subject: shared/install: add some more debug messages and comments $ systemctl --root=/ preset foobar.service Cannot find unit foobar.service. Failed to preset: No such file or directory. $ systemctl --root=/ preset foobar@.service Cannot find unit foobar@.service. Failed to preset: No such file or directory. $ systemctl --root=/ preset foobar@blah.service Cannot find unit foobar@blah.service or foobar@.service. Failed to preset: No such file or directory. --- src/shared/install.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index f0b63506a9..427e5eaf7b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -116,6 +116,14 @@ bool unit_type_may_template(UnitType type) { UNIT_PATH); } +static const char *unit_file_type_table[_UNIT_FILE_TYPE_MAX] = { + [UNIT_FILE_TYPE_REGULAR] = "regular", + [UNIT_FILE_TYPE_SYMLINK] = "symlink", + [UNIT_FILE_TYPE_MASKED] = "masked", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType); + static int in_search_path(const LookupPaths *p, const char *path) { _cleanup_free_ char *parent = NULL; char **i; @@ -1223,6 +1231,7 @@ static int unit_file_search( const LookupPaths *paths, SearchFlags flags) { + _cleanup_free_ char *template = NULL; char **p; int r; @@ -1260,8 +1269,6 @@ static int unit_file_search( * enablement was requested. We will check if it is * possible to load template unit file. */ - _cleanup_free_ char *template = NULL; - r = unit_name_template(info->name, &template); if (r < 0) return r; @@ -1283,6 +1290,7 @@ static int unit_file_search( } } + log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template)); return -ENOENT; } @@ -1314,6 +1322,11 @@ static int install_info_follow( return unit_file_load_or_readlink(c, i, i->path, root_dir, flags); } +/** + * Search for the unit file. If the unit name is a symlink, + * follow the symlink to the target, maybe more than once. + * Propagate the instance name if present. + */ static int install_info_traverse( UnitFileScope scope, InstallContext *c, @@ -1684,8 +1697,12 @@ static int install_context_mark_for_removal( if (r < 0) return r; - if (i->type != UNIT_FILE_TYPE_REGULAR) + if (i->type != UNIT_FILE_TYPE_REGULAR) { + log_debug("Unit %s has type %s, ignoring.", + i->name, + unit_file_type_to_string(i->type) ?: "invalid"); continue; + } r = mark_symlink_for_removal(remove_symlinks_to, i->name); if (r < 0) -- cgit v1.2.3-54-g00ecf From 893275df36c8c358d3c0b851ca255a6169dac138 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Wed, 4 May 2016 10:10:57 -0400 Subject: shared/install: handle dangling aliases as an explicit case, report nicely This fixes 'preset-all' with a unit that is a dangling symlink. $ systemctl --root=/ preset-all Unit syslog.service is an alias to a unit that is not present, ignoring. Unit auditd.service is masked, ignoring. Unit NetworkManager.service is masked, ignoring. --- src/shared/install.c | 16 +++++++++++++++- src/shared/install.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 427e5eaf7b..4229e59140 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -346,6 +346,11 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang if (!quiet) log_info("Unit %s is masked, ignoring.", changes[i].path); break; + case UNIT_FILE_IS_DANGLING: + if (!quiet) + log_info("Unit %s is an alias to a unit that is not present, ignoring.", + changes[i].path); + break; case -EEXIST: if (changes[i].source) log_error_errno(changes[i].type, @@ -1395,6 +1400,9 @@ static int install_info_traverse( /* Try again, with the new target we found. */ r = unit_file_search(c, i, paths, flags); + if (r == -ENOENT) + /* Translate error code to highlight this specific case */ + return -ENOLINK; } if (r < 0) @@ -1694,7 +1702,9 @@ static int install_context_mark_for_removal( return r; r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); - if (r < 0) + if (r == -ENOLINK) + return 0; + else if (r < 0) return r; if (i->type != UNIT_FILE_TYPE_REGULAR) { @@ -2797,6 +2807,9 @@ int unit_file_preset_all( if (r == -ERFKILL) r = unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, de->d_name, NULL); + else if (r == -ENOLINK) + r = unit_file_changes_add(changes, n_changes, + UNIT_FILE_IS_DANGLING, de->d_name, NULL); if (r < 0) return r; } @@ -2920,6 +2933,7 @@ static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] [UNIT_FILE_SYMLINK] = "symlink", [UNIT_FILE_UNLINK] = "unlink", [UNIT_FILE_IS_MASKED] = "masked", + [UNIT_FILE_IS_DANGLING] = "dangling", }; DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); diff --git a/src/shared/install.h b/src/shared/install.h index 5812447c5b..c6aa4f6ef1 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -73,6 +73,7 @@ enum UnitFileChangeType { UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK, UNIT_FILE_IS_MASKED, + UNIT_FILE_IS_DANGLING, _UNIT_FILE_CHANGE_TYPE_MAX, _UNIT_FILE_CHANGE_INVALID = INT_MIN }; -- cgit v1.2.3-54-g00ecf From 8515830341a49a0af875333a1893a8aa41ee1099 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 7 May 2016 17:02:55 -0400 Subject: shared/install: do not print warning when a unit is already enabled Executing 'systemctl enable' on the same unit twice would cause a warning about a missing [Install] section to be printed. To avoid this, count all symlinks that "would" be created, and return 1 no matter if we actually created a symlink or skipped creation because it already exists. --- src/shared/install.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 4229e59140..88867c456e 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -389,8 +389,6 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang log_error_errno(r, "Failed to %s: %m.", verb); } - - static int create_symlink( const char *old_path, const char *new_path, @@ -406,7 +404,11 @@ static int create_symlink( /* Actually create a symlink, and remember that we did. Is * smart enough to check if there's already a valid symlink in - * place. */ + * place. + * + * Returns 1 if a symlink was created or already exists and points to + * the right place, or negative on error. + */ mkdir_parents_label(new_path, 0755); @@ -431,7 +433,7 @@ static int create_symlink( } if (path_equal(dest, old_path)) - return 0; + return 1; if (!force) { unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest); -- cgit v1.2.3-54-g00ecf From a760db24bbdc4a7b185c9be29cef5cec4e442845 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 7 May 2016 17:15:34 -0400 Subject: shared/install: use "→" instead of "pointing to" for a symlink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's quite a bit shorter and just as readable. (The full sentence with "pointing to" was added to replace a text that used "ln -s %s %s". Using the "ln" syntax is indeed unclear, because it's not obvious which is the source and which is the target, and because symlink(2) uses the opposite order to ln(1). But with the unicode arrow there should be no ambiguity.) --- src/shared/install.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/shared/install.c b/src/shared/install.c index 88867c456e..94dc523414 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -40,6 +40,7 @@ #include "hashmap.h" #include "install-printf.h" #include "install.h" +#include "locale-util.h" #include "log.h" #include "macro.h" #include "mkdir.h" @@ -336,7 +337,10 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang switch(changes[i].type) { case UNIT_FILE_SYMLINK: if (!quiet) - log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); + log_info("Created symlink %s %s %s.", + changes[i].path, + draw_special_char(DRAW_ARROW), + changes[i].source); break; case UNIT_FILE_UNLINK: if (!quiet) -- cgit v1.2.3-54-g00ecf From 323b7dc90343f11febf9e87872d3e8ffded11849 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 7 May 2016 17:30:18 -0400 Subject: tree-wide: rename draw_special_char to special_glyph That function doesn't draw anything on it's own, just returns a string, which sometimes is more than one character. Also remove "DRAW_" prefix from character names, TREE_* and ARROW and BLACK_CIRCLE are unambigous on their own, don't draw anything, and are always used as an argument to special_glyph(). Rename "DASH" to "MDASH", as there's more than one type of dash. --- src/analyze/analyze.c | 4 ++-- src/basic/locale-util.c | 49 ++++++++++++++++++++-------------------- src/basic/locale-util.h | 24 ++++++++++---------- src/boot/bootctl.c | 8 +++---- src/delta/delta.c | 20 ++++++++-------- src/firstboot/firstboot.c | 8 +++---- src/libsystemd/sd-bus/bus-dump.c | 2 +- src/libsystemd/sd-bus/busctl.c | 6 ++--- src/login/sysfs-show.c | 8 +++---- src/network/networkctl.c | 4 ++-- src/shared/bus-unit-util.c | 8 +++---- src/shared/cgroup-show.c | 10 ++++---- src/shared/install.c | 2 +- src/systemctl/systemctl.c | 16 ++++++------- 14 files changed, 85 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index a790ccd33e..d621f66aec 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -752,9 +752,9 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX]; for (i = level; i != 0; i--) - printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE)); + printf("%s", special_glyph(branches & (1 << (i-1)) ? TREE_VERTICAL : TREE_SPACE)); - printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); + printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH)); if (times) { if (times->time) diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index eaad25e65b..8134f61a73 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -271,34 +271,35 @@ out: } -const char *draw_special_char(DrawSpecialChar ch) { - - static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { - - /* UTF-8 */ { - [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */ - [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ - [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ - [DRAW_TREE_SPACE] = " ", /* */ - [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ - [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */ - [DRAW_ARROW] = "\342\206\222", /* → */ - [DRAW_DASH] = "\342\200\223", /* – */ +const char *special_glyph(SpecialGlyph code) { + + static const char *draw_table[2][_SPECIAL_GLYPH_MAX] = { + /* ASCII fallback */ + [false] = { + [TREE_VERTICAL] = "| ", + [TREE_BRANCH] = "|-", + [TREE_RIGHT] = "`-", + [TREE_SPACE] = " ", + [TRIANGULAR_BULLET] = ">", + [BLACK_CIRCLE] = "*", + [ARROW] = "->", + [MDASH] = "-", }, - /* ASCII fallback */ { - [DRAW_TREE_VERTICAL] = "| ", - [DRAW_TREE_BRANCH] = "|-", - [DRAW_TREE_RIGHT] = "`-", - [DRAW_TREE_SPACE] = " ", - [DRAW_TRIANGULAR_BULLET] = ">", - [DRAW_BLACK_CIRCLE] = "*", - [DRAW_ARROW] = "->", - [DRAW_DASH] = "-", - } + /* UTF-8 */ + [ true ] = { + [TREE_VERTICAL] = "\342\224\202 ", /* │ */ + [TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ + [TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ + [TREE_SPACE] = " ", /* */ + [TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ + [BLACK_CIRCLE] = "\342\227\217", /* ● */ + [ARROW] = "\342\206\222", /* → */ + [MDASH] = "\342\200\223", /* – */ + }, }; - return draw_table[!is_locale_utf8()][ch]; + return draw_table[is_locale_utf8()][code]; } static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index b0f9679286..353b7845fd 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -55,19 +55,19 @@ void init_gettext(void); bool is_locale_utf8(void); -typedef enum DrawSpecialChar { - DRAW_TREE_VERTICAL, - DRAW_TREE_BRANCH, - DRAW_TREE_RIGHT, - DRAW_TREE_SPACE, - DRAW_TRIANGULAR_BULLET, - DRAW_BLACK_CIRCLE, - DRAW_ARROW, - DRAW_DASH, - _DRAW_SPECIAL_CHAR_MAX -} DrawSpecialChar; +typedef enum { + TREE_VERTICAL, + TREE_BRANCH, + TREE_RIGHT, + TREE_SPACE, + TRIANGULAR_BULLET, + BLACK_CIRCLE, + ARROW, + MDASH, + _SPECIAL_GLYPH_MAX +} SpecialGlyph; -const char *draw_special_char(DrawSpecialChar ch); +const char *special_glyph(SpecialGlyph code); const char* locale_variable_to_string(LocaleVariable i) _const_; LocaleVariable locale_variable_from_string(const char *s) _pure_; diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index e9baf69f6a..d0af41498f 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -266,9 +266,9 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char if (r < 0) return r; if (r > 0) - printf(" File: %s/%s/%s (%s)\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name, v); + printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT), path, de->d_name, v); else - printf(" File: %s/%s/%s\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name); + printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT), path, de->d_name); c++; } @@ -320,7 +320,7 @@ static int print_efi_option(uint16_t id, bool in_order) { 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%s\n", draw_special_char(DRAW_TREE_RIGHT), path); + printf(" File: %s%s\n", special_glyph(TREE_RIGHT), path); printf("\n"); return 0; @@ -1077,7 +1077,7 @@ static int bootctl_main(int argc, char*argv[]) { 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(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path)); printf("\n"); } else printf("System:\n Not booted with EFI\n"); diff --git a/src/delta/delta.c b/src/delta/delta.c index b4f0ecff2d..f32744def2 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -105,7 +105,7 @@ static int notify_override_masked(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight_red(), "[MASKED]", ansi_normal(), - top, draw_special_char(DRAW_ARROW), bottom); + top, special_glyph(ARROW), bottom); return 1; } @@ -115,7 +115,7 @@ static int notify_override_equivalent(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(), - top, draw_special_char(DRAW_ARROW), bottom); + top, special_glyph(ARROW), bottom); return 1; } @@ -125,7 +125,7 @@ static int notify_override_redirected(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight(), "[REDIRECTED]", ansi_normal(), - top, draw_special_char(DRAW_ARROW), bottom); + top, special_glyph(ARROW), bottom); return 1; } @@ -135,7 +135,7 @@ static int notify_override_overridden(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight(), "[OVERRIDDEN]", ansi_normal(), - top, draw_special_char(DRAW_ARROW), bottom); + top, special_glyph(ARROW), bottom); return 1; } @@ -145,7 +145,7 @@ static int notify_override_extended(const char *top, const char *bottom) { printf("%s%s%s %s %s %s\n", ansi_highlight(), "[EXTENDED]", ansi_normal(), - top, draw_special_char(DRAW_ARROW), bottom); + top, special_glyph(ARROW), bottom); return 1; } @@ -247,7 +247,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const return -ENOMEM; d = p + strlen(toppath) + 1; - log_debug("Adding at top: %s %s %s", d, draw_special_char(DRAW_ARROW), p); + log_debug("Adding at top: %s %s %s", d, special_glyph(ARROW), p); k = hashmap_put(top, d, p); if (k >= 0) { p = strdup(p); @@ -259,7 +259,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const return k; } - log_debug("Adding at bottom: %s %s %s", d, draw_special_char(DRAW_ARROW), p); + log_debug("Adding at bottom: %s %s %s", d, special_glyph(ARROW), p); free(hashmap_remove(bottom, d)); k = hashmap_put(bottom, d, p); if (k < 0) { @@ -283,7 +283,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const return -ENOMEM; log_debug("Adding to drops: %s %s %s %s %s", - unit, draw_special_char(DRAW_ARROW), basename(p), draw_special_char(DRAW_ARROW), p); + unit, special_glyph(ARROW), basename(p), special_glyph(ARROW), p); k = hashmap_put(h, basename(p), p); if (k < 0) { free(p); @@ -334,7 +334,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch if (!p) return -ENOMEM; - log_debug("Adding at top: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p); + log_debug("Adding at top: %s %s %s", basename(p), special_glyph(ARROW), p); k = hashmap_put(top, basename(p), p); if (k >= 0) { p = strdup(p); @@ -345,7 +345,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch return k; } - log_debug("Adding at bottom: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p); + log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(ARROW), p); free(hashmap_remove(bottom, basename(p))); k = hashmap_put(bottom, basename(p), p); if (k < 0) { diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 435e3805c4..3df72460ef 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -160,7 +160,7 @@ static int prompt_loop(const char *text, char **l, bool (*is_valid)(const char * _cleanup_free_ char *p = NULL; unsigned u; - r = ask_string(&p, "%s %s (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET), text); + r = ask_string(&p, "%s %s (empty to skip): ", special_glyph(TRIANGULAR_BULLET), text); if (r < 0) return log_error_errno(r, "Failed to query user: %m"); @@ -371,7 +371,7 @@ static int prompt_hostname(void) { for (;;) { _cleanup_free_ char *h = NULL; - r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET)); + r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", special_glyph(TRIANGULAR_BULLET)); if (r < 0) return log_error_errno(r, "Failed to query hostname: %m"); @@ -456,8 +456,8 @@ static int prompt_root_password(void) { print_welcome(); putchar('\n'); - msg1 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): "); - msg2 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: "); + msg1 = strjoina(special_glyph(TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): "); + msg2 = strjoina(special_glyph(TRIANGULAR_BULLET), " Please enter new root password again: "); for (;;) { _cleanup_string_free_erase_ char *a = NULL, *b = NULL; diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 5964a01c4f..21a6b20a11 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -74,7 +74,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64, m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() : - m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_normal(), + m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", special_glyph(TRIANGULAR_BULLET), ansi_normal(), ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(), m->header->endian, m->header->flags, diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 56bd5863a8..6fdb474b5e 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -249,8 +249,8 @@ static void print_subtree(const char *prefix, const char *path, char **l) { l++; } - vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL)); - space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE)); + vertical = strjoina(prefix, special_glyph(TREE_VERTICAL)); + space = strjoina(prefix, special_glyph(TREE_SPACE)); for (;;) { bool has_more = false; @@ -271,7 +271,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) { n++; } - printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l); + printf("%s%s%s\n", prefix, special_glyph(has_more ? TREE_BRANCH : TREE_RIGHT), *l); print_subtree(has_more ? vertical : space, *l, l); l = n; diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c index bd603e297d..29785e2f11 100644 --- a/src/login/sysfs-show.c +++ b/src/login/sysfs-show.c @@ -110,7 +110,7 @@ static int show_sysfs_one( if (!k) return -ENOMEM; - printf("%s%s%s\n", prefix, draw_special_char(lookahead ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), k); + printf("%s%s%s\n", prefix, special_glyph(lookahead ? TREE_BRANCH : TREE_RIGHT), k); if (asprintf(&l, "%s%s:%s%s%s%s", @@ -124,13 +124,13 @@ static int show_sysfs_one( if (!k) return -ENOMEM; - printf("%s%s%s\n", prefix, lookahead ? draw_special_char(DRAW_TREE_VERTICAL) : " ", k); + printf("%s%s%s\n", prefix, lookahead ? special_glyph(TREE_VERTICAL) : " ", k); *item = next; if (*item) { _cleanup_free_ char *p = NULL; - p = strappend(prefix, lookahead ? draw_special_char(DRAW_TREE_VERTICAL) : " "); + p = strappend(prefix, lookahead ? special_glyph(TREE_VERTICAL) : " "); if (!p) return -ENOMEM; @@ -183,7 +183,7 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) { if (first) show_sysfs_one(udev, seat, &first, "/", prefix, n_columns); else - printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), "(none)"); + printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), "(none)"); return r; } diff --git a/src/network/networkctl.c b/src/network/networkctl.c index b22a0f648a..d2df9b7560 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -750,7 +750,7 @@ static int link_status_one( (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to); (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by); - printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, info->ifindex, info->name); + printf("%s%s%s %i: %s\n", on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational, info->ifindex, info->name); printf(" Link File: %s\n" " Network File: %s\n" @@ -818,7 +818,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); printf("%s%s%s State: %s%s%s\n", - on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, + on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational, on_color_operational, strna(operational_state), off_color_operational); (void) dump_addresses(rtnl, " Address: ", 0); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index ee388b82db..cfced96804 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -1072,7 +1072,7 @@ static int dump_processes( } more = i+1 < n || cg->children; - special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT); + special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT); fprintf(stdout, "%s%s%*"PID_PRI" %s\n", prefix, @@ -1108,14 +1108,14 @@ static int dump_processes( name++; more = i+1 < n; - special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT); + special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT); fputs(prefix, stdout); fputs(special, stdout); fputs(name, stdout); fputc('\n', stdout); - special = draw_special_char(more ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE); + special = special_glyph(more ? TREE_VERTICAL : TREE_SPACE); pp = strappend(prefix, special); if (!pp) @@ -1199,7 +1199,7 @@ static int dump_extra_processes( fprintf(stdout, "%s%s %*" PID_PRI " %s\n", prefix, - draw_special_char(DRAW_TRIANGULAR_BULLET), + special_glyph(TRIANGULAR_BULLET), width, pids[k], name); } diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 7539891bf2..3e451db715 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -76,9 +76,9 @@ static void show_pid_array( get_process_cmdline(pids[i], n_columns, true, &t); if (extra) - printf("%s%s ", prefix, draw_special_char(DRAW_TRIANGULAR_BULLET)); + printf("%s%s ", prefix, special_glyph(TRIANGULAR_BULLET)); else - printf("%s%s", prefix, draw_special_char(((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT))); + printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? TREE_BRANCH : TREE_RIGHT))); printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t)); } @@ -172,10 +172,10 @@ int show_cgroup_by_path( } if (last) { - printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last))); + printf("%s%s%s\n", prefix, special_glyph(TREE_BRANCH), cg_unescape(basename(last))); if (!p1) { - p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL)); + p1 = strappend(prefix, special_glyph(TREE_VERTICAL)); if (!p1) return -ENOMEM; } @@ -195,7 +195,7 @@ int show_cgroup_by_path( show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags); if (last) { - printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last))); + printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), cg_unescape(basename(last))); if (!p2) { p2 = strappend(prefix, " "); diff --git a/src/shared/install.c b/src/shared/install.c index 94dc523414..64d66a45d3 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -339,7 +339,7 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang if (!quiet) log_info("Created symlink %s %s %s.", changes[i].path, - draw_special_char(DRAW_ARROW), + special_glyph(ARROW), changes[i].source); break; case UNIT_FILE_UNLINK: diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 639080bc66..bc35c25c1b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -483,7 +483,7 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { } if (circle_len > 0) - printf("%s%s%s ", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle); + printf("%s%s%s ", on_circle, circle ? special_glyph(BLACK_CIRCLE) : " ", off_circle); printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s", on_active, id_len, id, off_active, @@ -1540,7 +1540,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra printf("%s...\n",max_len % 2 ? "" : " "); return 0; } - printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE)); + printf("%s", special_glyph(branches & (1 << i) ? TREE_VERTICAL : TREE_SPACE)); } len += 2; @@ -1549,7 +1549,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra return 0; } - printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); + printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH)); } if (arg_full) { @@ -1728,7 +1728,7 @@ static int list_dependencies_one( break; } - printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal()); + printf("%s%s%s ", on, special_glyph(BLACK_CIRCLE), ansi_normal()); } r = list_dependencies_print(*c, level, branches, c[1] == NULL); @@ -1965,7 +1965,7 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n) on_failed = off_failed = ""; if (circle_len > 0) - printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state); + printf("%s%s%s ", on_state, circle ? special_glyph(BLACK_CIRCLE) : " ", off_state); if (m->is_host) printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n", @@ -3528,7 +3528,7 @@ static void print_status_info( } else active_on = active_off = ""; - printf("%s%s%s %s", active_on, draw_special_char(DRAW_BLACK_CIRCLE), active_off, strna(i->id)); + printf("%s%s%s %s", active_on, special_glyph(BLACK_CIRCLE), active_off, strna(i->id)); if (i->description && !streq_ptr(i->id, i->description)) printf(" - %s", i->description); @@ -3583,7 +3583,7 @@ static void print_status_info( } printf("%s\n %s", dir, - draw_special_char(DRAW_TREE_RIGHT)); + special_glyph(TREE_RIGHT)); } last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir)); @@ -4704,7 +4704,7 @@ static int show_system_status(sd_bus *bus) { } else on = off = ""; - printf("%s%s%s %s\n", on, draw_special_char(DRAW_BLACK_CIRCLE), off, arg_host ? arg_host : hn); + printf("%s%s%s %s\n", on, special_glyph(BLACK_CIRCLE), off, arg_host ? arg_host : hn); printf(" State: %s%s%s\n", on, strna(mi.state), off); -- cgit v1.2.3-54-g00ecf From dff4bf93d449b9d9086123521f83d68e98cecd09 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 9 May 2016 11:24:08 -0400 Subject: locale-util: mark special_glyph() as _const_ _const_ means that the caller can assume that the function will return the same result every time (and will not modify global memory). special_glyph() meets this: even though it depends on global memory, that part of global memory is not expected to change. This allows the calls to special_glyph() to be optimized, even if -flto is not used. --- src/basic/locale-util.c | 2 +- src/basic/locale-util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 8134f61a73..ada0a28cd8 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -273,7 +273,7 @@ out: const char *special_glyph(SpecialGlyph code) { - static const char *draw_table[2][_SPECIAL_GLYPH_MAX] = { + static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = { /* ASCII fallback */ [false] = { [TREE_VERTICAL] = "| ", diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index 353b7845fd..0630a034ab 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -67,7 +67,7 @@ typedef enum { _SPECIAL_GLYPH_MAX } SpecialGlyph; -const char *special_glyph(SpecialGlyph code); +const char *special_glyph(SpecialGlyph code) _const_; const char* locale_variable_to_string(LocaleVariable i) _const_; LocaleVariable locale_variable_from_string(const char *s) _pure_; -- cgit v1.2.3-54-g00ecf From fe1ef0f86e49c50cf71579d98679973a6d671323 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Wed, 11 May 2016 15:29:24 +0300 Subject: coredump: use next_datagram_size_fd instead of ioctl(FIONREAD) (#3237) We need to be sure that the size returned here actually matches what we will read with recvmsg() next Fixes #2984 --- src/coredump/coredump.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 01fdcfa909..999de63900 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -739,15 +739,16 @@ static int process_socket(int fd) { .msg_iovlen = 1, }; ssize_t n; - int l; + ssize_t l; if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) { r = log_oom(); goto finish; } - if (ioctl(fd, FIONREAD, &l) < 0) { - r = log_error_errno(errno, "FIONREAD failed: %m"); + l = next_datagram_size_fd(fd); + if (l < 0) { + r = log_error_errno(l, "Failed to determine datagram size to read: %m"); goto finish; } -- cgit v1.2.3-54-g00ecf From 42d35e1301928d08dd32ec51f0205252ae658ba5 Mon Sep 17 00:00:00 2001 From: Victor Toso Date: Wed, 11 May 2016 19:34:13 +0200 Subject: logind: introduce LockedHint and SetLockedHint (#3238) Desktop environments can keep this property up to date to allow applications to easily track session's Lock status. --- src/login/logind-session-dbus.c | 49 +++++++++++++++++++++++++++++++++++ src/login/logind-session.c | 17 ++++++++++++ src/login/logind-session.h | 4 +++ src/login/org.freedesktop.login1.conf | 4 +++ 4 files changed, 74 insertions(+) (limited to 'src') diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 0f8862c0d9..22dea5db1f 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -180,6 +180,24 @@ static int property_get_idle_since_hint( return sd_bus_message_append(reply, "t", u); } +static int property_get_locked_hint( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Session *s = userdata; + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0); +} + int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) { Session *s = userdata; int r; @@ -279,6 +297,35 @@ static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_ return sd_bus_reply_method_return(message, NULL); } +static int method_set_locked_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + Session *s = userdata; + uid_t uid; + int r, b; + + assert(message); + assert(s); + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_euid(creds, &uid); + if (r < 0) + return r; + + if (uid != 0 && uid != s->user->uid) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint"); + + session_set_locked_hint(s, b); + + return sd_bus_reply_method_return(message, NULL); +} + int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) { Session *s = userdata; const char *swho; @@ -487,12 +534,14 @@ const sd_bus_vtable session_vtable[] = { 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), + SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 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("SetLockedHint", "b", NULL, method_set_locked_hint, SD_BUS_VTABLE_UNPRIVILEGED), 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), diff --git a/src/login/logind-session.c b/src/login/logind-session.c index d2f1f7bc62..1e0666884a 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -852,6 +852,23 @@ void session_set_idle_hint(Session *s, bool b) { manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); } +int session_get_locked_hint(Session *s) { + assert(s); + + return s->locked_hint; +} + +void session_set_locked_hint(Session *s, bool b) { + assert(s); + + if (s->locked_hint == b) + return; + + s->locked_hint = b; + + session_send_changed(s, "LockedHint", NULL); +} + static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) { Session *s = userdata; diff --git a/src/login/logind-session.h b/src/login/logind-session.h index e24b808474..ffb7cd2d41 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -105,6 +105,8 @@ struct Session { bool idle_hint; dual_timestamp idle_hint_timestamp; + bool locked_hint; + bool in_gc_queue:1; bool started:1; bool stopping:1; @@ -132,6 +134,8 @@ int session_activate(Session *s); bool session_is_active(Session *s); int session_get_idle_hint(Session *s, dual_timestamp *t); void session_set_idle_hint(Session *s, bool b); +int session_get_locked_hint(Session *s); +void session_set_locked_hint(Session *s, bool b); int session_create_fifo(Session *s); int session_start(Session *s); int session_stop(Session *s, bool force); diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index 1662d4c428..c89e40457e 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -232,6 +232,10 @@ send_interface="org.freedesktop.login1.Session" send_member="SetIdleHint"/> + + -- cgit v1.2.3-54-g00ecf From 7163e1ca1108d789ee8b40238ebf0f6978cd58a9 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 12 May 2016 10:42:39 -0600 Subject: Create initrd-root-device.target synchronization point (#3239) Add a synchronization point so that custom initramfs units can run after the root device becomes available, before it is fsck'd and mounted. This is useful for custom initramfs units that may modify the root disk partition table, where the root device is not known in advance (it's dynamically selected by the generators). --- Makefile.am | 1 + man/bootup.xml | 7 ++++++- man/systemd.special.xml | 13 +++++++++++++ src/basic/special.h | 1 + src/fstab-generator/fstab-generator.c | 8 ++++++++ src/gpt-auto-generator/gpt-auto-generator.c | 6 ++++++ src/shared/generator.c | 16 +++++++++++++++- src/shared/generator.h | 4 ++++ units/initrd-root-device.target | 15 +++++++++++++++ units/initrd.target | 4 ++-- 10 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 units/initrd-root-device.target (limited to 'src') diff --git a/Makefile.am b/Makefile.am index aea91e9c94..c126f65ad2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -467,6 +467,7 @@ dist_systemunit_DATA = \ units/local-fs-pre.target \ units/initrd.target \ units/initrd-fs.target \ + units/initrd-root-device.target \ units/initrd-root-fs.target \ units/remote-fs.target \ units/remote-fs-pre.target \ diff --git a/man/bootup.xml b/man/bootup.xml index b92057af29..986996398c 100644 --- a/man/bootup.xml +++ b/man/bootup.xml @@ -179,6 +179,8 @@ identical to the system manager bootup (see above) until it reaches basic.target. From there, systemd approaches the special target initrd.target. + When the root device becomes available, + initd-root-device.target is reached. If the root device can be mounted at /sysroot, the sysroot.mount unit becomes active and @@ -204,7 +206,10 @@ | emergency.service ______________________/| | / | v - | sysroot.mount emergency.target + | initrd-root-device.target emergency.target + | | + | v + | sysroot.mount | | | v | initrd-root-fs.target diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 14998b9647..26974ed73f 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -83,6 +83,7 @@ remote-fs.target, remote-fs-pre.target, rescue.target, + initrd-root-device.target, initrd-root-fs.target, rpcbind.target, runlevel2.target, @@ -464,6 +465,18 @@ SysV. + + initrd-root-device.target + + A special initrd target unit that is reached when the root filesystem device is available, but before + it has been mounted. + systemd-fstab-generator3 + and + systemd-gpt-auto-generator3 + automatically setup the appropiate dependencies to make this happen. + + + initrd-root-fs.target diff --git a/src/basic/special.h b/src/basic/special.h index 2fd03d9f75..084d3dfa23 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -52,6 +52,7 @@ #define SPECIAL_LOCAL_FS_TARGET "local-fs.target" #define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target" #define SPECIAL_INITRD_FS_TARGET "initrd-fs.target" +#define SPECIAL_INITRD_ROOT_DEVICE_TARGET "initrd-root-device.target" #define SPECIAL_INITRD_ROOT_FS_TARGET "initrd-root-fs.target" #define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */ #define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target" diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 343e3b1817..108522873e 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -489,6 +489,7 @@ static int parse_fstab(bool initrd) { static int add_sysroot_mount(void) { _cleanup_free_ char *what = NULL; const char *opts; + int r; if (isempty(arg_root_what)) { log_debug("Could not find a root= entry on the kernel command line."); @@ -508,6 +509,13 @@ static int add_sysroot_mount(void) { opts = arg_root_options; log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype)); + + if (is_device_path(what)) { + r = generator_write_initrd_root_device_deps(arg_dest, what); + if (r < 0) + return r; + } + return add_mount(what, "/sysroot", arg_root_fstype, diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index af96adec06..a4938a7c3a 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -956,6 +956,12 @@ static int add_root_mount(void) { * wait for a root device to show up. A udev rule will create * the link for us under the right name. */ + if (in_initrd()) { + r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root"); + if (r < 0) + return 0; + } + return add_mount( "root", "/dev/gpt-auto-root", diff --git a/src/shared/generator.c b/src/shared/generator.c index cd3c35cd55..70afc6a285 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -65,7 +65,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { "Description=File System Check on %2$s\n" "DefaultDependencies=no\n" "BindsTo=%3$s\n" - "After=%3$s local-fs-pre.target\n" + "After=initrd-root-device.target local-fs-pre.target\n" "Before=shutdown.target\n" "\n" "[Service]\n" @@ -191,3 +191,17 @@ int generator_write_timeouts( "[Unit]\nJobTimeoutSec=%s", program_invocation_short_name, timeout); } + +int generator_write_initrd_root_device_deps(const char *dir, const char *what) { + _cleanup_free_ char *unit = NULL; + int r; + + r = unit_name_from_path(what, ".device", &unit); + if (r < 0) + return log_error_errno(r, "Failed to make unit name from path: %m"); + + return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device", + "# Automatically generated by %s\n\n" + "[Unit]\nRequires=%s\nAfter=%s", + program_invocation_short_name, unit, unit); +} diff --git a/src/shared/generator.h b/src/shared/generator.h index a734e13970..a6017c1b76 100644 --- a/src/shared/generator.h +++ b/src/shared/generator.h @@ -34,3 +34,7 @@ int generator_write_timeouts( const char *where, const char *opts, char **filtered); + +int generator_write_initrd_root_device_deps( + const char *dir, + const char *what); diff --git a/units/initrd-root-device.target b/units/initrd-root-device.target new file mode 100644 index 0000000000..9d44d2d303 --- /dev/null +++ b/units/initrd-root-device.target @@ -0,0 +1,15 @@ +# 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. + +[Unit] +Description=Initrd Root Device +Documentation=man:systemd.special(7) +ConditionPathExists=/etc/initrd-release +OnFailure=emergency.target +OnFailureJobMode=replace-irreversibly +DefaultDependencies=no +Conflicts=shutdown.target diff --git a/units/initrd.target b/units/initrd.target index eae7c703c1..8be7e2b399 100644 --- a/units/initrd.target +++ b/units/initrd.target @@ -12,6 +12,6 @@ OnFailure=emergency.target OnFailureJobMode=replace-irreversibly ConditionPathExists=/etc/initrd-release Requires=basic.target -Wants=initrd-root-fs.target initrd-fs.target initrd-parse-etc.service -After=initrd-root-fs.target initrd-fs.target basic.target rescue.service rescue.target +Wants=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-parse-etc.service +After=initrd-root-fs.target initrd-root-device.target initrd-fs.target basic.target rescue.service rescue.target AllowIsolate=yes -- cgit v1.2.3-54-g00ecf From 6900c740e1c2dab6d8f80e64e2fd1cd8c6d368a6 Mon Sep 17 00:00:00 2001 From: kayrus Date: Thu, 12 May 2016 18:58:59 +0200 Subject: core: added ListUnitsByNames dbus method (#3182) This new method returns information by unit names. Instead of ListUnitsByPatterns this method returns information of inactive and even unexisting units. Moved dbus unit reply logic into a separate shared function. Resolves https://github.com/coreos/fleet/pull/1418 --- src/core/dbus-manager.c | 103 ++++++++++++++++++++++++--------- src/core/org.freedesktop.systemd1.conf | 4 ++ 2 files changed, 80 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index d45f511489..86722e1162 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -642,6 +642,80 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s return bus_unit_method_set_properties(message, u, error); } +static int reply_unit_info(sd_bus_message *reply, Unit *u) { + _cleanup_free_ char *unit_path = NULL, *job_path = NULL; + Unit *following; + + following = unit_following(u); + + unit_path = unit_dbus_path(u); + if (!unit_path) + return -ENOMEM; + + if (u->job) { + job_path = job_dbus_path(u->job); + if (!job_path) + return -ENOMEM; + } + + return sd_bus_message_append( + reply, "(ssssssouso)", + u->id, + unit_description(u), + unit_load_state_to_string(u->load_state), + unit_active_state_to_string(unit_active_state(u)), + unit_sub_state_to_string(u), + following ? following->id : "", + unit_path, + u->job ? u->job->id : 0, + u->job ? job_type_to_string(u->job->type) : "", + job_path ? job_path : "/"); +} + +static int method_list_units_by_names(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + Manager *m = userdata; + int r; + char **unit; + _cleanup_strv_free_ char **units = NULL; + + assert(message); + assert(m); + + r = sd_bus_message_read_strv(message, &units); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)"); + if (r < 0) + return r; + + STRV_FOREACH(unit, units) { + Unit *u; + + if (!unit_name_is_valid(*unit, UNIT_NAME_ANY)) + continue; + + r = manager_load_unit(m, *unit, NULL, error, &u); + if (r < 0) + return r; + + r = reply_unit_info(reply, u); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; const char *name; @@ -915,14 +989,9 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e return r; HASHMAP_FOREACH_KEY(u, k, m->units, i) { - _cleanup_free_ char *unit_path = NULL, *job_path = NULL; - Unit *following; - if (k != u->id) continue; - following = unit_following(u); - if (!strv_isempty(states) && !strv_contains(states, unit_load_state_to_string(u->load_state)) && !strv_contains(states, unit_active_state_to_string(unit_active_state(u))) && @@ -933,28 +1002,7 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e !strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE)) continue; - unit_path = unit_dbus_path(u); - if (!unit_path) - return -ENOMEM; - - if (u->job) { - job_path = job_dbus_path(u->job); - if (!job_path) - return -ENOMEM; - } - - r = sd_bus_message_append( - reply, "(ssssssouso)", - u->id, - unit_description(u), - unit_load_state_to_string(u->load_state), - unit_active_state_to_string(unit_active_state(u)), - unit_sub_state_to_string(u), - following ? following->id : "", - unit_path, - u->job ? u->job->id : 0, - u->job ? job_type_to_string(u->job->type) : "", - job_path ? job_path : "/"); + r = reply_unit_info(reply, u); if (r < 0) return r; } @@ -2115,6 +2163,7 @@ const sd_bus_vtable bus_manager_vtable[] = { 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("ListUnitsByPatterns", "asas", "a(ssssssouso)", method_list_units_by_patterns, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListUnitsByNames", "as", "a(ssssssouso)", method_list_units_by_names, 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), diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 6c504a5e69..3c64f20872 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -154,6 +154,10 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="SetUnitProperties"/> + + -- cgit v1.2.3-54-g00ecf From 2099b3e9931eea8962cf7a97493abf9361cc6366 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 12 May 2016 20:14:58 +0200 Subject: nspawn: drop spurious newline --- src/nspawn/nspawn.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 0479389682..8ec058431b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1713,7 +1713,6 @@ static int setup_seccomp(void) { } } - /* Audit is broken in containers, much of the userspace audit hookup will fail if running inside a container. We don't -- cgit v1.2.3-54-g00ecf From 9e5f825280192be429cc79153235d12778427fae Mon Sep 17 00:00:00 2001 From: topimiettinen Date: Sat, 14 May 2016 16:46:23 +0000 Subject: namespace: unmount old /dev under our new private /dev (#3254) Drop all dangling old /dev mounts before mounting a new private /dev tree. --- src/core/namespace.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/core/namespace.c b/src/core/namespace.c index b573f008b9..ef85bfec23 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -237,6 +237,8 @@ static int mount_dev(BindMount *m) { */ (void) mkdir_p_label(m->path, 0755); + /* Unmount everything in old /dev */ + umount_recursive(m->path, 0); if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) { r = -errno; goto fail; -- cgit v1.2.3-54-g00ecf From 99e66921c86bce77d0d3587c201c7d1b611a7d99 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 14 May 2016 15:56:53 -0400 Subject: core: allow slice to be overriden if cgroups aren't realized (#3246) unit_set_slice() fails with -EBUSY if the unit already has a slice associated with it. This makes it impossible to override slice through dropin config or over dbus. There's no reason to disallow slice changes as long as cgroups aren't realized. Fix it. Fixes #3240. Signed-off-by: Tejun Heo Reported-by: Davide Cavalca --- src/core/unit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/unit.c b/src/core/unit.c index d8ab5781b0..dc8325515c 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2400,9 +2400,11 @@ int unit_set_slice(Unit *u, Unit *slice) { if (UNIT_DEREF(u->slice) == slice) return 0; - if (UNIT_ISSET(u->slice)) + /* Disallow slice changes if @u is already bound to cgroups */ + if (UNIT_ISSET(u->slice) && u->cgroup_realized) return -EBUSY; + unit_ref_unset(&u->slice); unit_ref_set(&u->slice, slice); return 1; } -- cgit v1.2.3-54-g00ecf From 17fd746098bb451f4e9a1485374540eeafd11fda Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sat, 14 May 2016 22:10:22 +0200 Subject: busctl: use Monitoring interface (#3245) This is now the recommended way to do monitoring by upstream D-Bus. It's also allowed in the default policy, whereas eavesdrop is not anymore, which effectively broke busctl on many systems. --- src/libsystemd/sd-bus/busctl.c | 45 ++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 6fdb474b5e..bfe967bfb0 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -1079,10 +1079,21 @@ static int message_pcap(sd_bus_message *m, FILE *f) { } static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) { - bool added_something = false; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char **i; + uint32_t flags = 0; int r; + /* upgrade connection; it's not used for anything else after this call */ + r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(message, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + STRV_FOREACH(i, argv+1) { _cleanup_free_ char *m = NULL; @@ -1095,34 +1106,38 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL if (!m) return log_oom(); - r = sd_bus_add_match(bus, NULL, m, NULL, NULL); + r = sd_bus_message_append_basic(message, 's', m); if (r < 0) - return log_error_errno(r, "Failed to add match: %m"); + return bus_log_create_error(r); free(m); m = strjoin("destination='", *i, "'", NULL); if (!m) return log_oom(); - r = sd_bus_add_match(bus, NULL, m, NULL, NULL); + r = sd_bus_message_append_basic(message, 's', m); if (r < 0) - return log_error_errno(r, "Failed to add match: %m"); - - added_something = true; + return bus_log_create_error(r); } STRV_FOREACH(i, arg_matches) { - r = sd_bus_add_match(bus, NULL, *i, NULL, NULL); + r = sd_bus_message_append_basic(message, 's', *i); if (r < 0) - return log_error_errno(r, "Failed to add match: %m"); - - added_something = true; + return bus_log_create_error(r); } - if (!added_something) { - r = sd_bus_add_match(bus, NULL, "", NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to add match: %m"); + r = sd_bus_message_close_container(message); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(message, 'u', &flags); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, message, arg_timeout, &error, NULL); + if (r < 0) { + log_error("%s", bus_error_message(&error, r)); + return r; } log_info("Monitoring bus message stream."); -- cgit v1.2.3-54-g00ecf From b9642f4199b7ab4560665539a4378730e01f7b7f Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 14 May 2016 16:46:01 -0400 Subject: networkd: drop route_drop It is just an alias for route_free which requires that route is not null, but it was only used in one place where it was checked that route is not null anyway. Let's just call route_free instead. --- src/network/networkd-manager.c | 6 ++---- src/network/networkd-route.c | 6 ------ src/network/networkd-route.h | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 5dcd4df536..9174dcc7f4 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -457,11 +457,9 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo break; case RTM_DELROUTE: - - if (route) - route_drop(route); - + route_free(route); break; + default: assert_not_reached("Received invalid RTNL message type"); } diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 43f37266d8..ab4a94f41a 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -324,12 +324,6 @@ int route_update(Route *route, return 0; } -void route_drop(Route *route) { - assert(route); - - route_free(route); -} - int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 84d74992c9..39de8363ed 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -61,7 +61,6 @@ int route_get(Link *link, int family, union in_addr_union *dst, unsigned char ds int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol); -void route_drop(Route *route); int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata); -- cgit v1.2.3-54-g00ecf From d9d94393471d32a35eeb3c71ec8ac20451362ba3 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 14 May 2016 16:47:59 -0400 Subject: networkd: fix copy-pasto in error message --- src/network/networkd-route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index ab4a94f41a..2b3970289e 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -369,7 +369,7 @@ int route_remove(Route *route, Link *link, else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6); if (r < 0) - return log_error_errno(r, "Could not append RTA_DST attribute: %m"); + return log_error_errno(r, "Could not append RTA_SRC attribute: %m"); r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen); if (r < 0) -- cgit v1.2.3-54-g00ecf From 6df6d89879b1fc390196b5638804e2c11fed9024 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Sun, 15 May 2016 18:45:20 +0530 Subject: networkd: bridge add support to configure multicast snooping (#3223) This patch implements support for the IFLA_BR_MCAST_SNOOPING attribute it can change the multicast snooping value. IGMP snooping monitors the Internet Group Management Protocol (IGMP) traffic between hosts and multicast routers. --- man/systemd.netdev.xml | 9 +++++++++ src/network/networkd-netdev-bridge.c | 7 +++++++ src/network/networkd-netdev-bridge.h | 1 + src/network/networkd-netdev-gperf.gperf | 1 + 4 files changed, 18 insertions(+) (limited to 'src') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 48c283c8df..8d12c305d2 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -321,6 +321,15 @@ + + MulticastSnooping= + + A boolean. This setting controls the IFLA_BR_MCAST_SNOOPING option in the kernel. + If enabled, IGMP snooping monitors the Internet Group Management Protocol (IGMP) traffic + between hosts and multicast routers. When unset, the kernel's default setting applies. + + + diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index 3e44dd7960..4cfd00413f 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -96,6 +96,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m"); } + if (b->mcast_snooping >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_SNOOPING, b->mcast_snooping); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m"); + } + r = sd_netlink_message_close_container(req); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); @@ -121,6 +127,7 @@ static void bridge_init(NetDev *n) { assert(b); b->mcast_querier = -1; + b->mcast_snooping = -1; } const NetDevVTable bridge_vtable = { diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index b921439f02..f2ae21fc50 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -25,6 +25,7 @@ typedef struct Bridge { NetDev meta; int mcast_querier; + int mcast_snooping; usec_t forward_delay; usec_t hello_time; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 1ebd0fdf20..ba04bb0165 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -99,3 +99,4 @@ Bridge.HelloTimeSec, config_parse_sec, 0, Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age) Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay) Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier) +Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping) -- cgit v1.2.3-54-g00ecf From bc48c51f72d86c6f690724f251892da5657116ac Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Sun, 15 May 2016 19:15:30 +0530 Subject: networkd: do not generate a mac address for vlan interfaces (#3221) While creating a VLAN the mac address should be copied from the parent interface, so that the VLANs inherit the MAC address of the physical interface. Before: ``` 3: wlp3s0: mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:26:c6:85:a3:c2 brd ff:ff:ff:ff:ff:ff ... 6: vlan1@wlp3s0: mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 22:07:73:9d:43:59 brd ff:ff:ff:ff:ff:ff 7: vlan2@wlp3s0: mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 46:30:76:33:35:d4 brd ff:ff:ff:ff:ff:ff ``` After: ``` 3: wlp3s0: mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:26:c6:85:a3:c2 brd ff:ff:ff:ff:ff:ff ... 11: vlan1@wlp3s0: mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 00:26:c6:85:a3:c2 brd ff:ff:ff:ff:ff:ff 12: vlan2@wlp3s0: mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 00:26:c6:85:a3:c2 brd ff:ff:ff:ff:ff:ff ``` v2 of #1573, with fixed commit message. --- src/network/networkd-netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index d7d014f05d..851a36290c 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -656,7 +656,7 @@ static int netdev_load_one(Manager *manager, const char *filename) { if (!netdev->filename) return log_oom(); - if (!netdev->mac) { + if (!netdev->mac && netdev->kind != NETDEV_KIND_VLAN) { r = netdev_get_mac(netdev->ifname, &netdev->mac); if (r < 0) return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname); -- cgit v1.2.3-54-g00ecf From 483d099e160759bd68fa46cab62e901318be552d Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 15 May 2016 10:22:40 -0400 Subject: tree-wide: drop spurious "&"s when passing functions around Also adjust indentation in various places. --- src/libsystemd-network/sd-dhcp6-client.c | 6 +++--- src/libsystemd/sd-netlink/test-netlink.c | 18 +++++++++--------- src/network/networkd-address.c | 7 +++++-- src/network/networkd-dhcp4.c | 16 ++++++++-------- src/network/networkd-dhcp6.c | 4 ++-- src/network/networkd-ipv4ll.c | 4 ++-- src/network/networkd-link.c | 4 ++-- 7 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 4adb053a57..57122ee289 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -1196,7 +1196,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { goto error; r = sd_event_source_set_description(client->receive_message, - "dhcp6-receive-message"); + "dhcp6-receive-message"); if (r < 0) goto error; @@ -1204,8 +1204,8 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { state = DHCP6_STATE_INFORMATION_REQUEST; log_dhcp6_client(client, "Started in %s mode", - client->information_request? "Information request": - "Managed"); + client->information_request? "Information request": + "Managed"); return client_start(client, state); diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index f9b6787187..58c2e892f5 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -217,7 +217,7 @@ static void test_event_loop(int ifindex) { assert_se(sd_netlink_open(&rtnl) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); - assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0); + assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, NULL) >= 0); assert_se(sd_event_default(&event) >= 0); @@ -258,7 +258,7 @@ static void test_async(int ifindex) { assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0); - assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0); + assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, &serial) >= 0); assert_se(sd_netlink_wait(rtnl, 0) >= 0); assert_se(sd_netlink_process(rtnl, &r) >= 0); @@ -277,10 +277,10 @@ static void test_pipe(int ifindex) { assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0); counter++; - assert_se(sd_netlink_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0); + assert_se(sd_netlink_call_async(rtnl, m1, pipe_handler, &counter, 0, NULL) >= 0); counter++; - assert_se(sd_netlink_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0); + assert_se(sd_netlink_call_async(rtnl, m2, pipe_handler, &counter, 0, NULL) >= 0); while (counter > 0) { assert_se(sd_netlink_wait(rtnl, 0) >= 0); @@ -330,12 +330,12 @@ static void test_match(void) { assert_se(sd_netlink_open(&rtnl) >= 0); - assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0); - assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0); + assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0); + assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0); - assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1); - assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1); - assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0); + assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1); + assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1); + assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 0); assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL); } diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 4eb0d927a6..b2de1f9d57 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -404,8 +404,11 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi return 0; } -int address_remove(Address *address, Link *link, - sd_netlink_message_handler_t callback) { +int address_remove( + Address *address, + Link *link, + sd_netlink_message_handler_t callback) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 89926e8a7e..2ddcee9db8 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -96,7 +96,7 @@ static int link_set_dhcp_routes(Link *link) { route_gw->protocol = RTPROT_DHCP; route_gw->priority = link->network->dhcp_route_metric; - r = route_configure(route_gw, link, &dhcp4_route_handler); + r = route_configure(route_gw, link, dhcp4_route_handler); if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); @@ -107,7 +107,7 @@ static int link_set_dhcp_routes(Link *link) { route->prefsrc.in = address; route->priority = link->network->dhcp_route_metric; - r = route_configure(route, link, &dhcp4_route_handler); + r = route_configure(route, link, dhcp4_route_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set routes: %m"); link_enter_failed(link); @@ -137,7 +137,7 @@ static int link_set_dhcp_routes(Link *link) { assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0); route->priority = link->network->dhcp_route_metric; - r = route_configure(route, link, &dhcp4_route_handler); + r = route_configure(route, link, dhcp4_route_handler); if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); @@ -177,7 +177,7 @@ static int dhcp_lease_lost(Link *link) { assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0); route_remove(route, link, - &link_route_remove_handler); + link_route_remove_handler); } } } @@ -198,7 +198,7 @@ static int dhcp_lease_lost(Link *link) { route_gw->scope = RT_SCOPE_LINK; route_remove(route_gw, link, - &link_route_remove_handler); + link_route_remove_handler); } r = route_new(&route); @@ -207,7 +207,7 @@ static int dhcp_lease_lost(Link *link) { route->gw.in = gateway; route_remove(route, link, - &link_route_remove_handler); + link_route_remove_handler); } } @@ -221,7 +221,7 @@ static int dhcp_lease_lost(Link *link) { address->in_addr.in = addr; address->prefixlen = prefixlen; - address_remove(address, link, &link_address_remove_handler); + address_remove(address, link, link_address_remove_handler); } } @@ -309,7 +309,7 @@ static int dhcp4_update_address(Link *link, /* allow reusing an existing address and simply update its lifetime * in case it already exists */ - r = address_configure(addr, link, &dhcp4_address_handler, true); + r = address_configure(addr, link, dhcp4_address_handler, true); if (r < 0) return r; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index ccca4e9522..6085b28f86 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -103,8 +103,8 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { sd_dhcp6_lease_reset_address_iter(lease); while (sd_dhcp6_lease_get_address(lease, &ip6_addr, - &lifetime_preferred, - &lifetime_valid) >= 0) { + &lifetime_preferred, + &lifetime_valid) >= 0) { r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid); if (r < 0) diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 35c9b06473..ae323d595b 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -51,7 +51,7 @@ static int ipv4ll_address_lost(Link *link) { address->prefixlen = 16; address->scope = RT_SCOPE_LINK; - address_remove(address, link, &link_address_remove_handler); + address_remove(address, link, link_address_remove_handler); r = route_new(&route); if (r < 0) { @@ -63,7 +63,7 @@ static int ipv4ll_address_lost(Link *link) { route->scope = RT_SCOPE_LINK; route->priority = IPV4LL_ROUTE_METRIC; - route_remove(route, link, &link_route_remove_handler); + route_remove(route, link, link_route_remove_handler); link_check_ready(link); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 4e3f62cf51..f3a79b0ec8 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -760,7 +760,7 @@ static int link_enter_set_routes(Link *link) { link_set_state(link, LINK_STATE_SETTING_ROUTES); LIST_FOREACH(routes, rt, link->network->static_routes) { - r = route_configure(rt, link, &route_handler); + r = route_configure(rt, link, route_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set routes: %m"); link_enter_failed(link); @@ -929,7 +929,7 @@ static int link_enter_set_addresses(Link *link) { link_set_state(link, LINK_STATE_SETTING_ADDRESSES); LIST_FOREACH(addresses, ad, link->network->static_addresses) { - r = address_configure(ad, link, &address_handler, false); + r = address_configure(ad, link, address_handler, false); if (r < 0) { log_link_warning_errno(link, r, "Could not set addresses: %m"); link_enter_failed(link); -- cgit v1.2.3-54-g00ecf From bd9a722196f7465d2f3104735b7ca9f62ae9a557 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sun, 15 May 2016 10:46:17 -0400 Subject: sd-dhcp6-client: add log_errno macro and improve debug messages a bit --- src/libsystemd-network/dhcp6-internal.h | 3 ++- src/libsystemd-network/sd-dhcp6-client.c | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 749086d33a..945c3b9721 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -55,7 +55,8 @@ struct DHCP6IA { typedef struct DHCP6IA DHCP6IA; -#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) +#define log_dhcp6_client_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) +#define log_dhcp6_client(p, fmt, ...) log_dhcp6_client_errno(p, 0, fmt, ##__VA_ARGS__) int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 57122ee289..0c296e39fa 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -922,9 +922,8 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, if (errno == EAGAIN || errno == EINTR) return 0; - log_dhcp6_client(client, "Could not receive message from UDP socket: %m"); + return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m"); - return -errno; } else if ((size_t)len < sizeof(DHCP6Message)) return 0; @@ -947,8 +946,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, break; default: - log_dhcp6_client(client, "unknown message type %d", - message->type); + log_dhcp6_client(client, "Unknown message type %d", message->type); return 0; } @@ -1007,10 +1005,9 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, return 0; } - if (r >= 0) { + if (r >= 0) log_dhcp6_client(client, "Recv %s", dhcp6_message_type_to_string(message->type)); - } return 0; } @@ -1063,7 +1060,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { if (client->lease->ia.lifetime_t1 == 0xffffffff || client->lease->ia.lifetime_t2 == 0xffffffff) { - log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x", + log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x", be32toh(client->lease->ia.lifetime_t1), be32toh(client->lease->ia.lifetime_t2)); @@ -1179,8 +1176,13 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { return r; r = dhcp6_network_bind_udp_socket(client->index, &client->local_address); - if (r < 0) - return r; + if (r < 0) { + _cleanup_free_ char *p = NULL; + + (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p); + return log_dhcp6_client_errno(client, r, + "Failed to bind to UDP socket at address %s: %m", strna(p)); + } client->fd = r; -- cgit v1.2.3-54-g00ecf From 737ba3c82c71c15de498f63527d264dc996ffa11 Mon Sep 17 00:00:00 2001 From: topimiettinen Date: Mon, 16 May 2016 02:34:05 +0000 Subject: namespace: Make private /dev noexec and readonly (#3263) Private /dev will not be managed by udev or others, so we can make it noexec and readonly after we have made all device nodes. As /dev/shm needs to be writable, we can't use bind_remount_recursive(). --- man/systemd.exec.xml | 5 ++++- src/core/namespace.c | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 2a93760428..3cf6de8256 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -933,7 +933,10 @@ (propagation in the opposite direction continues to work). This means that this setting may not be used for services which shall be able to install mount points in the main mount - namespace. + namespace. The /dev namespace will be mounted read-only and 'noexec'. + The latter may break old programs which try to set up executable + memory by using mmap2 + of /dev/zero instead of using MAP_ANON. diff --git a/src/core/namespace.c b/src/core/namespace.c index ef85bfec23..203d122810 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -44,6 +44,8 @@ #include "user-util.h" #include "util.h" +#define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC) + typedef enum MountMode { /* This is ordered by priority! */ INACCESSIBLE, @@ -153,7 +155,7 @@ static int mount_dev(BindMount *m) { dev = strjoina(temporary_mount, "/dev"); (void) mkdir(dev, 0755); - if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) { + if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) { r = -errno; goto fail; } @@ -330,9 +332,11 @@ static int make_read_only(BindMount *m) { if (IN_SET(m->mode, INACCESSIBLE, READONLY)) r = bind_remount_recursive(m->path, true); - else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV)) + else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV)) { r = bind_remount_recursive(m->path, false); - else + if (r == 0 && m->mode == PRIVATE_DEV) /* can be readonly but the submounts can't*/ + r = mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL); + } else r = 0; if (m->ignore && r == -ENOENT) -- cgit v1.2.3-54-g00ecf From 6a08e1b0cdef80f165a74bfff469c4660a9fb3f6 Mon Sep 17 00:00:00 2001 From: Kyle Russell Date: Mon, 16 May 2016 09:41:30 -0500 Subject: vconsole-setup: Store fonts on heap (#3268) More friendly to the stack. --- src/vconsole/vconsole-setup.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 8a1b824e65..08ae4aad27 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -195,9 +195,15 @@ static void font_copy_to_all_vcs(int fd) { unsigned char map8[E_TABSZ]; unsigned short map16[E_TABSZ]; struct unimapdesc unimapd; - struct unipair unipairs[USHRT_MAX]; + _cleanup_free_ struct unipair* unipairs = NULL; int i, r; + unipairs = new(struct unipair, USHRT_MAX); + if (unipairs == NULL) { + log_error("Not enough memory to copy fonts"); + return; + } + /* get active, and 16 bit mask of used VT numbers */ r = ioctl(fd, VT_GETSTATE, &vcs); if (r < 0) { -- cgit v1.2.3-54-g00ecf From 306578e51853f0a18597b1d976ab402ff7a91a95 Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Mon, 16 May 2016 17:58:46 +0300 Subject: missing.h: add BTRFS_IOC_QUOTA_RESCAN_WAIT (#3266) --- src/basic/missing.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/basic/missing.h b/src/basic/missing.h index 22ea8f67cc..651e414395 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -389,6 +389,10 @@ struct btrfs_ioctl_quota_ctl_args { struct btrfs_ioctl_qgroup_limit_args) #endif +#ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT +#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46) +#endif + #ifndef BTRFS_FIRST_FREE_OBJECTID #define BTRFS_FIRST_FREE_OBJECTID 256 #endif -- cgit v1.2.3-54-g00ecf From 833f92ad39beca0e954e91e5764ffc83f8d0c1cf Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Mon, 16 May 2016 17:24:51 +0200 Subject: core: don't log job status message in case job was effectively NOP (#3199) We currently generate log message about unit being started even when unit was started already and job didn't do anything. This is because job was requested explicitly and hence became anchor job of the transaction thus we could not eliminate it. That is fine but, let's not pollute journal with useless log messages. $ systemctl start systemd-resolved $ systemctl start systemd-resolved $ systemctl start systemd-resolved Current state: $ journalctl -u systemd-resolved | grep Started May 05 15:31:42 rawhide systemd[1]: Started Network Name Resolution. May 05 15:31:59 rawhide systemd[1]: Started Network Name Resolution. May 05 15:32:01 rawhide systemd[1]: Started Network Name Resolution. After patch applied: $ journalctl -u systemd-resolved | grep Started May 05 16:42:12 rawhide systemd[1]: Started Network Name Resolution. Fixes #1723 --- src/core/dbus-job.c | 2 +- src/core/job.c | 24 +++++++++++++----------- src/core/job.h | 2 +- src/core/manager.c | 2 +- src/core/transaction.c | 2 +- src/core/unit.c | 12 ++++++------ 6 files changed, 23 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index 97a93fb2f1..ccf7453d47 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -75,7 +75,7 @@ int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error 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); + job_finish_and_invalidate(j, JOB_CANCELED, true, false); return sd_bus_reply_method_return(message, NULL); } diff --git a/src/core/job.c b/src/core/job.c index d9c5669c9f..7557874d4d 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -191,7 +191,7 @@ Job* job_install(Job *j) { if (uj) { if (job_type_is_conflicting(uj->type, j->type)) - job_finish_and_invalidate(uj, JOB_CANCELED, false); + job_finish_and_invalidate(uj, JOB_CANCELED, false, false); else { /* not conflicting, i.e. mergeable */ @@ -614,19 +614,19 @@ int job_run_and_invalidate(Job *j) { if (j) { if (r == -EALREADY) - r = job_finish_and_invalidate(j, JOB_DONE, true); + r = job_finish_and_invalidate(j, JOB_DONE, true, true); else if (r == -EBADR) - r = job_finish_and_invalidate(j, JOB_SKIPPED, true); + r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false); else if (r == -ENOEXEC) - r = job_finish_and_invalidate(j, JOB_INVALID, true); + r = job_finish_and_invalidate(j, JOB_INVALID, true, false); else if (r == -EPROTO) - r = job_finish_and_invalidate(j, JOB_ASSERT, true); + r = job_finish_and_invalidate(j, JOB_ASSERT, true, false); else if (r == -EOPNOTSUPP) - r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true); + r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false); else if (r == -EAGAIN) job_set_state(j, JOB_WAITING); else if (r < 0) - r = job_finish_and_invalidate(j, JOB_FAILED, true); + r = job_finish_and_invalidate(j, JOB_FAILED, true, false); } return r; @@ -827,11 +827,11 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) { if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE)) continue; - job_finish_and_invalidate(j, JOB_DEPENDENCY, true); + job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false); } } -int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { +int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) { Unit *u; Unit *other; JobType t; @@ -848,7 +848,9 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result)); - job_emit_status_message(u, t, result); + /* If this job did nothing to respective unit we don't log the status message */ + if (!already) + job_emit_status_message(u, t, result); job_add_to_dbus_queue(j); @@ -923,7 +925,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user 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); + job_finish_and_invalidate(j, JOB_TIMEOUT, true, false); failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg); diff --git a/src/core/job.h b/src/core/job.h index 856b0ce829..d359e8bb3e 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -219,7 +219,7 @@ void job_add_to_dbus_queue(Job *j); int job_start_timer(Job *j); int job_run_and_invalidate(Job *j); -int job_finish_and_invalidate(Job *j, JobResult result, bool recursive); +int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already); char *job_dbus_path(Job *j); diff --git a/src/core/manager.c b/src/core/manager.c index e192cd475d..7838f56fd2 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1494,7 +1494,7 @@ void manager_clear_jobs(Manager *m) { while ((j = hashmap_first(m->jobs))) /* No need to recurse. We're cancelling all jobs. */ - job_finish_and_invalidate(j, JOB_CANCELED, false); + job_finish_and_invalidate(j, JOB_CANCELED, false, false); } static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) { diff --git a/src/core/transaction.c b/src/core/transaction.c index d5370b2a14..e06a48a2f1 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -597,7 +597,7 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { /* Not invalidating recursively. Avoids triggering * OnFailure= actions of dependent jobs. Also avoids * invalidating our iterator. */ - job_finish_and_invalidate(j, JOB_CANCELED, false); + job_finish_and_invalidate(j, JOB_CANCELED, false, false); } } diff --git a/src/core/unit.c b/src/core/unit.c index dc8325515c..acbd3d0bdf 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1916,12 +1916,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su case JOB_VERIFY_ACTIVE: if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) - job_finish_and_invalidate(u->job, JOB_DONE, true); + job_finish_and_invalidate(u->job, JOB_DONE, true, false); else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) { unexpected = true; if (UNIT_IS_INACTIVE_OR_FAILED(ns)) - job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); + job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false); } break; @@ -1932,12 +1932,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (u->job->state == JOB_RUNNING) { if (ns == UNIT_ACTIVE) - job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true); + job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false); else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) { unexpected = true; if (UNIT_IS_INACTIVE_OR_FAILED(ns)) - job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); + job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false); } } @@ -1948,10 +1948,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su case JOB_TRY_RESTART: if (UNIT_IS_INACTIVE_OR_FAILED(ns)) - job_finish_and_invalidate(u->job, JOB_DONE, true); + job_finish_and_invalidate(u->job, JOB_DONE, true, false); else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { unexpected = true; - job_finish_and_invalidate(u->job, JOB_FAILED, true); + job_finish_and_invalidate(u->job, JOB_FAILED, true, false); } break; -- cgit v1.2.3-54-g00ecf From cd042078df2151d7824abf91107a0d4a8716e54f Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Mon, 16 May 2016 21:25:36 +0200 Subject: basic: Fix incorrect architecture mapping on sparc64. (#3274) --- src/basic/architecture.c | 2 +- src/basic/architecture.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/architecture.c b/src/basic/architecture.c index 8e2c2b02d2..b1c8e91f50 100644 --- a/src/basic/architecture.c +++ b/src/basic/architecture.c @@ -63,7 +63,7 @@ int uname_architecture(void) { #elif defined(__s390__) || defined(__s390x__) { "s390x", ARCHITECTURE_S390X }, { "s390", ARCHITECTURE_S390 }, -#elif defined(__sparc__) || defined(__sparc64__) +#elif defined(__sparc__) { "sparc64", ARCHITECTURE_SPARC64 }, { "sparc", ARCHITECTURE_SPARC }, #elif defined(__mips__) || defined(__mips64__) diff --git a/src/basic/architecture.h b/src/basic/architecture.h index 91ec108e04..b3e4d85906 100644 --- a/src/basic/architecture.h +++ b/src/basic/architecture.h @@ -116,7 +116,7 @@ int uname_architecture(void); #elif defined(__s390__) # define native_architecture() ARCHITECTURE_S390 # define LIB_ARCH_TUPLE "s390-linux-gnu" -#elif defined(__sparc64__) +#elif defined(__sparc__) && defined (__arch64__) # define native_architecture() ARCHITECTURE_SPARC64 # define LIB_ARCH_TUPLE "sparc64-linux-gnu" #elif defined(__sparc__) -- cgit v1.2.3-54-g00ecf From e2c9192a4529a6d0a9d8ba824c3822eeb7d7c002 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 17 May 2016 10:27:26 +0200 Subject: vconsole: add log_oom() where appropriate --- src/vconsole/vconsole-setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 08ae4aad27..1118118450 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -199,8 +199,8 @@ static void font_copy_to_all_vcs(int fd) { int i, r; unipairs = new(struct unipair, USHRT_MAX); - if (unipairs == NULL) { - log_error("Not enough memory to copy fonts"); + if (!unipairs) { + log_oom(); return; } -- cgit v1.2.3-54-g00ecf From 87c7c9d75e8f5f671824deb0dcc4d05f4b4ab11b Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 17 May 2016 08:01:01 -0400 Subject: network: test MAC address parsing networkd currently silently accepts some strings as MAC addresses that it probably shouldn't (like "ab:cd:ef:12:34:56:78" and "ab:cd:ef:12:3 4:56"). Add tests to MAC address parsing to ensure that we only accept valid MAC addresses, and that we accept the three most common forms of MAC address (colon-delimited hex, IEEE, and Cisco) Several of these tests currently fail, but another commit in this series will resolve them. --- src/network/test-networkd-conf.c | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'src') diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index 9bd30b82c6..0e1a18457d 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -21,9 +21,11 @@ #include "log.h" #include "macro.h" #include "string-util.h" +#include "ether-addr-util.h" #include "networkd-conf.h" #include "networkd-network.h" +#include "network-internal.h" static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected) { DUIDType actual = 0; @@ -60,6 +62,21 @@ static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, cons } } +static void test_config_parse_hwaddr_one(const char *rvalue, int ret, const struct ether_addr* expected) { + struct ether_addr *actual = NULL; + int r; + + r = config_parse_hwaddr("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL); + assert_se(ret == r); + if (expected) { + assert_se(actual); + assert(ether_addr_equal(expected, actual)); + } else { + assert_se(actual == NULL); + } + free(actual); +} + #define BYTES_0_128 "0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e:7f:80" #define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80} @@ -80,12 +97,46 @@ static void test_config_parse_duid_rawdata(void) { test_config_parse_duid_rawdata_one(BYTES_0_128 + 2, 0, &(DUID){0, 128, BYTES_1_128}); } +static void test_config_parse_hwaddr(void) { + const struct ether_addr t[] = { + { .ether_addr_octet = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff } }, + { .ether_addr_octet = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } }, + }; + test_config_parse_hwaddr_one("", 0, NULL); + test_config_parse_hwaddr_one("no:ta:ma:ca:dd:re", 0, NULL); + test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:fx", 0, NULL); + test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff", 0, &t[0]); + test_config_parse_hwaddr_one(" aa:bb:cc:dd:ee:ff", 0, &t[0]); + test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\n", 0, &t[0]); + test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\nxxx", 0, NULL); + test_config_parse_hwaddr_one("aa:bb:cc: dd:ee:ff", 0, NULL); + test_config_parse_hwaddr_one("aa:bb:cc:d d:ee:ff", 0, NULL); + test_config_parse_hwaddr_one("aa:bb:cc:dd:ee", 0, NULL); + test_config_parse_hwaddr_one("9:aa:bb:cc:dd:ee:ff", 0, NULL); + test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff:gg", 0, NULL); + test_config_parse_hwaddr_one("aa:Bb:CC:dd:ee:ff", 0, &t[0]); + test_config_parse_hwaddr_one("01:23:45:67:89:aB", 0, &t[1]); + test_config_parse_hwaddr_one("1:23:45:67:89:aB", 0, &t[1]); + test_config_parse_hwaddr_one("aa-bb-cc-dd-ee-ff", 0, &t[0]); + test_config_parse_hwaddr_one("AA-BB-CC-DD-EE-FF", 0, &t[0]); + test_config_parse_hwaddr_one("01-23-45-67-89-ab", 0, &t[1]); + test_config_parse_hwaddr_one("aabb.ccdd.eeff", 0, &t[0]); + test_config_parse_hwaddr_one("0123.4567.89ab", 0, &t[1]); + test_config_parse_hwaddr_one("123.4567.89ab.", 0, NULL); + test_config_parse_hwaddr_one("aabbcc.ddeeff", 0, NULL); + test_config_parse_hwaddr_one("aabbccddeeff", 0, NULL); + test_config_parse_hwaddr_one("aabbccddee:ff", 0, NULL); + test_config_parse_hwaddr_one("012345.6789ab", 0, NULL); + test_config_parse_hwaddr_one("123.4567.89ab", 0, &t[1]); +} + int main(int argc, char **argv) { log_parse_environment(); log_open(); test_config_parse_duid_type(); test_config_parse_duid_rawdata(); + test_config_parse_hwaddr(); return 0; } -- cgit v1.2.3-54-g00ecf From 1a7906ae914fd233305fff0acf4b9138ff944209 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 17 May 2016 09:44:32 -0400 Subject: basic: define HEXDIGITS define HEXDIGITS alongside DIGITS, and use it where it's already useful. We'll use it again shortly when parsing MAC addresses. --- src/basic/string-util.h | 1 + src/test/test-fileio.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/string-util.h b/src/basic/string-util.h index ad0c813761..139cc8c91b 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -37,6 +37,7 @@ #define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS #define ALPHANUMERICAL LETTERS DIGITS +#define HEXDIGITS DIGITS "abcdefABCDEF" #define streq(a,b) (strcmp((a),(b)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index ec9f173da2..79609765e0 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -289,7 +289,7 @@ static void test_capeff(void) { assert_se(r == 0); assert_se(*capeff); - p = capeff[strspn(capeff, DIGITS "abcdefABCDEF")]; + p = capeff[strspn(capeff, HEXDIGITS)]; assert_se(!p || isspace(p)); } } -- cgit v1.2.3-54-g00ecf From dd4d201ab1c9456e1bffc39f9dec00a4a4619084 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 17 May 2016 11:00:29 -0400 Subject: util-lib: add ether_addr_from_string() This isn't quite symmetrical to in_addr_from_string() because it also returns an offset indicating how much of the string was consumed by the matched pattern. This offset reporting is needed for either of the following use cases: * verifying the lack of trailing garbage after such an address * parsing subsequent data from the same string --- src/basic/ether-addr-util.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ src/basic/ether-addr-util.h | 2 ++ 2 files changed, 71 insertions(+) (limited to 'src') diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index a4d8d656da..5697e8d132 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -23,6 +23,7 @@ #include "ether-addr-util.h" #include "macro.h" +#include "string-util.h" char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { assert(addr); @@ -54,3 +55,71 @@ bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) { a->ether_addr_octet[4] == b->ether_addr_octet[4] && a->ether_addr_octet[5] == b->ether_addr_octet[5]; } + +int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) { + size_t pos = 0, n, field; + char sep = '\0'; + const char *hex = HEXDIGITS, *hexoff; + size_t x; + bool touched; + +#define parse_fields(v) \ + for (field = 0; field < ELEMENTSOF(v); field++) { \ + touched = false; \ + for (n = 0; n < (2 * sizeof(v[0])); n++) { \ + if (s[pos] == '\0') \ + break; \ + hexoff = strchr(hex, s[pos]); \ + if (hexoff == NULL) \ + break; \ + assert(hexoff >= hex); \ + x = hexoff - hex; \ + if (x >= 16) \ + x -= 6; /* A-F */ \ + assert(x < 16); \ + touched = true; \ + v[field] <<= 4; \ + v[field] += x; \ + pos++; \ + } \ + if (!touched) \ + return -EINVAL; \ + if (field < (ELEMENTSOF(v)-1)) { \ + if (s[pos] != sep) \ + return -EINVAL; \ + else \ + pos++; \ + } \ + } + + assert(s); + assert(ret); + + sep = s[strspn(s, hex)]; + if (sep == '\n') + return -EINVAL; + if (strchr(":.-", sep) == NULL) + return -EINVAL; + + if (sep == '.') { + uint16_t shorts[3] = { 0 }; + + parse_fields(shorts); + + for (n = 0; n < ELEMENTSOF(shorts); n++) { + ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8); + ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff); + } + } else { + struct ether_addr out = { .ether_addr_octet = { 0 } }; + + parse_fields(out.ether_addr_octet); + + for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++) + ret->ether_addr_octet[n] = out.ether_addr_octet[n]; + } + + if (offset) + *offset = pos; + return 0; +} diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 074363793e..74e125a95f 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -35,3 +35,5 @@ bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b); static inline bool ether_addr_is_null(const struct ether_addr *addr) { return ether_addr_equal(addr, ÐER_ADDR_NULL); } + +int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset); -- cgit v1.2.3-54-g00ecf From 9ed8b06c9be4a5efae432d5cf4b1c47d03e6f107 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 17 May 2016 16:43:36 -0400 Subject: network: rely on ether_addr_from_string instead of sscanf --- src/libsystemd-network/network-internal.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 2badcdff58..046b0f9393 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -27,6 +27,7 @@ #include "condition.h" #include "conf-parser.h" #include "dhcp-lease-internal.h" +#include "ether-addr-util.c" #include "hexdecoct.h" #include "log.h" #include "network-internal.h" @@ -272,6 +273,8 @@ int config_parse_hwaddr(const char *unit, void *userdata) { struct ether_addr **hwaddr = data; struct ether_addr *n; + const char *start; + size_t offset; int r; assert(filename); @@ -283,14 +286,10 @@ int config_parse_hwaddr(const char *unit, if (!n) return log_oom(); - r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &n->ether_addr_octet[0], - &n->ether_addr_octet[1], - &n->ether_addr_octet[2], - &n->ether_addr_octet[3], - &n->ether_addr_octet[4], - &n->ether_addr_octet[5]); - if (r != 6) { + start = rvalue + strspn(rvalue, WHITESPACE); + r = ether_addr_from_string(start, n, &offset); + + if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) { log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue); free(n); return 0; -- cgit v1.2.3-54-g00ecf From a363a2e45f67eea5cc0a8fbbfc4a514f1b015cf7 Mon Sep 17 00:00:00 2001 From: Jonathan Boulle Date: Wed, 18 May 2016 01:30:37 +0200 Subject: core/dbus: use free_and_strdup to simplify code (#3279) Makes it consistent with the other branches here. --- src/core/dbus-execute.c | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 9dfca14914..646bd779a2 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -839,16 +839,8 @@ int bus_exec_context_set_transient_property( if (isempty(uu)) c->user = mfree(c->user); - else { - char *t; - - t = strdup(uu); - if (!t) - return -ENOMEM; - - free(c->user); - c->user = t; - } + else if (free_and_strdup(&c->user, uu) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu); } @@ -866,16 +858,8 @@ int bus_exec_context_set_transient_property( if (isempty(gg)) c->group = mfree(c->group); - else { - char *t; - - t = strdup(gg); - if (!t) - return -ENOMEM; - - free(c->group); - c->group = t; - } + else if (free_and_strdup(&c->group, gg) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg); } @@ -890,18 +874,10 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { - if (isempty(id)) { + if (isempty(id)) c->syslog_identifier = mfree(c->syslog_identifier); - } else { - char *t; - - t = strdup(id); - if (!t) - return -ENOMEM; - - free(c->syslog_identifier); - c->syslog_identifier = t; - } + else if (free_and_strdup(&c->syslog_identifier, id) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id); } -- cgit v1.2.3-54-g00ecf From 77ff6022fa30005f8e965c42064e0274d329b6c0 Mon Sep 17 00:00:00 2001 From: Clemens Gruber Date: Wed, 18 May 2016 01:34:25 +0200 Subject: networkd: Add EmitRouter= option for DHCP Server (#3251) Add an option to disable appending DHCP option 3 (Router) to the DHCP OFFER and ACK packets. This commit adds the boolean option EmitRouter= for the [DHCPServer] section in .network files. Rationale: On embedded devices, it is very useful to have a DHCP server running on an USB OTG ethernet gadget interface to avoid manual setup on the client PCs, but it should only serve IP addresses, no route(r)s. Otherwise, Windows clients experience network connectivity issues, due to them using the address set in DHCP option 3 as default gateway. Signed-off-by: Clemens Gruber --- NEWS | 32 +++++++++++++++------------ man/systemd.network.xml | 10 +++++++++ src/libsystemd-network/dhcp-server-internal.h | 2 ++ src/libsystemd-network/sd-dhcp-server.c | 31 +++++++++++++++++++------- src/network/networkd-link.c | 6 +++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 1 + src/systemd/sd-dhcp-server.h | 1 + 9 files changed, 63 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/NEWS b/NEWS index ff2dd9abbf..a6e0581879 100644 --- a/NEWS +++ b/NEWS @@ -180,22 +180,26 @@ CHANGES WITH 230 in spe: service. Please leave PrivateDevices= off if you run into problems with this. + * The systemd-networkd DHCP server gained the option EmitRouter=, which + defaults to yes, to configure if the DHCP Option 3 (Router) should be + emitted. + Contributions from: Alban Crequy, Alexander Kuleshov, Alex Crawford, Andrew Eikum, Beniamino Galvani, Benjamin Robin, Benjamin ROBIN, Biao - Lu, Bjørnar Ness, Calvin Owens, Christian Hesse, Colin Guthrie, Daniel - J Walsh, Daniel Mack, Dan Nicholson, daurnimator, David Herrmann, David - R. Hedges, Elias Probst, Emmanuel Gil Peyrot, EMOziko, Evgeny - Vereshchagin, Federico, Felipe Sateler, Filipe Brandenburger, Franck - Bui, frankheckenbach, Georgia Brikis, Harald Hoyer, Hendrik Brueckner, - Hristo Venev, Iago López Galeiras, Ian Kelling, Ismo Puustinen, Jakub - Wilk, Jaroslav Škarvada, Jeff Huang, Joel Holdsworth, kayrus, Klearchos - Chaloulos, Lennart Poettering, Lubomir Rintel, Lukas Nykryn, Lukáš - Nykrýn, Mantas Mikulėnas, Marcel Holtmann, Martin Pitt, Michael Biebl, - michaelolbrich, Michał Bartoszkiewicz, Michal Koutný, Michal Sekletar, - Mike Frysinger, Mike Gilbert, Mingcong Bai, Ming Lin, mulkieran, - muzena, Nalin Dahyabhai, Naohiro Aota, Nathan McSween, Nicolas - Braud-Santoni, Patrik Flykt, Peter Hutterer, Petr Lautrbach, Petros - Angelatos, Piotr Drąg, Rabin Vincent, Robert Węcławski, Ronny + Lu, Bjørnar Ness, Calvin Owens, Christian Hesse, Clemens Gruber, Colin + Guthrie, Daniel J Walsh, Daniel Mack, Dan Nicholson, daurnimator, David + Herrmann, David R. Hedges, Elias Probst, Emmanuel Gil Peyrot, EMOziko, + Evgeny Vereshchagin, Federico, Felipe Sateler, Filipe Brandenburger, + Franck Bui, frankheckenbach, Georgia Brikis, Harald Hoyer, Hendrik + Brueckner, Hristo Venev, Iago López Galeiras, Ian Kelling, Ismo + Puustinen, Jakub Wilk, Jaroslav Škarvada, Jeff Huang, Joel Holdsworth, + kayrus, Klearchos Chaloulos, Lennart Poettering, Lubomir Rintel, Lukas + Nykryn, Lukáš Nykrýn, Mantas Mikulėnas, Marcel Holtmann, Martin Pitt, + Michael Biebl, michaelolbrich, Michał Bartoszkiewicz, Michal Koutný, + Michal Sekletar, Mike Frysinger, Mike Gilbert, Mingcong Bai, Ming Lin, + mulkieran, muzena, Nalin Dahyabhai, Naohiro Aota, Nathan McSween, + Nicolas Braud-Santoni, Patrik Flykt, Peter Hutterer, Petr Lautrbach, + Petros Angelatos, Piotr Drąg, Rabin Vincent, Robert Węcławski, Ronny Chevalier, Samuel Tardieu, Stefan Schallenberg, Steven Siloti, Susant Sahani, Sylvain Plantefève, Taylor Smock, tblume, Tejun Heo, Thomas Blume, Thomas Haller, Thomas Hindoe Paaboel Andersen, Thomas diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 70e3804746..d917fe2c12 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -981,6 +981,16 @@ DNS=. + + EmitRouter= + + Similar to the EmitDNS= + setting described above, this setting configures whether the + DHCP lease should contain the router option. The same syntax, + propagation semantics and defaults apply as for + EmitDNS=. + + EmitTimezone= Timezone= diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index adb557167a..0c76956fad 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -63,6 +63,8 @@ struct sd_dhcp_server { struct in_addr *ntp, *dns; unsigned n_ntp, n_dns; + bool emit_router; + Hashmap *leases_by_client_id; DHCPLease **bound_leases; DHCPLease invalid_lease; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 9adf8ec19d..fb335337c4 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -468,10 +468,12 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, if (r < 0) return r; - r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_ROUTER, 4, &server->address); - if (r < 0) - return r; + if (server->emit_router) { + r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, + SD_DHCP_OPTION_ROUTER, 4, &server->address); + if (r < 0) + return r; + } r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset); if (r < 0) @@ -505,10 +507,12 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, if (r < 0) return r; - r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_ROUTER, 4, &server->address); - if (r < 0) - return r; + if (server->emit_router) { + r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, + SD_DHCP_OPTION_ROUTER, 4, &server->address); + if (r < 0) + return r; + } if (server->n_dns > 0) { r = dhcp_option_append( @@ -1158,3 +1162,14 @@ int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], u return 1; } + +int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) { + assert_return(server, -EINVAL); + + if (enabled == server->emit_router) + return 0; + + server->emit_router = enabled; + + return 1; +} diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f3a79b0ec8..16a3609a0b 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1020,6 +1020,12 @@ static int link_enter_set_addresses(Link *link) { log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m"); } + r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to set router emission for DHCP server: %m"); + return r; + } + if (link->network->dhcp_server_emit_timezone) { _cleanup_free_ char *buffer = NULL; const char *tz = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 4425ee4e2f..03e4e3b39f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -95,6 +95,7 @@ DHCPServer.EmitDNS, config_parse_bool, DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0 DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp) DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0 +DHCPServer.EmitRouter, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_router) DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone) DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 206c270e50..dd89b3770c 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -113,6 +113,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->dhcp_server_emit_dns = true; network->dhcp_server_emit_ntp = true; + network->dhcp_server_emit_router = true; network->dhcp_server_emit_timezone = true; network->use_bpdu = true; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 4cd0fa4ab8..91099161ce 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -127,6 +127,7 @@ struct Network { bool dhcp_server_emit_ntp; struct in_addr *dhcp_server_ntp; unsigned n_dhcp_server_ntp; + bool dhcp_server_emit_router; bool dhcp_server_emit_timezone; char *dhcp_server_timezone; usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec; diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index fcef083ce6..d4517a26d6 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -51,6 +51,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone); int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n); int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr dns[], unsigned n); +int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled); int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t); int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t); -- cgit v1.2.3-54-g00ecf From fe7ca21acfb9fcef6cf8ce9f945377667a26a27c Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 18 May 2016 07:06:43 +0530 Subject: networkd: add route expiration handler (#3242) Fix for #3232. --- src/network/networkd-route.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 2b3970289e..f001de772a 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -406,15 +406,45 @@ int route_remove(Route *route, Link *link, return 0; } +static int route_expire_callback(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(rtnl); + assert(m); + assert(link); + assert(link->ifname); + assert(link->link_messages > 0); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + link->link_messages--; + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EEXIST) + log_link_warning_errno(link, r, "could not remove route: %m"); + + if (link->link_messages == 0) + log_link_debug(link, "route removed"); + + return 1; +} + int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) { Route *route = userdata; int r; assert(route); - r = route_remove(route, route->link, NULL); + r = route_remove(route, route->link, route_expire_callback); if (r < 0) log_warning_errno(r, "Could not remove route: %m"); + else { + /* route may not be exist in kernel. If we fail still remove it */ + route->link->link_messages++; + route_free(route); + } return 1; } -- cgit v1.2.3-54-g00ecf From 7209086d8a0df862d04428877c2d2b9e562034f1 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 18 May 2016 08:29:56 +0530 Subject: networkd: do not update state or IPv6LL address if link is failed or lingering This is partial fix for #2228 and #2977, #3204. bridge-test: netdev ready docker0: Gained IPv6LL wlan0: Gained IPv6LL eth0: Gained IPv6LL Enumeration completed bridge-test: netdev exists, using existing without changing its parameters vboxnet0: IPv6 enabled for interface: Success lo: Configured docker0: Could not drop address: No such process vboxnet0: Gained carrier wlan0: Could not drop address: No such process eth0: Could not drop address: No such process eth0: Could not drop address: No such process eth0: Could not drop address: No such process vboxnet0: Gained IPv6LL vboxnet0: Could not set NDisc route or address: Invalid argument vboxnet0: Failed [New Thread 0x7ffff6505700 (LWP 1111)] [Thread 0x7ffff6505700 (LWP 1111) exited] Assertion 'link->state == LINK_STATE_SETTING_ROUTES' failed at src/network/networkd-link.c:672, function link_enter_configured(). Aborting. Program received signal SIGABRT, Aborted. 0x00007ffff6dc6a98 in raise () from /lib64/libc.so.6 Missing separate debuginfos, use: dnf debuginfo-install iptables-1.4.21-15.fc23.x86_64 libattr-2.4.47-14.fc23.x86_64 libidn-1.32-1.fc23.x86_64 pcre-8.38-7.fc23.x86_64 Debugging (gdb) bt "link->state == LINK_STATE_SETTING_ROUTES", file=0x5555556a34c8 "src/network/networkd-link.c", line=672, func=0x5555556a56d0 <__PRETTY_FUNCTION__.14850> "link_enter_configured") at src/basic/log.c:788 src/network/networkd-link.c:672 src/network/networkd-link.c:720 flags=0 '\000', scope=0 '\000', cinfo=0x7fffffffe020) at src/network/networkd-address.c:344 (rtnl=0x5555556eded0, message=0x55555570ff20, userdata=0x5555556ec590) at src/network/networkd-manager.c:604 m=0x55555570ff20) at src/libsystemd/sd-netlink/sd-netlink.c:365 at src/libsystemd/sd-netlink/sd-netlink.c:395 ret=0x0) at src/libsystemd/sd-netlink/sd-netlink.c:429 revents=1, userdata=0x5555556eded0) at src/libsystemd/sd-netlink/sd-netlink.c:723 src/libsystemd/sd-event/sd-event.c:2268 src/libsystemd/sd-event/sd-event.c:2629 timeout=18446744073709551615) at src/libsystemd/sd-event/sd-event.c:2688 bus=0x5555556eeba0, name=0x55555568a2f5 "org.freedesktop.network1", timeout=30000000, check_idle=0x55555556adb6 , userdata=0x5555556ec590) at src/shared/bus-util.c:134 src/network/networkd-manager.c:1130 src/network/networkd.c:127 (gdb) f 3 src/network/networkd-link.c:672 672 assert(link->state == LINK_STATE_SETTING_ROUTES); (gdb) p link->state $1 = LINK_STATE_FAILED We should not be in this state . even if vboxnet0 failed we went into this state. vboxnet0: Could not set NDisc route or address: Invalid argument vboxnet0: Failed --- src/network/networkd-address.c | 29 ++++++++++++++++------------- src/network/networkd-link.c | 3 +++ 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index b2de1f9d57..976f333f7e 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -331,6 +331,10 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s assert(address); assert(cinfo); + assert_return(address->link, 1); + + if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; ready = address_is_ready(address); @@ -338,19 +342,18 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s address->scope = scope; address->cinfo = *cinfo; - if (address->link) { - link_update_operstate(address->link); - - if (!ready && address_is_ready(address)) { - link_check_ready(address->link); - - if (address->family == AF_INET6 && - in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && - in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { - r = link_ipv6ll_gained(address->link, &address->in_addr.in6); - if (r < 0) - return r; - } + link_update_operstate(address->link); + + if (!ready && address_is_ready(address)) { + link_check_ready(address->link); + + if (address->family == AF_INET6 && + in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && + in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { + + r = link_ipv6ll_gained(address->link, &address->in_addr.in6); + if (r < 0) + return r; } } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 16a3609a0b..a021fc886f 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -686,6 +686,9 @@ void link_check_ready(Link *link) { assert(link); + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + if (!link->network) return; -- cgit v1.2.3-54-g00ecf From f150100ad43125682cfd01da4cb92ffc8eb17a09 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 18 May 2016 18:19:40 +0530 Subject: networkd: Drop IPv6LL address when link is down Now we are not dropping the IPv6LL address when link is down. So next time when link is up and before kernel acquired this address we are using the old address. When the link is down kernel tells us that this address is no longer valid . Let's remove this address and again when kernel tells us that the address is added let's use it. fixes #3264 --- src/network/networkd-address.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 976f333f7e..367c340e08 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -98,6 +98,9 @@ void address_free(Address *address) { if (address->link) { set_remove(address->link->addresses, address); set_remove(address->link->addresses_foreign, address); + + if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address)) + memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr)); } free(address); -- cgit v1.2.3-54-g00ecf From 9be572497df8dd0a076c3a2c9142e25b1106aa60 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 18 May 2016 13:50:56 -0700 Subject: core: introduce CGroupIOLimitType enums Currently, there are two cgroup IO limits, bandwidth max for read and write, and they are hard-coded in various places. This is fine for two limits but IO is expected to grow more limits - low, high and max limits for bandwidth and IOPS - and hard-coding each limit won't make sense. This patch replaces hard-coded limits with an array indexed by CGroupIOLimitType and accompanying string and default value tables so that new limits can be added trivially. --- src/basic/cgroup-util.c | 12 +++++++++++ src/basic/cgroup-util.h | 14 +++++++++++++ src/core/cgroup.c | 47 ++++++++++++++++++++----------------------- src/core/cgroup.h | 4 ++-- src/core/dbus-cgroup.c | 50 +++++++++++++++------------------------------- src/core/load-fragment.c | 21 +++++++++---------- src/shared/bus-unit-util.c | 3 +-- src/systemctl/systemctl.c | 2 +- 8 files changed, 77 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index ff57cf30b7..8eab100748 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2269,6 +2269,18 @@ int cg_weight_parse(const char *s, uint64_t *ret) { return 0; } +const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = { + [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX, + [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX, +}; + +static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = { + [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax", + [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax", +}; + +DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType); + int cg_cpu_shares_parse(const char *s, uint64_t *ret) { uint64_t u; int r; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index a696c1fa60..0d96fb6b76 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -72,6 +72,20 @@ static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) { (x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX); } +/* IO limits on unified hierarchy */ +typedef enum CGroupIOLimitType { + CGROUP_IO_RBPS_MAX, + CGROUP_IO_WBPS_MAX, + + _CGROUP_IO_LIMIT_TYPE_MAX, + _CGROUP_IO_LIMIT_TYPE_INVALID = -1 +} CGroupIOLimitType; + +extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX]; + +const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_; +CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_; + /* Special values for the cpu.shares attribute */ #define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) #define CGROUP_CPU_SHARES_MIN UINT64_C(2) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 4f1637ffe9..0b902fa6f7 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -184,20 +184,16 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { LIST_FOREACH(device_limits, il, c->io_device_limits) { char buf[FORMAT_BYTES_MAX]; - - if (il->rbps_max != CGROUP_LIMIT_MAX) - fprintf(f, - "%sIOReadBandwidthMax=%s %s\n", - prefix, - il->path, - format_bytes(buf, sizeof(buf), il->rbps_max)); - - if (il->wbps_max != CGROUP_LIMIT_MAX) - fprintf(f, - "%sIOWriteBandwidthMax=%s %s\n", - prefix, - il->path, - format_bytes(buf, sizeof(buf), il->wbps_max)); + CGroupIOLimitType type; + + for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) + if (il->limits[type] != cgroup_io_limit_defaults[type]) + fprintf(f, + "%s%s=%s %s\n", + prefix, + cgroup_io_limit_type_to_string(type), + il->path, + format_bytes(buf, sizeof(buf), il->limits[type])); } LIST_FOREACH(device_weights, w, c->blockio_device_weights) @@ -442,9 +438,9 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { - char rbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max"; - char wbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max"; + char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)]; char buf[DECIMAL_STR_MAX(dev_t)*2+2+(5+DECIMAL_STR_MAX(uint64_t)+1)*2]; + CGroupIOLimitType type; dev_t dev; unsigned n = 0; @@ -452,17 +448,18 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M if (r < 0) continue; - if (l->rbps_max != CGROUP_LIMIT_MAX) { - xsprintf(rbps_buf, "%" PRIu64, l->rbps_max); - n++; - } - - if (l->wbps_max != CGROUP_LIMIT_MAX) { - xsprintf(wbps_buf, "%" PRIu64, l->wbps_max); - n++; + for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) { + if (l->limits[type] != cgroup_io_limit_defaults[type]) { + xsprintf(limit_bufs[type], "%" PRIu64, l->limits[type]); + n++; + } else { + xsprintf(limit_bufs[type], "%s", + l->limits[type] == CGROUP_LIMIT_MAX ? "max" : "0"); + } } - xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev), rbps_buf, wbps_buf); + xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev), + limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX]); r = cg_set_attribute("io", path, "io.max", buf); if (r < 0) log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, diff --git a/src/core/cgroup.h b/src/core/cgroup.h index a533923072..1907461f7e 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -23,6 +23,7 @@ #include "list.h" #include "time-util.h" +#include "cgroup-util.h" typedef struct CGroupContext CGroupContext; typedef struct CGroupDeviceAllow CGroupDeviceAllow; @@ -64,8 +65,7 @@ struct CGroupIODeviceWeight { struct CGroupIODeviceLimit { LIST_FIELDS(CGroupIODeviceLimit, device_limits); char *path; - uint64_t rbps_max; - uint64_t wbps_max; + uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX]; }; struct CGroupBlockIODeviceWeight { diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index a2a4a6249c..4372828e30 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -80,17 +80,13 @@ static int property_get_io_device_limits( return r; LIST_FOREACH(device_limits, l, c->io_device_limits) { - uint64_t v; + CGroupIOLimitType type; - if (streq(property, "IOReadBandwidthMax")) - v = l->rbps_max; - else - v = l->wbps_max; - - if (v == CGROUP_LIMIT_MAX) + type = cgroup_io_limit_type_from_string(property); + if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type]) continue; - r = sd_bus_message_append(reply, "(st)", l->path, v); + r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]); if (r < 0) return r; } @@ -273,6 +269,7 @@ int bus_cgroup_set_property( UnitSetPropertiesMode mode, sd_bus_error *error) { + CGroupIOLimitType iol_type; int r; assert(u); @@ -416,15 +413,11 @@ int bus_cgroup_set_property( return 1; - } else if (streq(name, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax")) { + } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) { const char *path; - bool read = true; unsigned n = 0; uint64_t u64; - if (streq(name, "IOWriteBandwidthMax")) - read = false; - r = sd_bus_message_enter_container(message, 'a', "(st)"); if (r < 0) return r; @@ -442,6 +435,8 @@ int bus_cgroup_set_property( } if (!a) { + CGroupIOLimitType type; + a = new0(CGroupIODeviceLimit, 1); if (!a) return -ENOMEM; @@ -452,16 +447,13 @@ int bus_cgroup_set_property( return -ENOMEM; } - a->rbps_max = CGROUP_LIMIT_MAX; - a->wbps_max = CGROUP_LIMIT_MAX; + for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) + a->limits[type] = cgroup_io_limit_defaults[type]; LIST_PREPEND(device_limits, c->io_device_limits, a); } - if (read) - a->rbps_max = u64; - else - a->wbps_max = u64; + a->limits[iol_type] = u64; } n++; @@ -481,10 +473,7 @@ int bus_cgroup_set_property( if (n == 0) { LIST_FOREACH(device_limits, a, c->io_device_limits) - if (read) - a->rbps_max = CGROUP_LIMIT_MAX; - else - a->wbps_max = CGROUP_LIMIT_MAX; + a->limits[iol_type] = cgroup_io_limit_defaults[iol_type]; } unit_invalidate_cgroup(u, CGROUP_MASK_IO); @@ -493,17 +482,10 @@ int bus_cgroup_set_property( if (!f) return -ENOMEM; - if (read) { - fputs("IOReadBandwidthMax=\n", f); - LIST_FOREACH(device_limits, a, c->io_device_limits) - if (a->rbps_max != CGROUP_LIMIT_MAX) - fprintf(f, "IOReadBandwidthMax=%s %" PRIu64 "\n", a->path, a->rbps_max); - } else { - fputs("IOWriteBandwidthMax=\n", f); - LIST_FOREACH(device_limits, a, c->io_device_limits) - if (a->wbps_max != CGROUP_LIMIT_MAX) - fprintf(f, "IOWriteBandwidthMax=%s %" PRIu64 "\n", a->path, a->wbps_max); - } + fprintf(f, "%s=\n", name); + LIST_FOREACH(device_limits, a, c->io_device_limits) + if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type]) + fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]); r = fflush_and_check(f); if (r < 0) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index cea615132a..9626d861c5 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3023,9 +3023,9 @@ int config_parse_io_limit( _cleanup_free_ char *path = NULL; CGroupIODeviceLimit *l = NULL, *t; CGroupContext *c = data; + CGroupIOLimitType type; const char *limit; uint64_t num; - bool read; size_t n; int r; @@ -3033,14 +3033,12 @@ int config_parse_io_limit( assert(lvalue); assert(rvalue); - read = streq("IOReadBandwidthMax", lvalue); + type = cgroup_io_limit_type_from_string(lvalue); + assert(type >= 0); if (isempty(rvalue)) { LIST_FOREACH(device_limits, l, c->io_device_limits) - if (read) - l->rbps_max = CGROUP_LIMIT_MAX; - else - l->wbps_max = CGROUP_LIMIT_MAX; + l->limits[type] = cgroup_io_limit_defaults[type]; return 0; } @@ -3080,22 +3078,21 @@ int config_parse_io_limit( } if (!l) { + CGroupIOLimitType ttype; + l = new0(CGroupIODeviceLimit, 1); if (!l) return log_oom(); l->path = path; path = NULL; - l->rbps_max = CGROUP_LIMIT_MAX; - l->wbps_max = CGROUP_LIMIT_MAX; + for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++) + l->limits[ttype] = cgroup_io_limit_defaults[ttype]; LIST_PREPEND(device_limits, c->io_device_limits, l); } - if (read) - l->rbps_max = num; - else - l->wbps_max = num; + l->limits[type] = num; return 0; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 8f0df84793..03ae67ae7b 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -284,8 +284,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm); } - } else if (STR_IN_SET(field, "IOReadBandwidthMax", "IOWriteBandwidthMax", - "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { + } else if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(st)", 0); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0faf37d320..2097c5a660 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -4447,7 +4447,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return 0; - } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax") || + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (cgroup_io_limit_type_from_string(name) >= 0 || streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) { const char *path; uint64_t bandwidth; -- cgit v1.2.3-54-g00ecf From ac06a0cf8a5c5bd58bfa022408361e982f100bcb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 18 May 2016 13:50:56 -0700 Subject: core: add support for IOReadIOPSMax and IOWriteIOPSMax cgroup IO controller supports maximum limits for both bandwidth and IOPS but systemd resource control currently only supports bandwidth limits. This patch adds support for IOReadIOPSMax and IOWriteIOPSMax when unified cgroup hierarchy is in use. It isn't difficult to also add BlockIOReadIOPS and BlockIOWriteIOPS for legacy hierarchies but IO control on legacy hierarchies is half-broken anyway, so let's leave it alone for now. --- man/systemd.resource-control.xml | 24 ++++++++++++++++++++++++ src/basic/cgroup-util.c | 4 ++++ src/basic/cgroup-util.h | 2 ++ src/core/cgroup.c | 7 ++++--- src/core/dbus-cgroup.c | 2 ++ src/core/load-fragment-gperf.gperf.m4 | 2 ++ 6 files changed, 38 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 313a49a959..8a95e1196b 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -336,6 +336,30 @@ + + IOReadIOPSMax=device IOPS + IOWriteIOPSMax=device IOPS + + + Set the per-device overall block I/O IOs-Per-Second maximum limit for the executed processes, if the + unified control group hierarchy is used on the system. This limit is not work-conserving and the executed + processes are not allowed to use more even if the device has idle capacity. Takes a space-separated pair of + a file path and an IOPS value to specify the device specific IOPS. The file path may be a path to a block + device node, or as any other file in which case the backing block device of the file system of the file is + used. If the IOPS is suffixed with K, M, G, or T, the specified IOPS is parsed as KiloIOPS, MegaIOPS, + GigaIOPS, or TeraIOPS, respectively, to the base of 1000. (Example: + "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 1K"). This controls the io.max control + group attributes. Use this option multiple times to set IOPS limits for multiple devices. For details about + this control group attribute, see cgroup-v2.txt. + + + Implies IOAccounting=true. + + This setting is supported only if the unified control group hierarchy is used. + + + BlockIOAccounting= diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 8eab100748..7cdc97ee3c 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2272,11 +2272,15 @@ int cg_weight_parse(const char *s, uint64_t *ret) { const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = { [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX, [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX, + [CGROUP_IO_RIOPS_MAX] = CGROUP_LIMIT_MAX, + [CGROUP_IO_WIOPS_MAX] = CGROUP_LIMIT_MAX, }; static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = { [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax", [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax", + [CGROUP_IO_RIOPS_MAX] = "IOReadIOPSMax", + [CGROUP_IO_WIOPS_MAX] = "IOWriteIOPSMax", }; DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType); diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 0d96fb6b76..4bb5291296 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -76,6 +76,8 @@ static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) { typedef enum CGroupIOLimitType { CGROUP_IO_RBPS_MAX, CGROUP_IO_WBPS_MAX, + CGROUP_IO_RIOPS_MAX, + CGROUP_IO_WIOPS_MAX, _CGROUP_IO_LIMIT_TYPE_MAX, _CGROUP_IO_LIMIT_TYPE_INVALID = -1 diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 0b902fa6f7..a54634469f 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -439,7 +439,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)]; - char buf[DECIMAL_STR_MAX(dev_t)*2+2+(5+DECIMAL_STR_MAX(uint64_t)+1)*2]; + char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4]; CGroupIOLimitType type; dev_t dev; unsigned n = 0; @@ -458,8 +458,9 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } } - xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev), - limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX]); + xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev), + limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX], + limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]); r = cg_set_attribute("io", path, "io.max", buf); if (r < 0) log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 4372828e30..29c2edaf6b 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -213,6 +213,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0), SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0), SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0), + SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0), + SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0), SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0), SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index ad45611d9d..8193418980 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -126,6 +126,8 @@ $1.StartupIOWeight, config_parse_io_weight, 0, $1.IODeviceWeight, config_parse_io_device_weight, 0, offsetof($1, cgroup_context) $1.IOReadBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context) $1.IOWriteBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context) +$1.IOReadIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context) +$1.IOWriteIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context) $1.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting) $1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.blockio_weight) $1.StartupBlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.startup_blockio_weight) -- cgit v1.2.3-54-g00ecf From 979d03117ffeccd2cc18c8ff843932b03ea065b9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 18 May 2016 13:51:46 -0700 Subject: core: update CGroupBlockIODeviceBandwidth to record both rbps and wbps CGroupBlockIODeviceBandwith is used to keep track of IO bandwidth limits for legacy cgroup hierarchies. Unlike the unified hierarchy counterpart CGroupIODeviceLimit, a CGroupBlockIODeviceBandwiddth records either a read or write limit and has a couple issues. * There's no way to clear specific config entry. * When configs are cleared for an IO direction of a unit, the kernel settings aren't cleared accordingly creating discrepancies. This patch updates CGroupBlockIODeviceBandwidth so that it behaves similarly to CGroupIODeviceLimit - each entry records both rbps and wbps limits and is cleared if both are at default values after kernel settings are updated. --- src/core/cgroup.c | 46 ++++++++++++++++++++++++++++++++-------------- src/core/cgroup.h | 4 ++-- src/core/dbus-cgroup.c | 39 ++++++++++++++++++++++++++------------- src/core/load-fragment.c | 42 +++++++++++++++++++++++++++--------------- 4 files changed, 87 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index a54634469f..b0e7be082c 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -206,12 +206,18 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { char buf[FORMAT_BYTES_MAX]; - fprintf(f, - "%s%s=%s %s\n", - prefix, - b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth", - b->path, - format_bytes(buf, sizeof(buf), b->bandwidth)); + if (b->rbps != CGROUP_LIMIT_MAX) + fprintf(f, + "%sBlockIOReadBandwidth=%s %s\n", + prefix, + b->path, + format_bytes(buf, sizeof(buf), b->rbps)); + if (b->wbps != CGROUP_LIMIT_MAX) + fprintf(f, + "%sBlockIOWriteBandwidth=%s %s\n", + prefix, + b->path, + format_bytes(buf, sizeof(buf), b->wbps)); } } @@ -477,7 +483,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1, DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; CGroupBlockIODeviceWeight *w; - CGroupBlockIODeviceBandwidth *b; + CGroupBlockIODeviceBandwidth *b, *next; if (!is_root) { sprintf(buf, "%" PRIu64 "\n", @@ -504,22 +510,34 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } } - /* FIXME: no way to reset this list */ - LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { - const char *a; + LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) { dev_t dev; + unsigned n = 0; r = lookup_block_device(b->path, &dev); if (r < 0) continue; - a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device"; + if (b->rbps != CGROUP_LIMIT_MAX) + n++; + sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->rbps); + r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.throttle.read_bps_device on %s: %m", path); - sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth); - r = cg_set_attribute("blkio", path, a, buf); + if (b->wbps != CGROUP_LIMIT_MAX) + n++; + sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->wbps); + r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf); if (r < 0) log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set %s on %s: %m", a, path); + "Failed to set blkio.throttle.write_bps_device on %s: %m", path); + + /* If @b contained no config, we just cleared the kernel + * counterpart too. No reason to keep @l around. */ + if (!n) + cgroup_context_free_blockio_device_bandwidth(c, b); } } diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 1907461f7e..2b1edbafc4 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -77,8 +77,8 @@ struct CGroupBlockIODeviceWeight { struct CGroupBlockIODeviceBandwidth { LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths); char *path; - uint64_t bandwidth; - bool read; + uint64_t rbps; + uint64_t wbps; }; struct CGroupContext { diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 29c2edaf6b..eef1c47c14 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -146,11 +146,17 @@ static int property_get_blockio_device_bandwidths( return r; LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { + uint64_t v; - if (streq(property, "BlockIOReadBandwidth") != b->read) + if (streq(property, "BlockIOReadBandwidth")) + v = b->rbps; + else + v = b->wbps; + + if (v == CGROUP_LIMIT_MAX) continue; - r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth); + r = sd_bus_message_append(reply, "(st)", b->path, v); if (r < 0) return r; } @@ -651,7 +657,7 @@ int bus_cgroup_set_property( CGroupBlockIODeviceBandwidth *a = NULL, *b; LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { - if (path_equal(path, b->path) && read == b->read) { + if (path_equal(path, b->path)) { a = b; break; } @@ -662,7 +668,8 @@ int bus_cgroup_set_property( if (!a) return -ENOMEM; - a->read = read; + a->rbps = CGROUP_LIMIT_MAX; + a->wbps = CGROUP_LIMIT_MAX; a->path = strdup(path); if (!a->path) { free(a); @@ -672,7 +679,10 @@ int bus_cgroup_set_property( LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a); } - a->bandwidth = u64; + if (read) + a->rbps = u64; + else + a->wbps = u64; } n++; @@ -685,15 +695,18 @@ int bus_cgroup_set_property( return r; if (mode != UNIT_CHECK) { - CGroupBlockIODeviceBandwidth *a, *next; + CGroupBlockIODeviceBandwidth *a; _cleanup_free_ char *buf = NULL; _cleanup_fclose_ FILE *f = NULL; size_t size = 0; if (n == 0) { - LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths) - if (a->read == read) - cgroup_context_free_blockio_device_bandwidth(c, a); + LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) { + if (read) + a->rbps = CGROUP_LIMIT_MAX; + else + a->wbps = CGROUP_LIMIT_MAX; + } } unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO); @@ -705,13 +718,13 @@ int bus_cgroup_set_property( if (read) { fputs("BlockIOReadBandwidth=\n", f); LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) - if (a->read) - fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); + if (a->rbps != CGROUP_LIMIT_MAX) + fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps); } else { fputs("BlockIOWriteBandwidth=\n", f); LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) - if (!a->read) - fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); + if (a->wbps != CGROUP_LIMIT_MAX) + fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps); } r = fflush_and_check(f); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 9626d861c5..86b4fb071b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3208,7 +3208,7 @@ int config_parse_blockio_bandwidth( void *userdata) { _cleanup_free_ char *path = NULL; - CGroupBlockIODeviceBandwidth *b; + CGroupBlockIODeviceBandwidth *b = NULL, *t; CGroupContext *c = data; const char *bandwidth; uint64_t bytes; @@ -3223,12 +3223,10 @@ int config_parse_blockio_bandwidth( read = streq("BlockIOReadBandwidth", lvalue); if (isempty(rvalue)) { - CGroupBlockIODeviceBandwidth *next; - - LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths) - if (b->read == read) - cgroup_context_free_blockio_device_bandwidth(c, b); - + LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) { + b->rbps = CGROUP_LIMIT_MAX; + b->wbps = CGROUP_LIMIT_MAX; + } return 0; } @@ -3256,16 +3254,30 @@ int config_parse_blockio_bandwidth( return 0; } - b = new0(CGroupBlockIODeviceBandwidth, 1); - if (!b) - return log_oom(); + LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) { + if (path_equal(path, t->path)) { + b = t; + break; + } + } - b->path = path; - path = NULL; - b->bandwidth = bytes; - b->read = read; + if (!t) { + b = new0(CGroupBlockIODeviceBandwidth, 1); + if (!b) + return log_oom(); + + b->path = path; + path = NULL; + b->rbps = CGROUP_LIMIT_MAX; + b->wbps = CGROUP_LIMIT_MAX; + + LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b); + } - LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b); + if (read) + b->rbps = bytes; + else + b->wbps = bytes; return 0; } -- cgit v1.2.3-54-g00ecf From 64faf04c1f178804e066972ab0d6ff1181c0d373 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 18 May 2016 13:51:46 -0700 Subject: core: factor out io and blkio helper functions from cgroup_context_apply() Factor out the following functions out of cgroup_context_apply() * cgroup_context_[blk]io_weight() * cgroup_apply_[blk]io_device_weight() * cgroup_apply_[blk]io_device_limit() This is pure refactoring and shouldn't cause any functional differences. --- src/core/cgroup.c | 235 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 137 insertions(+), 98 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index b0e7be082c..ddc4f69ebe 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -358,6 +358,124 @@ fail: return -errno; } +static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) +{ + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + c->startup_io_weight != CGROUP_WEIGHT_INVALID) + return c->startup_io_weight; + else if (c->io_weight != CGROUP_WEIGHT_INVALID) + return c->io_weight; + else + return CGROUP_WEIGHT_DEFAULT; +} + +static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state) +{ + if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && + c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID) + return c->startup_blockio_weight; + else if (c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID) + return c->blockio_weight; + else + return CGROUP_BLKIO_WEIGHT_DEFAULT; +} + +static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) +{ + char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; + dev_t dev; + int r; + + r = lookup_block_device(dev_path, &dev); + if (r < 0) + return; + + xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), io_weight); + r = cg_set_attribute("io", path, "io.weight", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.weight on %s: %m", path); +} + +static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_path, uint64_t blkio_weight) +{ + char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; + dev_t dev; + int r; + + r = lookup_block_device(dev_path, &dev); + if (r < 0) + return; + + xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), blkio_weight); + r = cg_set_attribute("blkio", path, "blkio.weight_device", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.weight_device on %s: %m", path); +} + +static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_path, uint64_t *limits) +{ + char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)]; + char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4]; + CGroupIOLimitType type; + dev_t dev; + unsigned n = 0; + int r; + + r = lookup_block_device(dev_path, &dev); + if (r < 0) + return 0; + + for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) { + if (limits[type] != cgroup_io_limit_defaults[type]) { + xsprintf(limit_bufs[type], "%" PRIu64, limits[type]); + n++; + } else { + xsprintf(limit_bufs[type], "%s", limits[type] == CGROUP_LIMIT_MAX ? "max" : "0"); + } + } + + xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev), + limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX], + limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]); + r = cg_set_attribute("io", path, "io.max", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.max on %s: %m", path); + return n; +} + +static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *dev_path, uint64_t rbps, uint64_t wbps) +{ + char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; + dev_t dev; + unsigned n = 0; + int r; + + r = lookup_block_device(dev_path, &dev); + if (r < 0) + return 0; + + if (rbps != CGROUP_LIMIT_MAX) + n++; + sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), rbps); + r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.throttle.read_bps_device on %s: %m", path); + + if (wbps != CGROUP_LIMIT_MAX) + n++; + sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), wbps); + r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set blkio.throttle.write_bps_device on %s: %m", path); + + return n; +} + void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) { bool is_root; int r; @@ -407,19 +525,14 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } if (mask & CGROUP_MASK_IO) { - CGroupIODeviceWeight *w; CGroupIODeviceLimit *l, *next; if (!is_root) { - char buf[MAX(8+DECIMAL_STR_MAX(uint64_t)+1, - DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; - uint64_t weight = CGROUP_WEIGHT_DEFAULT; + char buf[8+DECIMAL_STR_MAX(uint64_t)+1]; + uint64_t weight; + CGroupIODeviceWeight *w; - if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && - c->startup_io_weight != CGROUP_WEIGHT_INVALID) - weight = c->startup_io_weight; - else if (c->io_weight != CGROUP_WEIGHT_INVALID) - weight = c->io_weight; + weight = cgroup_context_io_weight(c, state); xsprintf(buf, "default %" PRIu64 "\n", weight); r = cg_set_attribute("io", path, "io.weight", buf); @@ -428,115 +541,41 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M "Failed to set io.weight on %s: %m", path); /* FIXME: no way to reset this list */ - LIST_FOREACH(device_weights, w, c->io_device_weights) { - dev_t dev; - - r = lookup_block_device(w->path, &dev); - if (r < 0) - continue; - - xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight); - r = cg_set_attribute("io", path, "io.weight", buf); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set io.weight on %s: %m", path); - } + LIST_FOREACH(device_weights, w, c->io_device_weights) + cgroup_apply_io_device_weight(path, w->path, w->weight); } + /* Apply limits and free ones without config. */ LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { - char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)]; - char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4]; - CGroupIOLimitType type; - dev_t dev; - unsigned n = 0; - - r = lookup_block_device(l->path, &dev); - if (r < 0) - continue; - - for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) { - if (l->limits[type] != cgroup_io_limit_defaults[type]) { - xsprintf(limit_bufs[type], "%" PRIu64, l->limits[type]); - n++; - } else { - xsprintf(limit_bufs[type], "%s", - l->limits[type] == CGROUP_LIMIT_MAX ? "max" : "0"); - } - } - - xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev), - limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX], - limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]); - r = cg_set_attribute("io", path, "io.max", buf); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set io.max on %s: %m", path); - - /* If @l contained no config, we just cleared the kernel - counterpart too. No reason to keep @l around. */ - if (!n) + if (!cgroup_apply_io_device_limit(path, l->path, l->limits)) cgroup_context_free_io_device_limit(c, l); } } if (mask & CGROUP_MASK_BLKIO) { - char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1, - DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; - CGroupBlockIODeviceWeight *w; CGroupBlockIODeviceBandwidth *b, *next; if (!is_root) { - sprintf(buf, "%" PRIu64 "\n", - IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->startup_blockio_weight : - c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT); + char buf[DECIMAL_STR_MAX(uint64_t)+1]; + uint64_t weight; + CGroupBlockIODeviceWeight *w; + + weight = cgroup_context_blkio_weight(c, state); + + xsprintf(buf, "%" PRIu64 "\n", weight); r = cg_set_attribute("blkio", path, "blkio.weight", buf); if (r < 0) log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set blkio.weight on %s: %m", path); /* FIXME: no way to reset this list */ - LIST_FOREACH(device_weights, w, c->blockio_device_weights) { - dev_t dev; - - r = lookup_block_device(w->path, &dev); - if (r < 0) - continue; - - sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight); - r = cg_set_attribute("blkio", path, "blkio.weight_device", buf); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set blkio.weight_device on %s: %m", path); - } + LIST_FOREACH(device_weights, w, c->blockio_device_weights) + cgroup_apply_blkio_device_weight(path, w->path, w->weight); } + /* Apply limits and free ones without config. */ LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) { - dev_t dev; - unsigned n = 0; - - r = lookup_block_device(b->path, &dev); - if (r < 0) - continue; - - if (b->rbps != CGROUP_LIMIT_MAX) - n++; - sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->rbps); - r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set blkio.throttle.read_bps_device on %s: %m", path); - - if (b->wbps != CGROUP_LIMIT_MAX) - n++; - sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->wbps); - r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set blkio.throttle.write_bps_device on %s: %m", path); - - /* If @b contained no config, we just cleared the kernel - * counterpart too. No reason to keep @l around. */ - if (!n) + if (!cgroup_apply_blkio_device_limit(path, b->path, b->rbps, b->wbps)) cgroup_context_free_blockio_device_bandwidth(c, b); } } -- cgit v1.2.3-54-g00ecf From 538b48524cf48afc299ab78690bc03c18af67ede Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 18 May 2016 17:35:12 -0700 Subject: core: translate between IO and BlockIO settings to ease transition Due to the substantial interface changes in cgroup unified hierarchy, new IO settings are introduced. Currently, IO settings apply only to unified hierarchy and BlockIO to legacy. While the transition is necessary, it's painful for users to have to provide configs for both. This patch implements translation from one config set to another for configs which make sense. * The translation takes place during application of the configs. Users won't see IO or BlockIO settings appearing without being explicitly created. * The translation takes place only if there is no config for the matching cgroup hierarchy type at all. While this doesn't provide comprehensive compatibility, it should considerably ease transition to the new IO settings which are a superset of BlockIO settings. v2: - Update test-cgroup-mask.c so that it accounts for the fact that CGROUP_MASK_IO and CGROUP_MASK_BLKIO move together. Also, test/parent.slice now sets IOWeight instead of BlockIOWeight. --- man/systemd.resource-control.xml | 25 +++++++ src/core/cgroup.c | 146 ++++++++++++++++++++++++++++++--------- src/test/test-cgroup-mask.c | 13 ++-- test/parent.slice | 2 +- 4 files changed, 148 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 8a95e1196b..066f2cc19b 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -98,6 +98,31 @@ unit. + + Unified and Legacy Control Group Hierarchies + + Unified control group hierarchy is the new version of kernel control group interface. Depending on the + resource type, there are differences in resource control capabilities. Also, because of interface changes, some + resource types have a separate set of options on the unified hierarchy. + + + + + + + IO prefixed settings are superset of and replace BlockIO + prefixed ones. On unified hierarchy, IO resource control also applies to buffered writes. + + + + + + To ease the transition, there is best-effort translation between the two versions of settings. If all + settings of a unit for a given resource type are for the other hierarchy type, the settings are translated and + applied. If there are any valid settings for the hierarchy in use, all translations are disabled for the resource + type. Mixing the two types of settings on a unit can lead to confusing results. + + Options diff --git a/src/core/cgroup.c b/src/core/cgroup.c index ddc4f69ebe..8b8b2ac5ff 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -358,6 +358,24 @@ fail: return -errno; } +static bool cgroup_context_has_io_config(CGroupContext *c) +{ + return c->io_accounting || + c->io_weight != CGROUP_WEIGHT_INVALID || + c->startup_io_weight != CGROUP_WEIGHT_INVALID || + c->io_device_weights || + c->io_device_limits; +} + +static bool cgroup_context_has_blockio_config(CGroupContext *c) +{ + return c->blockio_accounting || + c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || + c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || + c->blockio_device_weights || + c->blockio_device_bandwidths; +} + static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) { if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && @@ -380,6 +398,18 @@ static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state return CGROUP_BLKIO_WEIGHT_DEFAULT; } +static uint64_t cgroup_weight_blkio_to_io(uint64_t blkio_weight) +{ + return CLAMP(blkio_weight * CGROUP_WEIGHT_DEFAULT / CGROUP_BLKIO_WEIGHT_DEFAULT, + CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX); +} + +static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) +{ + return CLAMP(io_weight * CGROUP_BLKIO_WEIGHT_DEFAULT / CGROUP_WEIGHT_DEFAULT, + CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX); +} + static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) { char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; @@ -525,14 +555,19 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } if (mask & CGROUP_MASK_IO) { - CGroupIODeviceLimit *l, *next; + bool has_io = cgroup_context_has_io_config(c); + bool has_blockio = cgroup_context_has_blockio_config(c); if (!is_root) { char buf[8+DECIMAL_STR_MAX(uint64_t)+1]; uint64_t weight; - CGroupIODeviceWeight *w; - weight = cgroup_context_io_weight(c, state); + if (has_io) + weight = cgroup_context_io_weight(c, state); + else if (has_blockio) + weight = cgroup_weight_blkio_to_io(cgroup_context_blkio_weight(c, state)); + else + weight = CGROUP_WEIGHT_DEFAULT; xsprintf(buf, "default %" PRIu64 "\n", weight); r = cg_set_attribute("io", path, "io.weight", buf); @@ -540,27 +575,62 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set io.weight on %s: %m", path); - /* FIXME: no way to reset this list */ - LIST_FOREACH(device_weights, w, c->io_device_weights) - cgroup_apply_io_device_weight(path, w->path, w->weight); + if (has_io) { + CGroupIODeviceWeight *w; + + /* FIXME: no way to reset this list */ + LIST_FOREACH(device_weights, w, c->io_device_weights) + cgroup_apply_io_device_weight(path, w->path, w->weight); + } else if (has_blockio) { + CGroupBlockIODeviceWeight *w; + + /* FIXME: no way to reset this list */ + LIST_FOREACH(device_weights, w, c->blockio_device_weights) + cgroup_apply_io_device_weight(path, w->path, cgroup_weight_blkio_to_io(w->weight)); + } } /* Apply limits and free ones without config. */ - LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { - if (!cgroup_apply_io_device_limit(path, l->path, l->limits)) - cgroup_context_free_io_device_limit(c, l); + if (has_io) { + CGroupIODeviceLimit *l, *next; + + LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { + if (!cgroup_apply_io_device_limit(path, l->path, l->limits)) + cgroup_context_free_io_device_limit(c, l); + } + } else if (has_blockio) { + CGroupBlockIODeviceBandwidth *b, *next; + + LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) { + uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX]; + CGroupIOLimitType type; + + for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) + limits[type] = cgroup_io_limit_defaults[type]; + + limits[CGROUP_IO_RBPS_MAX] = b->rbps; + limits[CGROUP_IO_WBPS_MAX] = b->wbps; + + if (!cgroup_apply_io_device_limit(path, b->path, limits)) + cgroup_context_free_blockio_device_bandwidth(c, b); + } } } if (mask & CGROUP_MASK_BLKIO) { - CGroupBlockIODeviceBandwidth *b, *next; + bool has_io = cgroup_context_has_io_config(c); + bool has_blockio = cgroup_context_has_blockio_config(c); if (!is_root) { char buf[DECIMAL_STR_MAX(uint64_t)+1]; uint64_t weight; - CGroupBlockIODeviceWeight *w; - weight = cgroup_context_blkio_weight(c, state); + if (has_blockio) + weight = cgroup_context_blkio_weight(c, state); + else if (has_io) + weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state)); + else + weight = CGROUP_BLKIO_WEIGHT_DEFAULT; xsprintf(buf, "%" PRIu64 "\n", weight); r = cg_set_attribute("blkio", path, "blkio.weight", buf); @@ -568,15 +638,36 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set blkio.weight on %s: %m", path); - /* FIXME: no way to reset this list */ - LIST_FOREACH(device_weights, w, c->blockio_device_weights) - cgroup_apply_blkio_device_weight(path, w->path, w->weight); + if (has_blockio) { + CGroupBlockIODeviceWeight *w; + + /* FIXME: no way to reset this list */ + LIST_FOREACH(device_weights, w, c->blockio_device_weights) + cgroup_apply_blkio_device_weight(path, w->path, w->weight); + } else if (has_io) { + CGroupIODeviceWeight *w; + + /* FIXME: no way to reset this list */ + LIST_FOREACH(device_weights, w, c->io_device_weights) + cgroup_apply_blkio_device_weight(path, w->path, cgroup_weight_io_to_blkio(w->weight)); + } } /* Apply limits and free ones without config. */ - LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) { - if (!cgroup_apply_blkio_device_limit(path, b->path, b->rbps, b->wbps)) - cgroup_context_free_blockio_device_bandwidth(c, b); + if (has_blockio) { + CGroupBlockIODeviceBandwidth *b, *next; + + LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) { + if (!cgroup_apply_blkio_device_limit(path, b->path, b->rbps, b->wbps)) + cgroup_context_free_blockio_device_bandwidth(c, b); + } + } else if (has_io) { + CGroupIODeviceLimit *l, *next; + + LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) { + if (!cgroup_apply_blkio_device_limit(path, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX])) + cgroup_context_free_io_device_limit(c, l); + } } } @@ -693,19 +784,8 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) { c->cpu_quota_per_sec_usec != USEC_INFINITY) mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU; - if (c->io_accounting || - c->io_weight != CGROUP_WEIGHT_INVALID || - c->startup_io_weight != CGROUP_WEIGHT_INVALID || - c->io_device_weights || - c->io_device_limits) - mask |= CGROUP_MASK_IO; - - if (c->blockio_accounting || - c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || - c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || - c->blockio_device_weights || - c->blockio_device_bandwidths) - mask |= CGROUP_MASK_BLKIO; + if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c)) + mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; if (c->memory_accounting || c->memory_limit != (uint64_t) -1) @@ -1795,6 +1875,10 @@ void unit_invalidate_cgroup(Unit *u, CGroupMask m) { if (m == 0) return; + /* always invalidate compat pairs together */ + if (m & (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)) + m |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; + if ((u->cgroup_realized_mask & m) == 0) return; diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 4eb8fcd773..a025704722 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -48,6 +48,7 @@ static int test_cgroup_mask(void) { m->default_cpu_accounting = m->default_memory_accounting = m->default_blockio_accounting = + m->default_io_accounting = m->default_tasks_accounting = false; m->default_tasks_max = (uint64_t) -1; @@ -76,7 +77,7 @@ static int test_cgroup_mask(void) { assert_se(unit_get_own_mask(daughter) == 0); assert_se(unit_get_own_mask(grandchild) == 0); assert_se(unit_get_own_mask(parent_deep) == CGROUP_MASK_MEMORY); - assert_se(unit_get_own_mask(parent) == CGROUP_MASK_BLKIO); + assert_se(unit_get_own_mask(parent) == (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)); assert_se(unit_get_own_mask(root) == 0); /* Verify aggregation of member masks */ @@ -85,23 +86,23 @@ static int test_cgroup_mask(void) { assert_se(unit_get_members_mask(grandchild) == 0); assert_se(unit_get_members_mask(parent_deep) == 0); assert_se(unit_get_members_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); - assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); /* Verify aggregation of sibling masks. */ assert_se(unit_get_siblings_mask(son) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); assert_se(unit_get_siblings_mask(daughter) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); assert_se(unit_get_siblings_mask(grandchild) == 0); assert_se(unit_get_siblings_mask(parent_deep) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); - assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); - assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); /* Verify aggregation of target masks. */ assert_se(unit_get_target_mask(son) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); assert_se(unit_get_target_mask(daughter) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); assert_se(unit_get_target_mask(grandchild) == 0); assert_se(unit_get_target_mask(parent_deep) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); manager_free(m); diff --git a/test/parent.slice b/test/parent.slice index 0222f8eb47..a95f90392d 100644 --- a/test/parent.slice +++ b/test/parent.slice @@ -2,4 +2,4 @@ Description=Parent Slice [Slice] -BlockIOWeight=200 +IOWeight=200 -- cgit v1.2.3-54-g00ecf From 42e1d23f323db01885ddeb97121c4098f0af6700 Mon Sep 17 00:00:00 2001 From: Jonathan Boulle Date: Thu, 19 May 2016 02:54:22 +0200 Subject: core/dbus: further simplify branch code (#3283) free_and_strdup already handles the NULL case for us, so we can remove an extraneous conditional check. As noted in https://github.com/systemd/systemd/pull/3279/files#r63687717 --- src/core/dbus-execute.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 646bd779a2..04fbc7ad15 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -836,11 +836,9 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - - if (isempty(uu)) - c->user = mfree(c->user); - else if (free_and_strdup(&c->user, uu) < 0) - return -ENOMEM; + r = free_and_strdup(&c->user, uu); + if (r < 0) + return r; unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu); } @@ -855,11 +853,9 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - - if (isempty(gg)) - c->group = mfree(c->group); - else if (free_and_strdup(&c->group, gg) < 0) - return -ENOMEM; + r = free_and_strdup(&c->group, gg); + if (r < 0) + return r; unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg); } @@ -873,11 +869,9 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - - if (isempty(id)) - c->syslog_identifier = mfree(c->syslog_identifier); - else if (free_and_strdup(&c->syslog_identifier, id) < 0) - return -ENOMEM; + r = free_and_strdup(&c->syslog_identifier, id); + if (r < 0) + return r; unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id); } @@ -1094,10 +1088,9 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - if (isempty(id)) - c->utmp_id = mfree(c->utmp_id); - else if (free_and_strdup(&c->utmp_id, id) < 0) - return -ENOMEM; + r = free_and_strdup(&c->utmp_id, id); + if (r < 0) + return r; unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s\n", strempty(id)); } @@ -1132,10 +1125,9 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - if (isempty(n)) - c->pam_name = mfree(c->pam_name); - else if (free_and_strdup(&c->pam_name, n) < 0) - return -ENOMEM; + r = free_and_strdup(&c->pam_name, n); + if (r < 0) + return r; unit_write_drop_in_private_format(u, mode, name, "PAMName=%s\n", strempty(n)); } -- cgit v1.2.3-54-g00ecf From f3f054f03e6de7865132e9602da178dfc82102ab Mon Sep 17 00:00:00 2001 From: tblume Date: Thu, 19 May 2016 16:35:27 +0200 Subject: systemctl: restore the no-sync option for legacy halt (#3249) The sync() call on shutdown had been removed with commit 57371e5829a61e5ee6c9f98404dfc729d6c62608 together with the no-sync option for the shutdown commands. The sync call was restored in commit 4a3ad39957399c4a30fc472a804e72907ecaa4f9 but the no-sync option wasn't re-added. I think we should restore this option at least for the legacy halt command. --- man/halt.xml | 8 ++++++++ src/systemctl/systemctl.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/man/halt.xml b/man/halt.xml index a06dbd0097..e3fa60a915 100644 --- a/man/halt.xml +++ b/man/halt.xml @@ -132,6 +132,14 @@ entry. + + + + + Don't sync hard disks/storage media before + halt, power-off, reboot. + + diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0faf37d320..3b4678c119 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -102,6 +102,7 @@ static bool arg_no_block = false; static bool arg_no_legend = false; static bool arg_no_pager = false; static bool arg_no_wtmp = false; +static bool arg_no_sync = false; static bool arg_no_wall = false; static bool arg_no_reload = false; static bool arg_value = false; @@ -6926,6 +6927,7 @@ static int halt_parse_argv(int argc, char *argv[]) { { "force", no_argument, NULL, 'f' }, { "wtmp-only", no_argument, NULL, 'w' }, { "no-wtmp", no_argument, NULL, 'd' }, + { "no-sync", no_argument, NULL, 'n' }, { "no-wall", no_argument, NULL, ARG_NO_WALL }, {} }; @@ -6971,13 +6973,16 @@ static int halt_parse_argv(int argc, char *argv[]) { arg_no_wtmp = true; break; + case 'n': + arg_no_sync = true; + break; + case ARG_NO_WALL: arg_no_wall = true; break; case 'i': case 'h': - case 'n': /* Compatibility nops */ break; @@ -7496,7 +7501,8 @@ static int halt_now(enum action a) { /* The kernel will automaticall flush ATA disks and suchlike * on reboot(), but the file systems need to be synce'd * explicitly in advance. */ - (void) sync(); + if (!arg_no_sync) + (void) sync(); /* Make sure C-A-D is handled by the kernel from this point * on... */ -- cgit v1.2.3-54-g00ecf From 823e5fabb783d452607ff8ccaa5235af14eb44eb Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Thu, 19 May 2016 16:37:04 +0200 Subject: systemctl: reload configuration when enabling sysv units too (#3297) After enabling/disabling a unit, the daemon configuration is expected to be unless '--no-reload' option is passed. However this is not done when enabling a sysv units. This can lead to the following scenario: $ cp /etc/init.d/named /etc/init.d/foo $ systemctl enable foo foo.service is not a native service, redirecting to systemd-sysv-install Executing /usr/lib/systemd/systemd-sysv-install enable foo $ systemctl start foo Failed to start foo.service: Unit foo.service failed to load: No such file or directory. This can also be seen after installing a package providing a sysv service: the service can't be started unless 'daemon-reload' is called manually. This shouldn't be needed and this patch will fix this case too since during package installation, the service is expected to be enabled/disabled. --- src/systemctl/systemctl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 3b4678c119..fe24b936ec 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5478,8 +5478,11 @@ static int enable_unit(int argc, char *argv[], void *userdata) { return r; /* If the operation was fully executed by the SysV compat, let's finish early */ - if (strv_isempty(names)) - return 0; + if (strv_isempty(names)) { + if (arg_no_reload || install_client_side()) + return 0; + return daemon_reload(argc, argv, userdata); + } if (install_client_side()) { if (streq(verb, "enable")) { -- cgit v1.2.3-54-g00ecf From 35b132e8ad3c50614605e00cf8ff20988094d21c Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Thu, 19 May 2016 15:08:41 -0400 Subject: systemctl: suppress no-[Install] hint when --quiet is used (#3295) https://bugzilla.redhat.com/show_bug.cgi?id=1336960 --- src/systemctl/systemctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index fe24b936ec..53ab650ce2 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5463,7 +5463,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { UnitFileChange *changes = NULL; unsigned n_changes = 0; int carries_install_info = -1; - bool ignore_carries_install_info = false; + bool ignore_carries_install_info = arg_quiet; int r; if (!argv[1]) -- cgit v1.2.3-54-g00ecf From 9243aa45fa0cfcd399aa7db1abd1e64e9ac515e3 Mon Sep 17 00:00:00 2001 From: tomty89 Date: Fri, 20 May 2016 18:20:24 +0800 Subject: [networkd-ndisc] set IPv6LL address in DHCP client Fix issue #3256 and probably #1982. Referenced link_acquire_ipv6_conf() in networkd-link.c. --- src/network/networkd-ndisc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index b22c58bfe5..78f02cf746 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -157,6 +157,10 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a if (flags & ND_RA_FLAG_MANAGED) dhcp6_request_address(link); + r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); + if (r < 0 && r != -EBUSY) + return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); + r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0 && r != -EBUSY) log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m"); @@ -203,6 +207,10 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { case SD_NDISC_EVENT_TIMEOUT: dhcp6_request_address(link); + r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); + if (r < 0 && r != -EBUSY) + return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); + r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0 && r != -EBUSY) log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m"); -- cgit v1.2.3-54-g00ecf From 59bc1530b8a06621bf29109984898daa3f8cc6ce Mon Sep 17 00:00:00 2001 From: tomty89 Date: Fri, 20 May 2016 18:28:30 +0800 Subject: [networkd-dhcp6] do not call sd_dhcp6_client_start() from dhcp6_request_address() Starting the DHCP client doesn't seem like dhcp6_request_address()'s responsibility anyway. Whenever it's called, sd_dhcp6_client_start() is unconditionally called outside of it as well. See ndisc_router_handler() and ndisc_handler() in networkd-ndisc.c. --- src/network/networkd-dhcp6.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src') diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 6085b28f86..37e13e639e 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -194,12 +194,6 @@ int dhcp6_request_address(Link *link) { if (r < 0) return r; - if (running) { - r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0) - return r; - } - return 0; } -- cgit v1.2.3-54-g00ecf From ad5ae47a0d159ea473c9730d7e0298a3e5d31cf6 Mon Sep 17 00:00:00 2001 From: sadag Date: Fri, 20 May 2016 04:26:27 -0700 Subject: sd-dhcp-client: fix busy loop reading zero sized DHCP UDP packets. (#3299) --- src/libsystemd-network/sd-dhcp-client.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 3846cf7476..123169832c 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1636,6 +1636,9 @@ static int client_receive_message_udp( if (buflen < 0) return buflen; + if (buflen == 0) + buflen = 1; + message = malloc0(buflen); if (!message) return -ENOMEM; -- cgit v1.2.3-54-g00ecf From f942504e4f74c6d30d7b73cb602517e055f02152 Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Fri, 20 May 2016 16:08:24 +0300 Subject: basic: remove rm_rf_and_free, add rm_rf_physical_and_free, use rm_rf_physical_and_freep in tests (#3292) Some distros don't mount /tmp as tmpfs. For example: https://lists.ubuntu.com/archives/ubuntu-cloud/2016-January/001009.html Some tests: * print 'Attempted to remove disk file system, and we can't allow that.' * don't really cleanup /tmp --- src/basic/rm-rf.h | 6 +++--- src/test/test-cgroup-mask.c | 2 +- src/test/test-engine.c | 2 +- src/test/test-path.c | 2 +- src/test/test-sched-prio.c | 2 +- src/test/test-unit-file.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h index 40b5b527d5..f693a5bb7c 100644 --- a/src/basic/rm-rf.h +++ b/src/basic/rm-rf.h @@ -32,10 +32,10 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev); int rm_rf(const char *path, RemoveFlags flags); /* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */ -static inline void rm_rf_and_free(char *p) { +static inline void rm_rf_physical_and_free(char *p) { if (!p) return; - (void) rm_rf(p, REMOVE_ROOT); + (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL); free(p); } -DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_and_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_physical_and_free); diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 4eb8fcd773..4677f7cbd9 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -109,7 +109,7 @@ static int test_cgroup_mask(void) { } int main(int argc, char* argv[]) { - _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; int rc = 0; assert_se(runtime_dir = setup_fake_runtime_dir()); diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 361d1e7b0b..23da10fa1a 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -28,7 +28,7 @@ #include "tests.h" int main(int argc, char *argv[]) { - _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; Manager *m = NULL; Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL; diff --git a/src/test/test-path.c b/src/test/test-path.c index 435cafd83a..62181e22a0 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -255,7 +255,7 @@ int main(int argc, char *argv[]) { NULL, }; - _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; const test_function_t *test = NULL; Manager *m = NULL; diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index 3e9caafc71..c068f5c39e 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -26,7 +26,7 @@ #include "tests.h" int main(int argc, char *argv[]) { - _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; Manager *m = NULL; Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched; Service *ser; diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index c340673c6c..ade0ff2a63 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -842,7 +842,7 @@ static void test_config_parse_pass_environ(void) { } int main(int argc, char *argv[]) { - _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL; + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; int r; log_parse_environment(); -- cgit v1.2.3-54-g00ecf From 186ad4b1a05b5c5d231a3b4b7faba8a5c40e3c9d Mon Sep 17 00:00:00 2001 From: Jonathan Boulle Date: Fri, 20 May 2016 15:09:14 +0200 Subject: core/dbus: expose SELinuxContext property (#3284) Adds support to core for systemd D-Bus clients to send the `SELinuxContext` property . This means `systemd-run -p SELinuxContext=foo` should now work. --- src/core/dbus-execute.c | 17 +++++++++++++++++ src/shared/bus-unit-util.c | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 04fbc7ad15..888319593c 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1446,6 +1446,23 @@ int bus_exec_context_set_transient_property( return 1; + } else if (streq(name, "SELinuxContext")) { + const char *s; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + r = free_and_strdup(&c->selinux_context, s); + if (r < 0) + return r; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, strempty(s)); + } + + return 1; + } ri = rlimit_from_string(name); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 8f0df84793..9431dad411 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -235,7 +235,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "StandardInput", "StandardOutput", "StandardError", "Description", "Slice", "Type", "WorkingDirectory", "RootDirectory", "SyslogIdentifier", "ProtectSystem", - "ProtectHome")) + "ProtectHome", "SELinuxContext")) r = sd_bus_message_append(m, "v", "s", eq); else if (streq(field, "SyslogLevel")) { -- cgit v1.2.3-54-g00ecf From 0e3e1aefebffdd97befd06586d055c5996697eed Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 20 May 2016 09:11:58 -0400 Subject: resolved: fix accounting of dns serves on a link (#3291) After a few link up/down events I got this warning: May 17 22:05:10 laptop systemd-resolved[2983]: Failed to read DNS servers for interface wlp3s0, ignoring: Argument list too long --- src/resolve/resolved-dns-server.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 49d488cec5..3095c042db 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -157,6 +157,7 @@ void dns_server_unlink(DnsServer *s) { assert(s->link); assert(s->link->n_dns_servers > 0); LIST_REMOVE(servers, s->link->dns_servers, s); + s->link->n_dns_servers--; break; case DNS_SERVER_SYSTEM: -- cgit v1.2.3-54-g00ecf From 6f270e6bd8b78aedf9f77534d6d11141ea0bf8ca Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 20 May 2016 09:12:42 -0400 Subject: Make the fix for net/if.h fuckup even worse (#3287) The original conflict is fixed in the kernel in v4.6-rc7-40-g4a91cb61bb, but now our work-around causes a compilation failure. Keep the workaround to support 4.5 kernels for now, and layer more ugliness on top. Tested with: kernel-headers-4.6.0-1.fc25.x86_64 glibc-devel-2.23.90-18.fc25.x86_64 kernel-headers-4.5.4-300.fc24.x86_64 glibc-devel-2.23.1-7.fc24.x86_64 kernel-headers-4.4.9-300.fc23.x86_64 glibc-devel-2.22-16.fc23.x86_64 kernel-headers-4.1.13-100.fc21.x86_64 glibc-devel-2.20-8.fc21.x86_64 --- src/shared/firewall-util.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index 97865eac4a..f73108eaa3 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -29,12 +29,10 @@ #include #include #include -#include #ifndef IFNAMSIZ -#undef _NET_IF_H -/* Let's make sure to include this one, too, if IFNAMSIZ isn't defined yet, as it is for kernels <= 4.2 */ -#include +#define IFNAMSIZ 16 #endif +#include #include #include #include -- cgit v1.2.3-54-g00ecf From 4e282d11b7f4d08c85b8b80b055b3c92f6714ee1 Mon Sep 17 00:00:00 2001 From: Jonathan Boulle Date: Fri, 20 May 2016 16:20:00 +0200 Subject: core/dbus: revert oversimplification (#3309) free_and_strdup handles NULL but not empty strings. See also: https://github.com/systemd/systemd/pull/3283#issuecomment-220603145 https://github.com/systemd/systemd/pull/3307 --- src/core/dbus-execute.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 888319593c..3be88ddf90 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1454,9 +1454,10 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - r = free_and_strdup(&c->selinux_context, s); - if (r < 0) - return r; + if (isempty(s)) + c->selinux_context = mfree(c->selinux_context); + else if (free_and_strdup(&c->selinux_context, s) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, strempty(s)); } -- cgit v1.2.3-54-g00ecf From 76736280668df164b867bb6c7c86588d0ec2cda1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 20 May 2016 22:36:22 +0200 Subject: Revert "core/dbus: further simplify branch code" (#3307) --- src/core/dbus-execute.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 3be88ddf90..06943c6365 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -836,9 +836,11 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - r = free_and_strdup(&c->user, uu); - if (r < 0) - return r; + + if (isempty(uu)) + c->user = mfree(c->user); + else if (free_and_strdup(&c->user, uu) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu); } @@ -853,9 +855,11 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - r = free_and_strdup(&c->group, gg); - if (r < 0) - return r; + + if (isempty(gg)) + c->group = mfree(c->group); + else if (free_and_strdup(&c->group, gg) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg); } @@ -869,9 +873,11 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - r = free_and_strdup(&c->syslog_identifier, id); - if (r < 0) - return r; + + if (isempty(id)) + c->syslog_identifier = mfree(c->syslog_identifier); + else if (free_and_strdup(&c->syslog_identifier, id) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id); } @@ -1088,9 +1094,10 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - r = free_and_strdup(&c->utmp_id, id); - if (r < 0) - return r; + if (isempty(id)) + c->utmp_id = mfree(c->utmp_id); + else if (free_and_strdup(&c->utmp_id, id) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s\n", strempty(id)); } @@ -1125,9 +1132,10 @@ int bus_exec_context_set_transient_property( return r; if (mode != UNIT_CHECK) { - r = free_and_strdup(&c->pam_name, n); - if (r < 0) - return r; + if (isempty(n)) + c->pam_name = mfree(c->pam_name); + else if (free_and_strdup(&c->pam_name, n) < 0) + return -ENOMEM; unit_write_drop_in_private_format(u, mode, name, "PAMName=%s\n", strempty(n)); } -- cgit v1.2.3-54-g00ecf From 508c45daa4e6381e5d3952ae4ff3d25f839dd97e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 20 May 2016 13:46:42 -0700 Subject: core: put opening curly braces on the same line as function names (#3313) Recently added cgroup helper functions break the style convention. Fix them up. --- src/core/cgroup.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 8b8b2ac5ff..0fb63b1bd1 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -358,8 +358,7 @@ fail: return -errno; } -static bool cgroup_context_has_io_config(CGroupContext *c) -{ +static bool cgroup_context_has_io_config(CGroupContext *c) { return c->io_accounting || c->io_weight != CGROUP_WEIGHT_INVALID || c->startup_io_weight != CGROUP_WEIGHT_INVALID || @@ -367,8 +366,7 @@ static bool cgroup_context_has_io_config(CGroupContext *c) c->io_device_limits; } -static bool cgroup_context_has_blockio_config(CGroupContext *c) -{ +static bool cgroup_context_has_blockio_config(CGroupContext *c) { return c->blockio_accounting || c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || @@ -376,8 +374,7 @@ static bool cgroup_context_has_blockio_config(CGroupContext *c) c->blockio_device_bandwidths; } -static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) -{ +static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) { if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_io_weight != CGROUP_WEIGHT_INVALID) return c->startup_io_weight; @@ -387,8 +384,7 @@ static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) return CGROUP_WEIGHT_DEFAULT; } -static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state) -{ +static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state) { if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID) return c->startup_blockio_weight; @@ -398,20 +394,17 @@ static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state return CGROUP_BLKIO_WEIGHT_DEFAULT; } -static uint64_t cgroup_weight_blkio_to_io(uint64_t blkio_weight) -{ +static uint64_t cgroup_weight_blkio_to_io(uint64_t blkio_weight) { return CLAMP(blkio_weight * CGROUP_WEIGHT_DEFAULT / CGROUP_BLKIO_WEIGHT_DEFAULT, CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX); } -static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) -{ +static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) { return CLAMP(io_weight * CGROUP_BLKIO_WEIGHT_DEFAULT / CGROUP_WEIGHT_DEFAULT, CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX); } -static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) -{ +static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) { char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; dev_t dev; int r; @@ -427,8 +420,7 @@ static void cgroup_apply_io_device_weight(const char *path, const char *dev_path "Failed to set io.weight on %s: %m", path); } -static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_path, uint64_t blkio_weight) -{ +static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_path, uint64_t blkio_weight) { char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; dev_t dev; int r; @@ -444,8 +436,7 @@ static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_p "Failed to set blkio.weight_device on %s: %m", path); } -static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_path, uint64_t *limits) -{ +static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_path, uint64_t *limits) { char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)]; char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4]; CGroupIOLimitType type; @@ -476,8 +467,7 @@ static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_p return n; } -static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *dev_path, uint64_t rbps, uint64_t wbps) -{ +static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *dev_path, uint64_t rbps, uint64_t wbps) { char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1]; dev_t dev; unsigned n = 0; -- cgit v1.2.3-54-g00ecf From 3da48d7aa9438029f45b84124b825634c2f091dc Mon Sep 17 00:00:00 2001 From: Evgeny Vereshchagin Date: Sat, 21 May 2016 19:40:34 +0300 Subject: core: set all log fds to -1 when freezing (#3314) Fixes: -bash-4.3# echo core >/proc/sys/kernel/core_pattern -bash-4.3# kill -ABRT 1 -bash-4.3# kill -ABRT 1 [ 61.373922] systemd[1]: segfault at 7fff1d0a8f48 ip 00007fc9ca91b1c3 sp 00007fff1d0a8f50 error 6 in libc-2.23.so[7fc9ca8ce000+1c0000] [ 61.768017] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000008b [ 61.768017] ... Recursive ABRT and segfault: PID 1 - core TID 1: ... #153905 0x00005575fc3f829d log_dispatch #153906 0x00005575fc3f8aa3 log_assert #153907 0x00005575fc3f8ae9 log_assert_failed #153908 0x00005575fc3e7eb1 safe_close #153909 0x00005575fc3f6d5e log_close_journal #153910 0x00005575fc3f829d log_dispatch #153911 0x00005575fc3f85a1 log_internalv #153912 0x00005575fc3f86a1 log_internal #153913 0x00005575fc31c4c1 crash #153914 0x00007fb26f2cf3d0 __restore_rt #153915 0x00007fb26f2ced00 pause #153916 0x00005575fc403944 freeze #153917 0x00005575fc31bf7b freeze_or_reboot ... --- src/basic/process-util.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 4a7367cc92..1ad8816206 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -667,6 +667,8 @@ bool is_main_thread(void) { noreturn void freeze(void) { + log_close(); + /* Make sure nobody waits for us on a socket anymore */ close_all_fds(NULL, 0); -- cgit v1.2.3-54-g00ecf From cf447cb62d01137f4cbd1cd14b83b88823542bbf Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sat, 21 May 2016 23:00:32 +0200 Subject: libsystemd-network: use recv(..., 0) instead of read(...) (#3317) According to recv(2) these should be the same, but that is not true. Passing a buffer of length 0 to read is defined to be a noop according to read(2), but passing a buffer of length 0 to recv will discard the pending pacet. We can easily hit this as we allocate our buffer size depending on the size of the incoming packet (using FIONREAD). As pointed out in issue #3299 simply sending an empty UDP packet to the DHCP client port will trigger a busy loop in networkd as we are polling on the socket but never discarding the empty packet. This reverts ad5ae47a0d159ea473c9730d7e0298a3e5d31cf6 but fixes the same issue. --- src/libsystemd-network/sd-dhcp-client.c | 5 +---- src/libsystemd-network/sd-dhcp6-client.c | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 123169832c..ad79c6cc2c 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -1636,14 +1636,11 @@ static int client_receive_message_udp( if (buflen < 0) return buflen; - if (buflen == 0) - buflen = 1; - message = malloc0(buflen); if (!message) return -ENOMEM; - len = read(fd, message, buflen); + len = recv(fd, message, buflen, 0); if (len < 0) { if (errno == EAGAIN || errno == EINTR) return 0; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 0c296e39fa..05972e01c9 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -917,7 +917,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, if (!message) return -ENOMEM; - len = read(fd, message, buflen); + len = recv(fd, message, buflen, 0); if (len < 0) { if (errno == EAGAIN || errno == EINTR) return 0; -- cgit v1.2.3-54-g00ecf From 20fc5811192463188b7ffd09897f1e959783d7d1 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 21 May 2016 18:30:33 -0400 Subject: run: do not try to use reply after freeing it (#3318) We'd call sd_bus_message_unref and then proceed to use variables pointing into the reply buffer (fd and char*). dup the fd and copy the string before destorying the reply. This makes systemd-run run again for me. https://bugzilla.redhat.com/show_bug.cgi?id=1337636 --- src/run/run.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/run/run.c b/src/run/run.c index 1d0f74ad21..d6c9b6d37a 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -760,6 +760,7 @@ static int start_transient_service( } else if (arg_transport == BUS_TRANSPORT_MACHINE) { _cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL; const char *s; r = sd_bus_default_system(&system_bus); @@ -772,19 +773,17 @@ static int start_transient_service( "org.freedesktop.machine1.Manager", "OpenMachinePTY", &error, - &reply, + &pty_reply, "s", arg_host); if (r < 0) { log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r)); return r; } - r = sd_bus_message_read(reply, "hs", &master, &s); + r = sd_bus_message_read(pty_reply, "hs", &master, &s); 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"); -- cgit v1.2.3-54-g00ecf From 3a74d4fc90cb322a4784a3515bef7118c8f8c5ba Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 21 May 2016 18:12:17 -0400 Subject: networkd-ndisc: do not return value from void function Fixup for #3304. Only warn, and not return, because that's what sd_dhcp6_client_start() does right below the call to sd_dhcp6_client_set_local_address(). --- src/network/networkd-ndisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 78f02cf746..1a380bd214 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -159,7 +159,7 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); if (r < 0 && r != -EBUSY) - return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); + log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0 && r != -EBUSY) @@ -209,7 +209,7 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); if (r < 0 && r != -EBUSY) - return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); + log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0 && r != -EBUSY) -- cgit v1.2.3-54-g00ecf From 2d900c86dac10aeaedee7d734491ec23bd90ca16 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 24 May 2016 05:32:30 -0400 Subject: Revert "rules: allow users to access frame buffer devices" (#3333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 483d8bbb4c0190f419bf9fba57fb0feb1a56bea6. In [1] Michel Dänzer and Daniel Vetter wrote: >> The scenario you describe isn't possible if the Wayland compositor >> directly uses the KMS API of /dev/dri/card*, but it may be possible if >> the Wayland compositor uses the fbdev API of /dev/fb* instead (e.g. if >> weston uses its fbdev backend). > > Yeah, if both weston and your screen grabber uses native fbdev API you can > now screenshot your desktop. And since fbdev has no concept of "current > owner of the display hw" like the drm master, I think this is not fixable. > At least not just in userspace. Also even with native KMS compositors > fbdev still doesn't have the concept of ownership, which is why it doesn't > bother clearing it's buffer before KMS takes over. I agree that this > should be reverted or at least hidden better. TBH, I think that privilege separation between processes running under the same UID is tenuous. Even with drm, in common setups any user process can ptrace the "current owner of the display" and call DROP_MASTER or do whatever. It *is* possible to prevent that, e.g. by disabling ptrace using yama.ptrace_scope, or selinux, and so on, but afaik this is not commonly done. E.g. all Fedora systems pull in elfutils-default-yama-scope.rpm through dependencies which sets yama.ptrace_scope=0. And even assuming that ptrace was disabled, it is trivial to modify files on disk, communicate through dbus, etc; there is just to many ways for a non-sandboxed process to interact maliciously with the display shell to close them all off. To achieve real protection, some sort of sandboxing must be implemented, and in that case there is no need to rely on access mode on the device files, since much more stringent measures have to be implemented anyway. The situation is similar for framebuffer devices. It is common to add framebuffer users to video group to allow them unlimited access to /dev/fb*. Using uaccess would be better solution in that case. Also, since there is no "current owner" limitation like in DRM, processes running under the same UID should be able to access /proc//fd/* and gain access to the devices. Nevertheless, weston implements a suid wrapper to access the devices and then drop privileges, and this patch would make this daemon pointless. So if the weston developers feel that this change reduces security, I prefer to revert it. [1] https://lists.freedesktop.org/archives/wayland-devel/2016-May/029017.html --- src/login/70-uaccess.rules | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules index 886c5bfcdf..50dcd2e275 100644 --- a/src/login/70-uaccess.rules +++ b/src/login/70-uaccess.rules @@ -42,9 +42,8 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" -# DRI and frame buffer video devices +# DRI video devices SUBSYSTEM=="drm", KERNEL=="card*|renderD*", TAG+="uaccess" -SUBSYSTEM=="graphics", KERNEL=="fb*", TAG+="uaccess" # KVM SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" -- cgit v1.2.3-54-g00ecf From e75cd4c1e74bf004a1bea586bae72fb11ed35d9f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 26 May 2016 15:57:37 +0200 Subject: {machine,system}ctl: always pass &changes and &n_changes (#3350) We have to pass addresses of changes and n_changes to bus_deserialize_and_dump_unit_file_changes(). Otherwise we are hit by missing information (subsequent calls to unit_file_changes_add() to not add anything). Also prevent null pointer dereference in bus_deserialize_and_dump_unit_file_changes() by asserting. Fixes #3339 --- src/machine/machinectl.c | 15 ++++++++--- src/shared/bus-unit-util.c | 5 ++++ src/systemctl/systemctl.c | 64 +++++++++++++++++++++++++++------------------- 3 files changed, 53 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 1165ab5afa..8e4ffa9a39 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1602,6 +1602,8 @@ static int start_machine(int argc, char *argv[], void *userdata) { static int enable_machine(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; int carries_install_info = 0; const char *method = NULL; sd_bus *bus = userdata; @@ -1662,9 +1664,9 @@ 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, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; r = sd_bus_call_method( bus, @@ -1677,10 +1679,15 @@ static int enable_machine(int argc, char *argv[], void *userdata) { NULL); if (r < 0) { log_error("Failed to reload daemon: %s", bus_error_message(&error, -r)); - return r; + goto finish; } - return 0; + r = 0; + +finish: + unit_file_changes_free(changes, n_changes); + + return r; } static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) { diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index f6559cd854..f68c4a41ac 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -865,6 +865,11 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un const char *type, *path, *source; int r; + /* changes is dereferenced when calling unit_file_dump_changes() later, + * so we have to make sure this is not NULL. */ + assert(changes); + assert(n_changes); + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); if (r < 0) return bus_log_parse_error(r); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index b943c68e1b..0500593d06 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2058,6 +2058,8 @@ static int get_default(int argc, char *argv[], void *userdata) { static int set_default(int argc, char *argv[], void *userdata) { _cleanup_free_ char *unit = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; int r; assert(argc >= 2); @@ -2068,13 +2070,8 @@ static int set_default(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to mangle unit name: %m"); if (install_client_side()) { - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet); - unit_file_changes_free(changes, n_changes); - return r; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -2098,9 +2095,9 @@ static int set_default(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r)); - r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; /* Try to reload if enabled */ if (!arg_no_reload) @@ -2109,6 +2106,9 @@ static int set_default(int argc, char *argv[], void *userdata) { r = 0; } +finish: + unit_file_changes_free(changes, n_changes); + return r; } @@ -5650,6 +5650,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; _cleanup_free_ char *target = NULL; const char *verb = argv[0]; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; UnitDependency dep; int r = 0; @@ -5672,13 +5674,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown verb"); if (install_client_side()) { - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet); - unit_file_changes_free(changes, n_changes); - return r; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -5712,27 +5709,32 @@ static int add_dependency(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r)); - r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; - if (arg_no_reload) - return 0; - return daemon_reload(argc, argv, userdata); + if (arg_no_reload) { + r = 0; + goto finish; + } + + r = daemon_reload(argc, argv, userdata); } + +finish: + unit_file_changes_free(changes, n_changes); + + return r; } static int preset_all(int argc, char *argv[], void *userdata) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; int r; if (install_client_side()) { - UnitFileChange *changes = NULL; - unsigned n_changes = 0; - r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet); - unit_file_changes_free(changes, n_changes); - return r; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -5759,14 +5761,22 @@ static int preset_all(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r)); - r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); + r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes); if (r < 0) - return r; + goto finish; - if (arg_no_reload) - return 0; - return daemon_reload(argc, argv, userdata); + if (arg_no_reload) { + r = 0; + goto finish; + } + + r = daemon_reload(argc, argv, userdata); } + +finish: + unit_file_changes_free(changes, n_changes); + + return r; } static int unit_is_enabled(int argc, char *argv[], void *userdata) { -- cgit v1.2.3-54-g00ecf From ba1e172687a6ed7f7d71a7480f900d5432594543 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 May 2016 09:32:41 +0200 Subject: systemctl: fix return values on success --- src/systemctl/systemctl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0500593d06..2480f69a75 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1439,6 +1439,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { assert(c <= n_units); hashmap_free(h); + + r = 0; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -2025,6 +2027,7 @@ static int get_default(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to get default target: %m"); path = _path; + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; @@ -2072,6 +2075,9 @@ static int set_default(int argc, char *argv[], void *userdata) { if (install_client_side()) { r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet); + + if (r > 0) + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -5676,6 +5682,9 @@ static int add_dependency(int argc, char *argv[], void *userdata) { if (install_client_side()) { r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet); + + if (r > 0) + r = 0; } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -5735,6 +5744,9 @@ static int preset_all(int argc, char *argv[], void *userdata) { if (install_client_side()) { r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet); + + if (r > 0) + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; @@ -5817,6 +5829,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { puts(unit_file_state_to_string(state)); } + r = 0; } else { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; -- cgit v1.2.3-54-g00ecf From 227b234720823fc02c3f70cd80da281beb869464 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:23:40 -0400 Subject: FSDG: os-release: Default to PRETTY_NAME "GNU/Linux" instead of "Linux". --- man/kernel-install.xml | 2 +- man/os-release.xml | 2 +- src/analyze/analyze.c | 2 +- src/core/main.c | 4 ++-- src/firstboot/firstboot.c | 2 +- src/kernel-install/90-loaderentry.install | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/man/kernel-install.xml b/man/kernel-install.xml index d7e27de758..eb519188a6 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -106,7 +106,7 @@ PRETTY_NAME parameter specified in /etc/os-release or /usr/lib/os-release (if the former is - missing), or "Linux + missing), or "GNU/Linux KERNEL-VERSION", if unset. If the file initrd is found next to the linux file, the initrd will be added to diff --git a/man/os-release.xml b/man/os-release.xml index 4557abc4a3..767a1c764e 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -194,7 +194,7 @@ suitable for presentation to the user. May or may not contain a release code name or OS version of some kind, as suitable. If not set, defaults to - PRETTY_NAME="Linux". Example: + PRETTY_NAME="GNU/Linux". Example: PRETTY_NAME="Fedora 17 (Beefy Miracle)". diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index d621f66aec..53c97f957f 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -653,7 +653,7 @@ static int analyze_plot(sd_bus *bus) { svg("\n"); svg("%s", pretty_times); svg("%s %s (%s %s %s) %s %s", - isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name, + isempty(host->os_pretty_name) ? "GNU/Linux" : host->os_pretty_name, strempty(host->hostname), strempty(host->kernel_name), strempty(host->kernel_release), diff --git a/src/core/main.c b/src/core/main.c index 6397aadc73..5ed8c3d3f5 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1237,11 +1237,11 @@ static int status_welcome(void) { return status_printf(NULL, false, false, "\nWelcome to \x1B[%sm%s\x1B[0m!\n", isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); else return status_printf(NULL, false, false, "\nWelcome to %s!\n", - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); } static int write_container_id(void) { diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 3df72460ef..1e1a592b7c 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -96,7 +96,7 @@ static void print_welcome(void) { log_warning_errno(r, "Failed to read os-release file: %m"); printf("\nWelcome to your new installation of %s!\nPlease configure a few basic system settings:\n\n", - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); press_any_key(); diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 4c9b1f0327..6e94e12f94 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -37,7 +37,7 @@ elif [[ -f /usr/lib/os-release ]]; then fi if ! [[ $PRETTY_NAME ]]; then - PRETTY_NAME="Linux $KERNEL_VERSION" + PRETTY_NAME="GNU/Linux $KERNEL_VERSION" fi declare -a BOOT_OPTIONS -- cgit v1.2.3-54-g00ecf From 10c64ce22b1abea61cb29d9d2ffcbbd2e84448b1 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:24:56 -0400 Subject: FSDG: os-release: Default to NAME "GNU/Linux" instead of "Linux". --- man/os-release.xml | 2 +- src/journal-remote/journal-gatewayd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/man/os-release.xml b/man/os-release.xml index 767a1c764e..f6787f9340 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -121,7 +121,7 @@ A string identifying the operating system, without a version component, and suitable for presentation to the user. If not set, defaults to - NAME=Linux. Example: + NAME=GNU/Linux. Example: NAME=Fedora or NAME="Debian GNU/Linux". diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 4ad9184993..e265027a04 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -801,7 +801,7 @@ static int request_handler_machine( SD_ID128_FORMAT_VAL(mid), SD_ID128_FORMAT_VAL(bid), hostname_cleanup(hostname), - os_name ? os_name : "Linux", + os_name ? os_name : "GNU/Linux", v ? v : "bare", usage, cutoff_from, -- cgit v1.2.3-54-g00ecf From 23d05b522385ee28da0f7d3769d1840b47a17a59 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:31:20 -0400 Subject: FSDG: systemd-resolved: Default to hostname "gnu-linux" instead of "linux" --- src/resolve/resolved-manager.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index b3ff46b5da..7166b94d71 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -429,12 +429,12 @@ static int manager_watch_hostname(Manager *m) { r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname); if (r < 0) { - log_info("Defaulting to hostname 'linux'."); - m->llmnr_hostname = strdup("linux"); + log_info("Defaulting to hostname 'gnu-linux'."); + m->llmnr_hostname = strdup("gnu-linux"); if (!m->llmnr_hostname) return log_oom(); - m->mdns_hostname = strdup("linux.local"); + m->mdns_hostname = strdup("gnu-linux.local"); if (!m->mdns_hostname) return log_oom(); } else -- cgit v1.2.3-54-g00ecf From 022ed72eff07ca6c1409747e774ef5b35724c9df Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 9 Jun 2016 02:26:44 -0400 Subject: # Rename "Linux Boot Manager" -> "Systemd Boot Manager" sed -i 's|Linux Boot Manager|Systemd Boot Manager|' src/boot/bootctl.c --- src/boot/bootctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index d0af41498f..4a356d25d1 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -763,13 +763,13 @@ static int install_variables(const char *esp_path, "Failed to determine current boot order: %m"); if (first || r == false) { - r = efi_add_boot_option(slot, "Linux Boot Manager", + r = efi_add_boot_option(slot, "Systemd 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\"."); + log_info("Created EFI boot entry \"Systemd Boot Manager\"."); } return insert_into_order(slot, first); -- cgit v1.2.3-54-g00ecf