diff options
Diffstat (limited to 'src')
26 files changed, 949 insertions, 52 deletions
diff --git a/src/basic/missing.h b/src/basic/missing.h index e860fa7c2c..55028754cd 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -759,6 +759,25 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) #endif +#if !HAVE_DECL_IFLA_GENEVE_LABEL +#define IFLA_GENEVE_UNSPEC 0 +#define IFLA_GENEVE_ID 1 +#define IFLA_GENEVE_REMOTE 2 +#define IFLA_GENEVE_TTL 3 +#define IFLA_GENEVE_TOS 4 +#define IFLA_GENEVE_PORT 5 +#define IFLA_GENEVE_COLLECT_METADATA 6 +#define IFLA_GENEVE_REMOTE6 7 +#define IFLA_GENEVE_UDP_CSUM 8 +#define IFLA_GENEVE_UDP_ZERO_CSUM6_TX 9 +#define IFLA_GENEVE_UDP_ZERO_CSUM6_RX 10 +#define IFLA_GENEVE_LABEL 11 + +#define __IFLA_GENEVE_MAX 12 + +#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) +#endif + #if !HAVE_DECL_IFLA_IPTUN_ENCAP_DPORT #define IFLA_IPTUN_UNSPEC 0 #define IFLA_IPTUN_LINK 1 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 5b7471c0d0..af3c6a4606 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -392,7 +392,9 @@ int config_parse_socket_listen(const char *unit, r = socket_address_parse_and_warn(&p->address, k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue); + if (r != -EAFNOSUPPORT) + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue); + return 0; } @@ -3907,6 +3909,7 @@ int config_parse_bind_paths( void *userdata) { ExecContext *c = data; + Unit *u = userdata; const char *p; int r; @@ -3926,6 +3929,7 @@ int config_parse_bind_paths( p = rvalue; for (;;) { _cleanup_free_ char *source = NULL, *destination = NULL; + _cleanup_free_ char *sresolved = NULL, *dresolved = NULL; char *s = NULL, *d = NULL; bool rbind = true, ignore_enoent = false; @@ -3939,7 +3943,14 @@ int config_parse_bind_paths( return 0; } - s = source; + r = unit_full_printf(u, source, &sresolved); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to resolved specifiers in \"%s\", ignoring: %m", source); + return 0; + } + + s = sresolved; if (s[0] == '-') { ignore_enoent = true; s++; @@ -3970,16 +3981,23 @@ int config_parse_bind_paths( return 0; } - if (!utf8_is_valid(destination)) { - log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, destination); + r = unit_full_printf(u, destination, &dresolved); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to resolved specifiers in \"%s\", ignoring: %m", destination); + return 0; + } + + if (!utf8_is_valid(dresolved)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, dresolved); return 0; } - if (!path_is_absolute(destination)) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", destination); + if (!path_is_absolute(dresolved)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute destination path, ignoring: %s", dresolved); return 0; } - d = path_kill_slashes(destination); + d = path_kill_slashes(dresolved); /* Optionally, there's also a short option string specified */ if (p && p[-1] == ':') { diff --git a/src/core/service.c b/src/core/service.c index 185173a542..a63c6d8bc3 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -45,6 +45,7 @@ #include "service.h" #include "signal-util.h" #include "special.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -2140,6 +2141,80 @@ _pure_ static bool service_can_reload(Unit *u) { return !!s->exec_command[SERVICE_EXEC_RELOAD]; } +static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecCommand *current) { + Service *s = SERVICE(u); + unsigned idx = 0; + ExecCommand *first, *c; + + assert(s); + + first = s->exec_command[id]; + + /* Figure out where we are in the list by walking back to the beginning */ + for (c = current; c != first; c = c->command_prev) + idx++; + + return idx; +} + +static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command) { + Service *s = SERVICE(u); + ServiceExecCommand id; + unsigned idx; + const char *type; + char **arg; + _cleanup_strv_free_ char **escaped_args = NULL; + _cleanup_free_ char *args = NULL, *p = NULL; + size_t allocated = 0, length = 0; + + assert(s); + assert(f); + + if (!command) + return 0; + + if (command == s->control_command) { + type = "control"; + id = s->control_command_id; + } else { + type = "main"; + id = SERVICE_EXEC_START; + } + + idx = service_exec_command_index(u, id, command); + + STRV_FOREACH(arg, command->argv) { + size_t n; + _cleanup_free_ char *e = NULL; + + e = xescape(*arg, WHITESPACE); + if (!e) + return -ENOMEM; + + n = strlen(e); + if (!GREEDY_REALLOC(args, allocated, length + 1 + n + 1)) + return -ENOMEM; + + if (length > 0) + args[length++] = ' '; + + memcpy(args + length, e, n); + length += n; + } + + if (!GREEDY_REALLOC(args, allocated, length + 1)) + return -ENOMEM; + args[length++] = 0; + + p = xescape(command->path, WHITESPACE); + if (!p) + return -ENOMEM; + + fprintf(f, "%s-command=%s %u %s %s\n", type, service_exec_command_to_string(id), idx, p, args); + + return 0; +} + static int service_serialize(Unit *u, FILE *f, FDSet *fds) { Service *s = SERVICE(u); ServiceFDStore *fs; @@ -2167,11 +2242,8 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { if (r < 0) return r; - /* FIXME: There's a minor uncleanliness here: if there are - * multiple commands attached here, we will start from the - * first one again */ - if (s->control_command_id >= 0) - unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id)); + service_serialize_exec_command(u, f, s->control_command); + service_serialize_exec_command(u, f, s->main_command); r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd); if (r < 0) @@ -2227,6 +2299,106 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { return 0; } +static int service_deserialize_exec_command(Unit *u, const char *key, const char *value) { + Service *s = SERVICE(u); + int r; + unsigned idx = 0, i; + bool control, found = false; + ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID; + ExecCommand *command = NULL; + _cleanup_free_ char *args = NULL, *path = NULL; + _cleanup_strv_free_ char **argv = NULL; + + enum ExecCommandState { + STATE_EXEC_COMMAND_TYPE, + STATE_EXEC_COMMAND_INDEX, + STATE_EXEC_COMMAND_PATH, + STATE_EXEC_COMMAND_ARGS, + _STATE_EXEC_COMMAND_MAX, + _STATE_EXEC_COMMAND_INVALID = -1, + } state; + + assert(s); + assert(key); + assert(value); + + control = streq(key, "control-command"); + + state = STATE_EXEC_COMMAND_TYPE; + + for (;;) { + _cleanup_free_ char *arg = NULL; + + r = extract_first_word(&value, &arg, NULL, EXTRACT_CUNESCAPE); + if (r == 0) + break; + else if (r < 0) + return r; + + switch (state) { + case STATE_EXEC_COMMAND_TYPE: + id = service_exec_command_from_string(arg); + if (id < 0) + return -EINVAL; + + state = STATE_EXEC_COMMAND_INDEX; + break; + case STATE_EXEC_COMMAND_INDEX: + r = safe_atou(arg, &idx); + if (r < 0) + return -EINVAL; + + state = STATE_EXEC_COMMAND_PATH; + break; + case STATE_EXEC_COMMAND_PATH: + path = arg; + arg = NULL; + state = STATE_EXEC_COMMAND_ARGS; + + if (!path_is_absolute(path)) + return -EINVAL; + break; + case STATE_EXEC_COMMAND_ARGS: + r = strv_extend(&argv, arg); + if (r < 0) + return -ENOMEM; + break; + default: + assert_not_reached("Unknown error at deserialization of exec command"); + break; + } + } + + if (state != STATE_EXEC_COMMAND_ARGS) + return -EINVAL; + + /* Let's check whether exec command on given offset matches data that we just deserialized */ + for (command = s->exec_command[id], i = 0; command; command = command->command_next, i++) { + if (i != idx) + continue; + + found = strv_equal(argv, command->argv) && streq(command->path, path); + break; + } + + if (!found) { + /* Command at the index we serialized is different, let's look for command that exactly + * matches but is on different index. If there is no such command we will not resume execution. */ + for (command = s->exec_command[id]; command; command = command->command_next) + if (strv_equal(command->argv, argv) && streq(command->path, path)) + break; + } + + if (command && control) + s->control_command = command; + else if (command) + s->main_command = command; + else + log_unit_warning(u, "Current command vanished from the unit file, execution of the command list won't be resumed."); + + return 0; +} + static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { Service *s = SERVICE(u); int r; @@ -2309,16 +2481,6 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, s->status_text = t; } - } else if (streq(key, "control-command")) { - ServiceExecCommand id; - - id = service_exec_command_from_string(value); - if (id < 0) - log_unit_debug(u, "Failed to parse exec-command value: %s", value); - else { - s->control_command_id = id; - s->control_command = s->exec_command[id]; - } } else if (streq(key, "accept-socket")) { Unit *socket; @@ -2437,6 +2599,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, s->watchdog_override_enable = true; s->watchdog_override_usec = watchdog_override_usec; } + } else if (STR_IN_SET(key, "main-command", "control-command")) { + r = service_deserialize_exec_command(u, key, value); + if (r < 0) + log_unit_debug_errno(u, r, "Failed to parse serialized command \"%s\": %m", value); } else log_unit_debug(u, "Unknown serialization key: %s", key); diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 2677a3fb32..50d350fce8 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -358,7 +358,7 @@ static int add_mount( "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n", source); - if (!noauto && !nofail && !automount) + if (!nofail && !automount) fprintf(f, "Before=%s\n", post); if (!automount && opts) { diff --git a/src/import/pull-common.c b/src/import/pull-common.c index 62a9195cc4..4c745288f5 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -275,6 +275,7 @@ int pull_make_verification_jobs( _cleanup_(pull_job_unrefp) PullJob *checksum_job = NULL, *signature_job = NULL; int r; + const char *chksums = NULL; assert(ret_checksum_job); assert(ret_signature_job); @@ -284,10 +285,16 @@ int pull_make_verification_jobs( assert(glue); if (verify != IMPORT_VERIFY_NO) { - _cleanup_free_ char *checksum_url = NULL; + _cleanup_free_ char *checksum_url = NULL, *fn = NULL; - /* Queue job for the SHA256SUMS file for the image */ - r = import_url_change_last_component(url, "SHA256SUMS", &checksum_url); + /* Queue jobs for the checksum file for the image. */ + r = import_url_last_component(url, &fn); + if (r < 0) + return r; + + chksums = strjoina(fn, ".sha256"); + + r = import_url_change_last_component(url, chksums, &checksum_url); if (r < 0) return r; @@ -362,6 +369,15 @@ static int verify_one(PullJob *checksum_job, PullJob *job) { line, strlen(line)); + if (!p) { + line = strjoina(job->checksum, " ", fn, "\n"); + + p = memmem(checksum_job->payload, + checksum_job->payload_size, + line, + strlen(line)); + } + if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) { log_error("DOWNLOAD INVALID: Checksum of %s file did not checkout, file has been tampered with.", fn); return -EBADMSG; @@ -416,6 +432,9 @@ int pull_verify(PullJob *main_job, if (!signature_job) return 0; + if (checksum_job->style == VERIFICATION_PER_FILE) + signature_job = checksum_job; + assert(signature_job->state == PULL_JOB_DONE); if (!signature_job->payload || signature_job->payload_size <= 0) { @@ -507,9 +526,11 @@ int pull_verify(PullJob *main_job, cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH; cmd[k++] = "--verify"; - cmd[k++] = sig_file_path; - cmd[k++] = "-"; - cmd[k++] = NULL; + if (checksum_job->style == VERIFICATION_PER_DIRECTORY) { + cmd[k++] = sig_file_path; + cmd[k++] = "-"; + cmd[k++] = NULL; + } stdio_unset_cloexec(); diff --git a/src/import/pull-job.c b/src/import/pull-job.c index 70aaa5c291..8eabb09eed 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -29,6 +29,8 @@ #include "string-util.h" #include "strv.h" #include "xattr-util.h" +#include "pull-common.h" +#include "import-util.h" PullJob* pull_job_unref(PullJob *j) { if (!j) @@ -73,6 +75,33 @@ static void pull_job_finish(PullJob *j, int ret) { j->on_finished(j); } +static int pull_job_restart(PullJob *j) { + int r; + char *chksum_url = NULL; + + r = import_url_change_last_component(j->url, "SHA256SUMS", &chksum_url); + if (r < 0) + return r; + + free(j->url); + free(j->payload); + j->url = chksum_url; + j->state = PULL_JOB_INIT; + j->payload = NULL; + j->payload_size = 0; + j->payload_allocated = 0; + j->written_compressed = 0; + j->written_uncompressed = 0; + j->written_since_last_grow = 0; + + r = pull_job_begin(j); + if (r < 0) + return r; + + return 0; +} + + void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { PullJob *j = NULL; CURLcode code; @@ -102,6 +131,26 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { r = 0; goto finish; } else if (status >= 300) { + if (status == 404 && j->style == VERIFICATION_PER_FILE) { + + /* retry pull job with SHA256SUMS file */ + r = pull_job_restart(j); + if (r < 0) + goto finish; + + code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status); + if (code != CURLE_OK) { + log_error("Failed to retrieve response code: %s", curl_easy_strerror(code)); + r = -EIO; + goto finish; + } + + if (status == 0) { + j->style = VERIFICATION_PER_DIRECTORY; + return; + } + } + log_error("HTTP request to %s failed with code %li.", j->url, status); r = -EIO; goto finish; @@ -528,6 +577,7 @@ int pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata) j->content_length = (uint64_t) -1; j->start_usec = now(CLOCK_MONOTONIC); j->compressed_max = j->uncompressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU; /* 64GB safety limit */ + j->style = VERIFICATION_STYLE_UNSET; j->url = strdup(url); if (!j->url) diff --git a/src/import/pull-job.h b/src/import/pull-job.h index 3a152a50e3..412b66cf22 100644 --- a/src/import/pull-job.h +++ b/src/import/pull-job.h @@ -42,6 +42,12 @@ typedef enum PullJobState { _PULL_JOB_STATE_INVALID = -1, } PullJobState; +typedef enum VerificationStyle { + VERIFICATION_STYLE_UNSET, + VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline signature */ + VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detach SHA256SUM.gpg signatures */ +} VerificationStyle; + #define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED)) struct PullJob { @@ -94,6 +100,8 @@ struct PullJob { bool grow_machine_directory; uint64_t written_since_last_grow; + + VerificationStyle style; }; int pull_job_new(PullJob **job, const char *url, CurlGlue *glue, void *userdata); diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 60a769e944..fd2e472f09 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -478,11 +478,9 @@ static void raw_pull_job_on_finished(PullJob *j) { } else if (j == i->settings_job) { if (j->error != 0) log_info_errno(j->error, "Settings file could not be retrieved, proceeding without."); - } else if (j->error != 0) { + } else if (j->error != 0 && j != i->signature_job) { if (j == i->checksum_job) log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)"); - else if (j == i->signature_job) - log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); else log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)"); @@ -500,6 +498,13 @@ static void raw_pull_job_on_finished(PullJob *j) { if (!raw_pull_is_done(i)) return; + if (i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) { + log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); + + r = i->signature_job->error; + goto finish; + } + if (i->roothash_job) i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd); if (i->settings_job) @@ -744,6 +749,7 @@ int raw_pull_start( if (i->checksum_job) { i->checksum_job->on_progress = raw_pull_job_on_progress; + i->checksum_job->style = VERIFICATION_PER_FILE; r = pull_job_begin(i->checksum_job); if (r < 0) diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 91833d6174..d4b599ba95 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -298,11 +298,9 @@ static void tar_pull_job_on_finished(PullJob *j) { if (j == i->settings_job) { if (j->error != 0) log_info_errno(j->error, "Settings file could not be retrieved, proceeding without."); - } else if (j->error != 0) { + } else if (j->error != 0 && j != i->signature_job) { if (j == i->checksum_job) log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)"); - else if (j == i->signature_job) - log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); else log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)"); @@ -317,6 +315,13 @@ static void tar_pull_job_on_finished(PullJob *j) { if (!tar_pull_is_done(i)) return; + if (i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) { + log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); + + r = i->signature_job->error; + goto finish; + } + i->tar_job->disk_fd = safe_close(i->tar_job->disk_fd); if (i->settings_job) i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd); @@ -547,6 +552,7 @@ int tar_pull_start( if (i->checksum_job) { i->checksum_job->on_progress = tar_pull_job_on_progress; + i->checksum_job->style = VERIFICATION_PER_FILE; r = pull_job_begin(i->checksum_job); if (r < 0) diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 71967a0f33..86afb4985d 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -2424,6 +2424,7 @@ _public_ int sd_journal_process(sd_journal *j) { assert_return(!journal_pid_changed(j), -ECHILD); j->last_process_usec = now(CLOCK_MONOTONIC); + j->last_invalidate_counter = j->current_invalidate_counter; for (;;) { union inotify_event_buffer buffer; diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index c1135ffa22..92cb790d49 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -517,3 +517,8 @@ global: sd_id128_get_machine_app_specific; sd_is_socket_sockaddr; } LIBSYSTEMD_232; + +LIBSYSTEMD_234 { +global: + sd_bus_message_appendv; +} LIBSYSTEMD_233; diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index 2d06bf541f..04158cae4d 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -48,7 +48,7 @@ _public_ int sd_bus_emit_signal( va_list ap; va_start(ap, types); - r = bus_message_append_ap(m, types, ap); + r = sd_bus_message_appendv(m, types, ap); va_end(ap); if (r < 0) return r; @@ -85,7 +85,7 @@ _public_ int sd_bus_call_method_async( va_list ap; va_start(ap, types); - r = bus_message_append_ap(m, types, ap); + r = sd_bus_message_appendv(m, types, ap); va_end(ap); if (r < 0) return r; @@ -123,7 +123,7 @@ _public_ int sd_bus_call_method( va_list ap; va_start(ap, types); - r = bus_message_append_ap(m, types, ap); + r = sd_bus_message_appendv(m, types, ap); va_end(ap); if (r < 0) goto fail; @@ -162,7 +162,7 @@ _public_ int sd_bus_reply_method_return( va_list ap; va_start(ap, types); - r = bus_message_append_ap(m, types, ap); + r = sd_bus_message_appendv(m, types, ap); va_end(ap); if (r < 0) return r; @@ -493,7 +493,7 @@ _public_ int sd_bus_set_property( goto fail; va_start(ap, type); - r = bus_message_append_ap(m, type, ap); + r = sd_bus_message_appendv(m, type, ap); va_end(ap); if (r < 0) goto fail; diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 5cec804e32..da6fd3b896 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -2341,7 +2341,7 @@ static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const cha return 1; } -int bus_message_append_ap( +_public_ int sd_bus_message_appendv( sd_bus_message *m, const char *types, va_list ap) { @@ -2351,10 +2351,10 @@ int bus_message_append_ap( unsigned stack_ptr = 0; int r; - assert(m); - - if (!types) - return 0; + assert_return(m, -EINVAL); + assert_return(types, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(!m->poisoned, -ESTALE); n_array = (unsigned) -1; n_struct = strlen(types); @@ -2555,7 +2555,7 @@ _public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) { assert_return(!m->poisoned, -ESTALE); va_start(ap, types); - r = bus_message_append_ap(m, types, ap); + r = sd_bus_message_appendv(m, types, ap); va_end(ap); return r; diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h index 4710c106b9..a59aa73833 100644 --- a/src/libsystemd/sd-bus/bus-message.h +++ b/src/libsystemd/sd-bus/bus-message.h @@ -220,8 +220,6 @@ int bus_message_from_malloc( int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str); int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv); -int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap); - int bus_message_parse_fields(sd_bus_message *m); struct bus_body_part *message_append_part(sd_bus_message *m); diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index fc13a4ce14..248bc90788 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -286,6 +286,19 @@ static const NLType rtnl_link_info_data_vrf_types[] = { [IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 }, }; +static const NLType rtnl_link_info_data_geneve_types[] = { + [IFLA_GENEVE_ID] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GENEVE_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_PORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GENEVE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GENEVE_REMOTE6] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GENEVE_UDP_CSUM] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GENEVE_LABEL] = { .type = NETLINK_TYPE_U32 }, +}; + /* these strings must match the .kind entries in the kernel */ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_BOND] = "bond", @@ -308,6 +321,7 @@ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl", [NL_UNION_LINK_INFO_DATA_VRF] = "vrf", [NL_UNION_LINK_INFO_DATA_VCAN] = "vcan", + [NL_UNION_LINK_INFO_DATA_GENEVE] = "geneve", }; DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData); @@ -349,6 +363,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = { .types = rtnl_link_info_data_ip6tnl_types }, [NL_UNION_LINK_INFO_DATA_VRF] = { .count = ELEMENTSOF(rtnl_link_info_data_vrf_types), .types = rtnl_link_info_data_vrf_types }, + [NL_UNION_LINK_INFO_DATA_GENEVE] = { .count = ELEMENTSOF(rtnl_link_info_data_geneve_types), + .types = rtnl_link_info_data_geneve_types }, }; static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = { diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index 42e96173de..ae65c1d8e4 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -88,6 +88,7 @@ typedef enum NLUnionLinkInfoData { NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL, NL_UNION_LINK_INFO_DATA_VRF, NL_UNION_LINK_INFO_DATA_VCAN, + NL_UNION_LINK_INFO_DATA_GENEVE, _NL_UNION_LINK_INFO_DATA_MAX, _NL_UNION_LINK_INFO_DATA_INVALID = -1 } NLUnionLinkInfoData; diff --git a/src/network/netdev/geneve.c b/src/network/netdev/geneve.c new file mode 100644 index 0000000000..bb9807b556 --- /dev/null +++ b/src/network/netdev/geneve.c @@ -0,0 +1,394 @@ +/*** + This file is part of systemd. + + Copyright 2017 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 <http://www.gnu.org/licenses/>. +***/ + +#include <net/if.h> + +#include "alloc-util.h" +#include "conf-parser.h" +#include "extract-word.h" +#include "geneve.h" +#include "parse-util.h" +#include "sd-netlink.h" +#include "string-util.h" +#include "strv.h" +#include "missing.h" +#include "networkd-manager.h" + +#define GENEVE_FLOW_LABEL_MAX_MASK 0xFFFFFU +#define DEFAULT_GENEVE_DESTINATION_PORT 6081 + +/* callback for geneve netdev's created without a backing Link */ +static int geneve_netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { + _cleanup_netdev_unref_ NetDev *netdev = userdata; + int r; + + assert(netdev->state != _NETDEV_STATE_INVALID); + + r = sd_netlink_message_get_errno(m); + if (r == -EEXIST) + log_netdev_info(netdev, "Geneve netdev exists, using existing without changing its parameters"); + else if (r < 0) { + log_netdev_warning_errno(netdev, r, "Geneve netdev could not be created: %m"); + netdev_drop(netdev); + + return 1; + } + + log_netdev_debug(netdev, "Geneve created"); + + return 1; +} + +static int netdev_geneve_create(NetDev *netdev) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + Geneve *v; + int r; + + assert(netdev); + + v = GENEVE(netdev); + + r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m"); + + r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m"); + + if (netdev->mac) { + r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m"); + } + + if (netdev->mtu) { + r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m"); + } + + r = sd_netlink_message_open_container(m, IFLA_LINKINFO); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); + + r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); + + if (v->id <= GENEVE_VID_MAX) { + r = sd_netlink_message_append_u32(m, IFLA_GENEVE_ID, v->id); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_ID attribute: %m"); + } + + if (!in_addr_is_null(v->remote_family, &v->remote)) { + + if (v->remote_family == AF_INET) + r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in); + else + r = sd_netlink_message_append_in6_addr(m, IFLA_GENEVE_REMOTE6, &v->remote.in6); + + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_GROUP attribute: %m"); + + } + + if (v->ttl) { + r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL, v->ttl); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TTL attribute: %m"); + } + + r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TOS, v->tos); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TOS attribute: %m"); + + r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_CSUM, v->udpcsum); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_CSUM attribute: %m"); + + r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_TX attribute: %m"); + + r = sd_netlink_message_append_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_UDP_ZERO_CSUM6_RX attribute: %m"); + + if (v->dest_port != DEFAULT_GENEVE_DESTINATION_PORT) { + r = sd_netlink_message_append_u16(m, IFLA_GENEVE_PORT, htobe16(v->dest_port)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_PORT attribute: %m"); + } + + if (v->flow_label > 0) { + r = sd_netlink_message_append_u32(m, IFLA_GENEVE_LABEL, htobe32(v->flow_label)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_LABEL attribute: %m"); + } + + r = sd_netlink_message_close_container(m); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); + + r = sd_netlink_message_close_container(m); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); + + r = sd_netlink_call_async(netdev->manager->rtnl, m, geneve_netdev_create_handler, netdev, 0, NULL); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m"); + + netdev_ref(netdev); + + netdev->state = NETDEV_STATE_CREATING; + + log_netdev_debug(netdev, "Creating"); + + + return r; +} + +int config_parse_geneve_vni(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) { + Geneve *v = userdata; + uint32_t f; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou32(rvalue, &f); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve VNI '%s'.", rvalue); + return 0; + } + + if (f > GENEVE_VID_MAX){ + log_syntax(unit, LOG_ERR, filename, line, r, "Geneve VNI out is of range '%s'.", rvalue); + return 0; + } + + v->id = f; + + return 0; +} + +int config_parse_geneve_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) { + Geneve *v = userdata; + uint8_t f; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou8(rvalue, &f); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve TOS '%s'.", rvalue); + return 0; + } + + v->tos = f; + + return 0; +} + +int config_parse_geneve_ttl(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) { + Geneve *v = userdata; + uint8_t f; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou8(rvalue, &f); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve TTL '%s'.", rvalue); + return 0; + } + + if (f == 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid Geneve TTL '%s'.", rvalue); + return 0; + } + + v->ttl = f; + + return 0; +} + +int config_parse_geneve_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) { + Geneve *v = userdata; + union in_addr_union *addr = data, buffer; + int r, f; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = in_addr_from_string_auto(rvalue, &f, &buffer); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "geneve '%s' address is invalid, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + r = in_addr_is_multicast(f, &buffer); + if (r > 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "geneve invalid multicast '%s' address, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + v->remote_family = f; + *addr = buffer; + + return 0; +} + +int config_parse_geneve_destination_port(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) { + Geneve *v = userdata; + uint16_t port; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_ip_port(rvalue, &port); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve destination port '%s'.", rvalue); + return 0; + } + + v->dest_port = port; + + return 0; +} + +int config_parse_geneve_flow_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) { + Geneve *v = userdata; + uint32_t f; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou32(rvalue, &f); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Geneve flow label '%s'.", rvalue); + return 0; + } + + if (f & ~GENEVE_FLOW_LABEL_MAX_MASK) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Geneve flow label '%s' not valid. Flow label range should be [0-1048575].", rvalue); + return 0; + } + + v->flow_label = f; + + return 0; +} + +static void geneve_init(NetDev *netdev) { + Geneve *v; + + assert(netdev); + + v = GENEVE(netdev); + + assert(v); + + v->id = GENEVE_VID_MAX + 1; + v->dest_port = DEFAULT_GENEVE_DESTINATION_PORT; + v->udpcsum = false; + v->udp6zerocsumtx = false; + v->udp6zerocsumrx = false; +} + +const NetDevVTable geneve_vtable = { + .object_size = sizeof(Geneve), + .init = geneve_init, + .sections = "Match\0NetDev\0GENEVE\0", + .create = netdev_geneve_create, + .create_type = NETDEV_CREATE_INDEPENDENT, +}; diff --git a/src/network/netdev/geneve.h b/src/network/netdev/geneve.h new file mode 100644 index 0000000000..3ba599aae6 --- /dev/null +++ b/src/network/netdev/geneve.h @@ -0,0 +1,119 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2017 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 <http://www.gnu.org/licenses/>. +***/ + +typedef struct Geneve Geneve; + +#include "in-addr-util.h" +#include "netdev.h" +#include "networkd-link.h" +#include "networkd-network.h" +#include "netdev.h" + +#define GENEVE_VID_MAX (1u << 24) - 1 + +struct Geneve { + NetDev meta; + + uint32_t id; + uint32_t flow_label; + + int remote_family; + + uint8_t tos; + uint8_t ttl; + + uint16_t dest_port; + + bool udpcsum; + bool udp6zerocsumtx; + bool udp6zerocsumrx; + + union in_addr_union remote; +}; + +DEFINE_NETDEV_CAST(GENEVE, Geneve); +extern const NetDevVTable geneve_vtable; + +int config_parse_geneve_vni(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_geneve_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_geneve_ttl(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_geneve_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_geneve_destination_port(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_geneve_flow_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); diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index 077fbc1d5c..a27a3d5562 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -4,6 +4,7 @@ #include "network-internal.h" #include "netdev/bond.h" #include "netdev/bridge.h" +#include "netdev/geneve.h" #include "netdev/ipvlan.h" #include "netdev/macvlan.h" #include "netdev/tunnel.h" @@ -80,6 +81,15 @@ VXLAN.MaximumFDBEntries, config_parse_unsigned, 0, VXLAN.PortRange, config_parse_port_range, 0, 0 VXLAN.DestinationPort, config_parse_destination_port, 0, offsetof(VxLan, dest_port) VXLAN.FlowLabel, config_parse_flow_label, 0, 0 +GENEVE.Id, config_parse_geneve_vni, 0, offsetof(Geneve, id) +GENEVE.Remote, config_parse_geneve_address, 0, offsetof(Geneve, remote) +GENEVE.TOS, config_parse_geneve_tos, 0, offsetof(Geneve, tos) +GENEVE.TTL, config_parse_geneve_ttl, 0, offsetof(Geneve, ttl) +GENEVE.UDPChecksum, config_parse_bool, 0, offsetof(Geneve, udpcsum) +GENEVE.UDP6ZeroCheckSumRx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumrx) +GENEVE.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(Geneve, udp6zerocsumtx) +GENEVE.DestinationPort, config_parse_geneve_destination_port, 0, offsetof(Geneve, dest_port) +GENEVE.FlowLabel, config_parse_geneve_flow_label, 0, 0 Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue) Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue) Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 9b9e83d9db..3848c863c5 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -35,6 +35,7 @@ #include "netdev/bridge.h" #include "netdev/bond.h" +#include "netdev/geneve.h" #include "netdev/vlan.h" #include "netdev/macvlan.h" #include "netdev/ipvlan.h" @@ -69,6 +70,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable, [NETDEV_KIND_VRF] = &vrf_vtable, [NETDEV_KIND_VCAN] = &vcan_vtable, + [NETDEV_KIND_GENEVE] = &geneve_vtable, }; static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { @@ -94,6 +96,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { [NETDEV_KIND_IP6TNL] = "ip6tnl", [NETDEV_KIND_VRF] = "vrf", [NETDEV_KIND_VCAN] = "vcan", + [NETDEV_KIND_GENEVE] = "geneve", }; DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index 37c7431213..a961e2ac3b 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -57,6 +57,7 @@ typedef enum NetDevKind { NETDEV_KIND_TAP, NETDEV_KIND_VRF, NETDEV_KIND_VCAN, + NETDEV_KIND_GENEVE, _NETDEV_KIND_MAX, _NETDEV_KIND_INVALID = -1 } NetDevKind; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index abd921ee1a..3743113825 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -87,6 +87,7 @@ Route.Scope, config_parse_route_scope, Route.PreferredSource, config_parse_preferred_src, 0, 0 Route.Table, config_parse_route_table, 0, 0 Route.GatewayOnlink, config_parse_gateway_onlink, 0, 0 +Route.IPv6Preference, config_parse_ipv6_route_preference, 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 e2a5c77ed1..56f831628c 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -17,6 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <linux/icmpv6.h> + #include "alloc-util.h" #include "conf-parser.h" #include "in-addr-util.h" @@ -975,6 +977,35 @@ int config_parse_gateway_onlink(const char *unit, n->flags |= RTNH_F_ONLINK; else n->flags &= ~RTNH_F_ONLINK; + n = NULL; + + return 0; +} + +int config_parse_ipv6_route_preference(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_route_free_ Route *n = NULL; + int r; + + if (streq(rvalue, "low")) + n->pref = ICMPV6_ROUTER_PREF_LOW; + else if (streq(rvalue, "medium")) + n->pref = ICMPV6_ROUTER_PREF_MEDIUM; + else if (streq(rvalue, "high")) + n->pref = ICMPV6_ROUTER_PREF_HIGH; + else { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route preference: %s", rvalue); + return 0; + } n = NULL; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index e2446b3e92..47ff6f28a0 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -76,3 +76,4 @@ int config_parse_route_priority(const char *unit, const char *filename, unsigned 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); int config_parse_gateway_onlink(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_ipv6_route_preference(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/shared/pager.c b/src/shared/pager.c index c1480a718b..22d7603ec6 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -53,6 +53,11 @@ noreturn static void pager_fallback(void) { _exit(EXIT_SUCCESS); } +static int stored_stdout = -1; +static int stored_stderr = -1; +static bool stdout_redirected = false; +static bool stderr_redirected = false; + int pager_open(bool no_pager, bool jump_to_end) { _cleanup_close_pair_ int fd[2] = { -1, -1 }; const char *pager; @@ -147,10 +152,19 @@ int pager_open(bool no_pager, bool jump_to_end) { } /* Return in the parent */ - if (dup2(fd[1], STDOUT_FILENO) < 0) + stored_stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 3); + if (dup2(fd[1], STDOUT_FILENO) < 0) { + stored_stdout = safe_close(stored_stdout); return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); - if (dup2(fd[1], STDERR_FILENO) < 0) + } + stdout_redirected = true; + + stored_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); + if (dup2(fd[1], STDERR_FILENO) < 0) { + stored_stderr = safe_close(stored_stderr); return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); + } + stderr_redirected = true; return 1; } @@ -161,8 +175,15 @@ void pager_close(void) { return; /* Inform pager that we are done */ - safe_fclose(stdout); - safe_fclose(stderr); + (void) fflush(stdout); + if (stdout_redirected && ((stored_stdout < 0) || (dup2(stored_stdout, STDOUT_FILENO) < 0))) + (void) close(STDOUT_FILENO); + stored_stdout = safe_close(stored_stdout); + (void) fflush(stderr); + if (stderr_redirected && ((stored_stderr < 0) || (dup2(stored_stderr, STDERR_FILENO) < 0))) + (void) close(STDERR_FILENO); + stored_stderr = safe_close(stored_stderr); + stdout_redirected = stderr_redirected = false; (void) kill(pager_pid, SIGCONT); (void) wait_for_terminate(pager_pid, NULL); diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index c47459c9ad..2b6aeb7989 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -266,6 +266,7 @@ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination); int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority); int sd_bus_message_append(sd_bus_message *m, const char *types, ...); +int sd_bus_message_appendv(sd_bus_message *m, const char *types, va_list ap); int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p); int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, size_t size); int sd_bus_message_append_array_space(sd_bus_message *m, char type, size_t size, void **ptr); |