+static int merge_by_names(Unit **u, Set *names, const char *id) {
+ char *k;
+ int r;
+
+ assert(u);
+ assert(*u);
+ assert(names);
+
+ /* Let's try to add in all symlink names we found */
+ while ((k = set_steal_first(names))) {
+
+ /* First try to merge in the other name into our
+ * unit */
+ if ((r = unit_merge_by_name(*u, k)) < 0) {
+ Unit *other;
+
+ /* Hmm, we couldn't merge the other unit into
+ * ours? Then let's try it the other way
+ * round */
+
+ other = manager_get_unit((*u)->meta.manager, k);
+ free(k);
+
+ if (other)
+ if ((r = unit_merge(other, *u)) >= 0) {
+ *u = other;
+ return merge_by_names(u, names, NULL);
+ }
+
+ return r;
+ }
+
+ if (id == k)
+ unit_choose_id(*u, id);
+
+ free(k);
+ }
+
+ return 0;
+}
+
+static void dump_items(FILE *f, const ConfigItem *items) {
+ const ConfigItem *i;
+ const char *prev_section = NULL;
+ bool not_first = false;
+
+ struct {
+ ConfigParserCallback callback;
+ const char *rvalue;
+ } table[] = {
+ { config_parse_int, "INTEGER" },
+ { config_parse_unsigned, "UNSIGNED" },
+ { config_parse_size, "SIZE" },
+ { config_parse_bool, "BOOLEAN" },
+ { config_parse_string, "STRING" },
+ { config_parse_path, "PATH" },
+ { config_parse_strv, "STRING [...]" },
+ { config_parse_nice, "NICE" },
+ { config_parse_oom_adjust, "OOMADJUST" },
+ { config_parse_io_class, "IOCLASS" },
+ { config_parse_io_priority, "IOPRIORITY" },
+ { config_parse_cpu_sched_policy, "CPUSCHEDPOLICY" },
+ { config_parse_cpu_sched_prio, "CPUSCHEDPRIO" },
+ { config_parse_cpu_affinity, "CPUAFFINITY" },
+ { config_parse_mode, "MODE" },
+ { config_parse_output, "OUTPUT" },
+ { config_parse_input, "INPUT" },
+ { config_parse_facility, "FACILITY" },
+ { config_parse_level, "LEVEL" },
+ { config_parse_capabilities, "CAPABILITIES" },
+ { config_parse_secure_bits, "SECUREBITS" },
+ { config_parse_bounding_set, "BOUNDINGSET" },
+ { config_parse_timer_slack_ns, "TIMERSLACK" },
+ { config_parse_limit, "LIMIT" },
+ { config_parse_cgroup, "CGROUP [...]" },
+ { config_parse_deps, "UNIT [...]" },
+ { config_parse_names, "UNIT [...]" },
+ { config_parse_exec, "PATH [ARGUMENT [...]]" },
+ { config_parse_service_type, "SERVICETYPE" },
+ { config_parse_service_restart, "SERVICERESTART" },
+ { config_parse_sysv_priority, "SYSVPRIORITY" },
+ { config_parse_kill_mode, "KILLMODE" },
+ { config_parse_listen, "SOCKET [...]" },
+ { config_parse_socket_bind, "SOCKETBIND" },
+ { config_parse_bindtodevice, "NETWORKINTERFACE" },
+ { config_parse_usec, "SECONDS" },
+ { config_parse_path_strv, "PATH [...]" },
+ { config_parse_mount_flags, "MOUNTFLAG [...]" },
+ { config_parse_description, "DESCRIPTION" },
+ };
+
+ assert(f);
+ assert(items);
+
+ for (i = items; i->lvalue; i++) {
+ unsigned j;
+ const char *rvalue = "OTHER";
+
+ if (!streq_ptr(i->section, prev_section)) {
+ if (!not_first)
+ not_first = true;
+ else
+ fputc('\n', f);
+
+ fprintf(f, "[%s]\n", i->section);
+ prev_section = i->section;
+ }
+
+ for (j = 0; j < ELEMENTSOF(table); j++)
+ if (i->parse == table[j].callback) {
+ rvalue = table[j].rvalue;
+ break;
+ }
+
+ fprintf(f, "%s=%s\n", i->lvalue, rvalue);
+ }
+}
+