+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);
+ }
+}
+
+static int load_from_path(Unit *u, const char *path) {
+
+ static const char* const section_table[_UNIT_TYPE_MAX] = {
+ [UNIT_SERVICE] = "Service",
+ [UNIT_TIMER] = "Timer",
+ [UNIT_SOCKET] = "Socket",
+ [UNIT_TARGET] = "Target",
+ [UNIT_DEVICE] = "Device",
+ [UNIT_MOUNT] = "Mount",
+ [UNIT_AUTOMOUNT] = "Automount",
+ [UNIT_SNAPSHOT] = "Snapshot",
+ [UNIT_SWAP] = "Swap"
+ };
+
+#define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
+ { "WorkingDirectory", config_parse_path, &(context).working_directory, section }, \
+ { "RootDirectory", config_parse_path, &(context).root_directory, section }, \
+ { "User", config_parse_string, &(context).user, section }, \
+ { "Group", config_parse_string, &(context).group, section }, \
+ { "SupplementaryGroups", config_parse_strv, &(context).supplementary_groups, section }, \
+ { "Nice", config_parse_nice, &(context), section }, \
+ { "OOMAdjust", config_parse_oom_adjust, &(context), section }, \
+ { "IOSchedulingClass", config_parse_io_class, &(context), section }, \
+ { "IOSchedulingPriority", config_parse_io_priority, &(context), section }, \
+ { "CPUSchedulingPolicy", config_parse_cpu_sched_policy,&(context), section }, \
+ { "CPUSchedulingPriority", config_parse_cpu_sched_prio, &(context), section }, \
+ { "CPUSchedulingResetOnFork", config_parse_bool, &(context).cpu_sched_reset_on_fork, section }, \
+ { "CPUAffinity", config_parse_cpu_affinity, &(context), section }, \
+ { "UMask", config_parse_mode, &(context).umask, section }, \
+ { "Environment", config_parse_strv, &(context).environment, section }, \
+ { "StandardInput", config_parse_input, &(context).std_input, section }, \
+ { "StandardOutput", config_parse_output, &(context).std_output, section }, \
+ { "StandardError", config_parse_output, &(context).std_output, section }, \
+ { "TTYPath", config_parse_path, &(context).tty_path, section }, \
+ { "SyslogIdentifier", config_parse_string, &(context).syslog_identifier, section }, \
+ { "SyslogFacility", config_parse_facility, &(context).syslog_priority, section }, \
+ { "SyslogLevel", config_parse_level, &(context).syslog_priority, section }, \
+ { "Capabilities", config_parse_capabilities, &(context), section }, \
+ { "SecureBits", config_parse_secure_bits, &(context), section }, \
+ { "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context), section }, \
+ { "TimerSlackNS", config_parse_timer_slack_ns, &(context), section }, \
+ { "LimitCPU", config_parse_limit, &(context).rlimit[RLIMIT_CPU], section }, \
+ { "LimitFSIZE", config_parse_limit, &(context).rlimit[RLIMIT_FSIZE], section }, \
+ { "LimitDATA", config_parse_limit, &(context).rlimit[RLIMIT_DATA], section }, \
+ { "LimitSTACK", config_parse_limit, &(context).rlimit[RLIMIT_STACK], section }, \
+ { "LimitCORE", config_parse_limit, &(context).rlimit[RLIMIT_CORE], section }, \
+ { "LimitRSS", config_parse_limit, &(context).rlimit[RLIMIT_RSS], section }, \
+ { "LimitNOFILE", config_parse_limit, &(context).rlimit[RLIMIT_NOFILE], section }, \
+ { "LimitAS", config_parse_limit, &(context).rlimit[RLIMIT_AS], section }, \
+ { "LimitNPROC", config_parse_limit, &(context).rlimit[RLIMIT_NPROC], section }, \
+ { "LimitMEMLOCK", config_parse_limit, &(context).rlimit[RLIMIT_MEMLOCK], section }, \
+ { "LimitLOCKS", config_parse_limit, &(context).rlimit[RLIMIT_LOCKS], section }, \
+ { "LimitSIGPENDING", config_parse_limit, &(context).rlimit[RLIMIT_SIGPENDING], section }, \
+ { "LimitMSGQUEUE", config_parse_limit, &(context).rlimit[RLIMIT_MSGQUEUE], section }, \
+ { "LimitNICE", config_parse_limit, &(context).rlimit[RLIMIT_NICE], section }, \
+ { "LimitRTPRIO", config_parse_limit, &(context).rlimit[RLIMIT_RTPRIO], section }, \
+ { "LimitRTTIME", config_parse_limit, &(context).rlimit[RLIMIT_RTTIME], section }, \
+ { "ControlGroup", config_parse_cgroup, u, section }, \
+ { "ReadWriteDirectories", config_parse_path_strv, &(context).read_write_dirs, section }, \
+ { "ReadOnlyDirectories", config_parse_path_strv, &(context).read_only_dirs, section }, \
+ { "InaccessibleDirectories",config_parse_path_strv, &(context).inaccessible_dirs, section }, \
+ { "PrivateTmp", config_parse_bool, &(context).private_tmp, section }, \
+ { "MountFlags", config_parse_mount_flags, &(context), section }