Cache Allocation Technology is a feature on selected recent Intel Xeon processors which allows control over L3 cache allocation.
Kernel support has been merged to the upstream kernel, via a filesystem resctrlfs. On top of that, a userspace utility, resctrltool has been written to facilitate writing applications and using the filesystem interface (see the rationale at http://www.mail-archive.com/[email protected]/msg1300792.html). This patch adds a new option to systemd, RDTCacheReservation, to allow configuration of CAT via resctrltool. See the first hunk of the patch for a description of the option. Signed-off-by: Marcelo Tosatti <[email protected]> Index: systemd/man/systemd.exec.xml =================================================================== --- systemd.orig/man/systemd.exec.xml +++ systemd/man/systemd.exec.xml @@ -233,6 +233,31 @@ </varlistentry> <varlistentry> + <term><varname>RDTCacheReservation=</varname></term> + + <listitem><para>Creates a L3 CAT reservation in resctrlfs + for the executed processes. Takes a ";" separated list of + tuples (optionally triples) containing type,size and + optionally cacheid: + type=type,size=size,cacheid=id; + type=type,size=size,cacheid=id;... + + Where: + + type is one of: both, data, code. + size is size in kbytes. + cacheid (optional) is the cacheid for + the reservation. + + Rules for the parameters: + * type=code must be paired with type=data entry. + + See the output of resctrltool for more details. + + </para></listitem> + </varlistentry> + + <varlistentry> <term><varname>IOSchedulingClass=</varname></term> <listitem><para>Sets the I/O scheduling class for executed Index: systemd/src/basic/exit-status.c =================================================================== --- systemd.orig/src/basic/exit-status.c +++ systemd/src/basic/exit-status.c @@ -62,6 +62,9 @@ const char* exit_status_to_string(int st case EXIT_OOM_ADJUST: return "OOM_ADJUST"; + case EXIT_RDT_CACHE_RESERVATION: + return "RDT_CACHE_RESERVATION"; + case EXIT_SIGNAL_MASK: return "SIGNAL_MASK"; Index: systemd/src/basic/exit-status.h =================================================================== --- systemd.orig/src/basic/exit-status.h +++ systemd/src/basic/exit-status.h @@ -83,6 +83,7 @@ enum { EXIT_CHOWN, EXIT_SMACK_PROCESS_LABEL, EXIT_KEYRING, + EXIT_RDT_CACHE_RESERVATION, }; typedef enum ExitStatusLevel { Index: systemd/src/core/dbus-execute.c =================================================================== --- systemd.orig/src/core/dbus-execute.c +++ systemd/src/core/dbus-execute.c @@ -119,6 +119,36 @@ static int property_get_oom_score_adjust return sd_bus_message_append(reply, "i", n); } +static int property_get_rdt_cache_reservation( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + int r; + int i; + + assert(bus); + assert(reply); + assert(c); + + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + for (i = 0; i < c->argmidx; i++) { + r = sd_bus_message_append(reply, "s", c->argm[i]); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + static int property_get_nice( sd_bus *bus, const char *path, @@ -759,6 +789,7 @@ const sd_bus_vtable bus_exec_vtable[] = SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RDTCacheReservation", "as", property_get_rdt_cache_reservation, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -921,6 +952,90 @@ int bus_property_get_exec_command_list( return sd_bus_message_close_container(reply); } +static char* convert_rdt_back(char *argm[], int argmidx) +{ + int i, ret; + char *buf, *str; + int size = 0; + int printcomma = 0; + int printsemicolon = 0; + int localmode = 0; + + for (i=0; i < argmidx; i++) { + /* ',', ';', '=' */ + size += strlen(argm[i]) + 3; + } + + buf = malloc(size); + if (buf == NULL) + return NULL; + memset(buf, 0, size); + + str = buf; + + /* cache-id specified */ + for (i=0; i < argmidx; i++) { + if (strlen(argm[i]) == 10) { + if (strcmp(argm[i], "--cache-id") == 0) + localmode = 1; + } + } + + for (i=0; i<argmidx; i++) { + char *cur = argm[i]; + + if (strlen(cur) == 0) + return buf; + + if (strlen(cur) == 6) { + if (strcmp(cur, "--type") == 0) { + ret = sprintf(str, "type="); + str = str + ret; + printcomma = 1; + continue; + } + + if (strcmp(cur, "--size") == 0) { + ret = sprintf(str, "size="); + str = str + ret; + if (localmode == 1) + printcomma = 1; + else + printsemicolon = 1; + + continue; + } + } + + if (strlen(cur) == 10) { + if (strcmp(cur, "--cache-id") == 0) { + ret = sprintf(str, "cache-id="); + str = str + ret; + printsemicolon = 1; + continue; + } + } + + ret = sprintf(str, "%s", cur); + str = str + ret; + + if (i != argmidx - 1) { + if (printsemicolon) { + ret = sprintf(str, ";"); + str = str + 1; + } else if (printcomma) { + ret = sprintf(str, ","); + str = str + 1; + } + + printcomma = 0; + printsemicolon = 0; + } + } + + return buf; +} + int bus_exec_context_set_transient_property( Unit *u, ExecContext *c, @@ -1377,6 +1492,46 @@ int bus_exec_context_set_transient_prope } return 1; + } else if (streq(name, "RDTCacheReservation")) { + + r = sd_bus_message_enter_container(message, 'a', "s"); + if (r < 0) + return r; + + while ((r = sd_bus_message_enter_container(message, 'r', "s")) > 0) { + const char *str; + + r = sd_bus_message_read(message, "s", &str); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) + c->argm[c->argmidx++] = strdup(str); + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + } + + if (mode != UNIT_CHECK) { + char *conv; + + conv = convert_rdt_back(c->argm, c->argmidx); + if (conv == NULL) { + return sd_bus_error_setf(error, + SD_BUS_ERROR_NO_MEMORY, + "out of memory for rdt string convertion"); + } + + unit_write_drop_in_private_format(u, mode, name, "RDTCacheReservation=%s", conv); + free(conv); + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + return 1; } else if (streq(name, "EnvironmentFiles")) { Index: systemd/src/core/execute.c =================================================================== --- systemd.orig/src/core/execute.c +++ systemd/src/core/execute.c @@ -36,6 +36,10 @@ #include <sys/un.h> #include <unistd.h> #include <utmpx.h> +#include <fcntl.h> +#include <sys/select.h> +#include <sys/types.h> +#include <sys/wait.h> #ifdef HAVE_PAM #include <security/pam_appl.h> @@ -2201,6 +2205,161 @@ static int apply_working_directory(const return 0; } + +static int fork_exec_resctrltool(Unit *u, char *argv[]) +{ + int outpipe[2]; + int errpipe[2]; + pid_t cpid; + + pipe(outpipe); + pipe(errpipe); + cpid = fork(); + + if(cpid == 0) { + int r; + + dup2(errpipe[1], STDERR_FILENO); + dup2(outpipe[1], STDOUT_FILENO); + + r = execve(argv[0], argv, NULL); + if (r == -1) { + log_open(); + log_unit_error_errno(u, r, "Failed to execve resctrltool, ignoring: %m"); + log_close(); + return -errno; + } + } else { + char buffer[100]; + fd_set fdset; + int count; + int ret; + int nfds; + int status = 0; + int retst; + + ret = waitpid(cpid, &status, 0); + if (ret == -1) { + log_open(); + log_unit_error_errno(u, ret, "Failed to waitpid resctrltool, ignoring: %m"); + log_close(); + return -errno; + } + + if (!WIFEXITED(status)) { + log_open(); + log_unit_error_errno(u, ret, "resctrltool exits abnormally, ignoring: %m"); + log_close(); + return -1; + } else { + retst = WEXITSTATUS(status); + + if (retst == 0) { + return 0; + } + } + + /* + * error, read stderr and stdout and log. + */ + + FD_ZERO(&fdset); + FD_SET(outpipe[0], &fdset); + FD_SET(errpipe[0], &fdset); + + if (outpipe[0] > errpipe[0]) + nfds = outpipe[0] + 1; + else + nfds = errpipe[0] + 1; + + ret = select(nfds, &fdset, NULL, NULL, NULL); + if (ret == -1) { + log_open(); + log_unit_error_errno(u, ret, "select error, ignoring RDTCacheReservation: %m"); + log_close(); + return -1; + } + + if (FD_ISSET(outpipe[0], &fdset)) { + count = read(outpipe[0], buffer, sizeof(buffer)-1); + if (count >= 0) { + buffer[count] = 0; + log_open(); + log_unit_error(u, "resctrltool stdout: %s", buffer); + log_close(); + } else { + log_open(); + log_unit_error(u, "resctrltool io error\n"); + log_close(); + } + } + + if (FD_ISSET(errpipe[0], &fdset)) { + count = read(errpipe[0], buffer, sizeof(buffer)-1); + if (count >= 0) { + buffer[count] = 0; + log_open(); + log_unit_error(u, "resctrltool stderr: %s", buffer); + log_close(); + } else { + log_open(); + log_unit_error(u, "resctrltool io error\n"); + log_close(); + } + } + + return retst; + } + + return -1; +} + +static int setup_rdt_cat(Unit *u, const ExecContext *c, pid_t pid) +{ + int ret, i; + const char *arg[5]; + char pidstr[100]; + char *name = u->id; + const char *largm[ARGMSIZE + 4]; + + sprintf(pidstr, "%d", pid); + + arg[0] = "/usr/bin/resctrltool"; + arg[1] = "delete"; + arg[2] = name; + arg[3] = 0; + + ret = fork_exec_resctrltool(u, (char **)arg); + /* we want to ignore 'reservation does not exist' + * errors, so skip error checking entirely. + * any other errors will be caught when trying + * to execute create below + */ + + memset(largm, 0, sizeof(largm)); + largm[0] = "/usr/bin/resctrltool"; + largm[1] = "create"; + largm[2] = "--name"; + largm[3] = name; + for (i = 0; i < c->argmidx; i++) + largm[i+4] = c->argm[i]; + + ret = fork_exec_resctrltool(u, (char **)largm); + if (ret) + return ret; + + arg[0] = "/usr/bin/resctrltool"; + arg[1] = "assign"; + arg[2] = pidstr; + arg[3] = name; + arg[4] = 0; + ret = fork_exec_resctrltool(u, (char **)arg); + if (ret) + return ret; + + return 0; +} + static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid) { key_serial_t keyring; @@ -2572,6 +2731,15 @@ static int exec_child( } } + if (context->rdt_cache_reservation_set) { + r = setup_rdt_cat(unit, context, getpid()); + + if (r) { + *exit_status = EXIT_RDT_CACHE_RESERVATION; + return r; + } + } + if (context->nice_set) if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { *exit_status = EXIT_NICE; Index: systemd/src/core/execute.h =================================================================== --- systemd.orig/src/core/execute.h +++ systemd/src/core/execute.h @@ -100,6 +100,8 @@ struct ExecRuntime { int netns_storage_socket[2]; }; +#define ARGMSIZE 100 + struct ExecContext { char **environment; char **environment_files; @@ -218,6 +220,11 @@ struct ExecContext { bool nice_set:1; bool ioprio_set:1; bool cpu_sched_set:1; + bool rdt_cache_reservation_set:1; + + /* Parameters for resctrltool */ + char *argm[ARGMSIZE]; + int argmidx; }; static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) { Index: systemd/src/core/load-fragment-gperf.gperf.m4 =================================================================== --- systemd.orig/src/core/load-fragment-gperf.gperf.m4 +++ systemd/src/core/load-fragment-gperf.gperf.m4 @@ -24,6 +24,7 @@ $1.Group, config_ $1.SupplementaryGroups, config_parse_user_group_strv, 0, offsetof($1, exec_context.supplementary_groups) $1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context) $1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context) +$1.RDTCacheReservation, config_parse_rdt_cache_reservation, 0, offsetof($1, exec_context) $1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context) $1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context) $1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context) Index: systemd/src/core/load-fragment.c =================================================================== --- systemd.orig/src/core/load-fragment.c +++ systemd/src/core/load-fragment.c @@ -567,6 +567,230 @@ int config_parse_exec_oom_score_adjust(c return 0; } +#define STATE_NEXT_TYPE 0 +#define STATE_NEXT_SIZE 1 +#define STATE_NEXT_CACHEID_OR_END 2 + +static void free_argm(ExecContext *c) +{ + int i; + + for (i=0; i < c->argmidx; i++) { + free(c->argm[i]); + c->argm[i] = NULL; + } + c->argmidx = 0; +} + +int config_parse_rdt_cache_reservation(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; + int curstate = STATE_NEXT_TYPE; + char *buf = (char *)rvalue; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* An empty assignment resets the list */ + free_argm(c); + return 0; + } + + do { + if (c->argmidx > ARGMSIZE - 3) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, ENOMEM, + "argmidx overflow, ignoring: %s", rvalue); + return 0; + } + + switch (curstate) { + case STATE_NEXT_TYPE: { + char *string, *buf2; + + buf = strstr(buf, "type="); + if (buf == NULL) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "type= not found when expected, ignoring: %s", rvalue); + return 0; + } + + buf2 = strstr(buf, ","); + if (buf2 == NULL) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + ", not found when parsing type, ignoring: %s", rvalue); + return 0; + } + if (strlen(buf) <= 5) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "invalid type, ignoring: %s", rvalue); + return 0; + } + /* skip type= */ + buf = buf + 5; + if (strlen(buf) < 4) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "invalid type, ignoring: %s", rvalue); + return 0; + } + string = strndup(buf, 4); + if (string == NULL) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, ENOMEM, + "enomem for strndup, ignoring: %s", rvalue); + return 0; + } + + c->argm[c->argmidx++] = strdup("--type"); + c->argm[c->argmidx++] = string; + + /* skip {code,data,both}, */ + buf = buf + 5; + curstate = STATE_NEXT_SIZE; + break; + } + case STATE_NEXT_SIZE: { + char *string, *buf2, *commabuf, *dotcommabuf; + int len, skip = 0; + + buf = strstr(buf, "size="); + if (buf == NULL) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "size= not found when expected, ignoring: %s", rvalue); + return 0; + } + if (strlen(buf) <= 5) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "invalid size, ignoring: %s", rvalue); + return 0; + } + /* skip size= */ + buf = buf + 5; + + commabuf = strstr(buf, ","); + dotcommabuf = strstr(buf, ";"); + + buf2 = NULL; + + /* the end, neither , or ; follow */ + if (commabuf == NULL && dotcommabuf == NULL) { + buf2 = buf + strlen(buf); + skip = 0; + /* only ',': cache-id must follow */ + } else if (commabuf && dotcommabuf == NULL) { + buf2 = commabuf; + skip = 1; + /* trailing ';' at the end */ + } else if (commabuf == NULL && dotcommabuf) { + buf2 = dotcommabuf; + skip = 1; + } else if (commabuf && dotcommabuf) { + if (commabuf > dotcommabuf) + buf2 = dotcommabuf; + else + buf2 = commabuf; + skip = 1; + } + len = buf2 - buf; + string = strndup(buf, len); + if (string == NULL) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, ENOMEM, + "enomem for strndup, ignoring: %s", rvalue); + return 0; + } + + c->argm[c->argmidx++] = strdup("--size"); + c->argm[c->argmidx++] = string; + curstate = STATE_NEXT_CACHEID_OR_END; + + buf = buf2; + buf = buf + skip; + break; + } + case STATE_NEXT_CACHEID_OR_END: { + char *buf2, *string, *dotcommabuf; + int len, skip = 0; + + if (strlen(buf) < 4) + break; + + if (strncmp(buf, "type", 4) == 0) { + curstate = STATE_NEXT_TYPE; + break; + } + + buf = strstr(buf, "cache-id="); + if (buf == NULL) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "cache-id= not found when expected, ignoring: %s", rvalue); + return 0; + } + if (strlen(buf) <= 9) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "invalid cache-id=, ignoring: %s", rvalue); + return 0; + } + /* skip cache-id= */ + buf = buf + 9; + + dotcommabuf = strstr(buf, ";"); + /* the end */ + if (dotcommabuf == NULL) { + buf2 = buf + strlen(buf); + skip = 0; + } else { + buf2 = dotcommabuf; + skip = 1; + } + len = buf2 - buf; + string = strndup(buf, len); + if (string == NULL) { + free_argm(c); + log_syntax(unit, LOG_ERR, filename, line, ENOMEM, + "enomem for strndup, ignoring: %s", rvalue); + return 0; + } + + c->argm[c->argmidx++] = strdup("--cache-id"); + c->argm[c->argmidx++] = string; + + buf = buf + skip; + curstate = STATE_NEXT_TYPE; + break; + } + default: + break; + } + } while (strlen(buf) > 4); + + c->argm[c->argmidx] = 0; + + c->rdt_cache_reservation_set = true; + + return 0; +} + int config_parse_exec( const char *unit, const char *filename, @@ -4551,6 +4775,8 @@ void unit_dump_config_items(FILE *f) { { config_parse_job_mode, "MODE" }, { config_parse_job_mode_isolate, "BOOLEAN" }, { config_parse_personality, "PERSONALITY" }, + { config_parse_rdt_cache_reservation, "RDTCACHERESERVATION" }, + }; const char *prev = NULL; Index: systemd/src/core/load-fragment.h =================================================================== --- systemd.orig/src/core/load-fragment.h +++ systemd/src/core/load-fragment.h @@ -40,6 +40,7 @@ int config_parse_socket_protocol(const c int config_parse_socket_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_exec_nice(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_oom_score_adjust(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_rdt_cache_reservation(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_service_timeout(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_service_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); Index: systemd/src/shared/bus-unit-util.c =================================================================== --- systemd.orig/src/shared/bus-unit-util.c +++ systemd/src/shared/bus-unit-util.c @@ -61,6 +61,7 @@ int bus_parse_unit_info(sd_bus_message * &u->job_path); } + int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) { const char *eq, *field; UnitDependency dep; @@ -470,6 +471,199 @@ int bus_append_unit_property_assignment( } r = sd_bus_message_append(m, "v", "i", oa); + } else if (streq(field, "RDTCacheReservation")) { + int argmidx = 0; +#define ARGMSIZE 100 +#define STATE_NEXT_TYPE 0 +#define STATE_NEXT_SIZE 1 +#define STATE_NEXT_CACHEID_OR_END 2 + int curstate = STATE_NEXT_TYPE; + char *buf = (char *)eq; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return r; + + do { + if (argmidx > ARGMSIZE - 3) { + log_error("argmidx overflow"); + return -EINVAL; + } + + switch (curstate) { + case STATE_NEXT_TYPE: { + char *string, *buf2; + + buf = strstr(buf, "type="); + if (buf == NULL) { + log_error("type= not found when expected"); + return 0; + } + + buf2 = strstr(buf, ","); + if (buf2 == NULL) { + log_error(", not found when parsing type"); + return 0; + } + if (strlen(buf) <= 5) { + log_error("invalid type"); + return 0; + } + + /* skip type= */ + buf = buf + 5; + string = strndup(buf, 4); + if (string == NULL) { + log_error("enomem for strndup"); + return 0; + } + + r = sd_bus_message_append_basic(m, 's', "--type"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', string); + if (r < 0) + return bus_log_create_error(r); + + free(string); + + /* skip {code,data,both}, */ + buf = buf + 5; + curstate = STATE_NEXT_SIZE; + break; + } + + case STATE_NEXT_SIZE: { + char *string, *buf2, *commabuf, *dotcommabuf; + int len, skip = 0; + + buf = strstr(buf, "size="); + if (buf == NULL) { + log_error("size= not found when expected"); + return 0; + } + if (strlen(buf) <= 5) { + log_error("invalid type"); + return 0; + } + /* skip size= */ + buf = buf + 5; + + commabuf = strstr(buf, ","); + dotcommabuf = strstr(buf, ";"); + + /* the end, neither , or ; follow */ + if (commabuf == NULL && dotcommabuf == NULL) { + buf2 = buf + strlen(buf); + skip = 0; + /* only ',': cache-id must follow */ + } else if (commabuf && dotcommabuf == NULL) { + buf2 = commabuf; + skip = 1; + /* trailing ';' at the end */ + } else if (commabuf == NULL && dotcommabuf) { + buf2 = dotcommabuf; + skip = 1; + } else if (commabuf && dotcommabuf) { + if (commabuf > dotcommabuf) + buf2 = dotcommabuf; + else + buf2 = commabuf; + skip = 1; + } + len = buf2 - buf; + string = strndup(buf, len); + if (string == NULL) { + log_error("enomem for strndup"); + return 0; + } + + r = sd_bus_message_append_basic(m, 's', "--size"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', string); + if (r < 0) + return bus_log_create_error(r); + + free(string); + curstate = STATE_NEXT_CACHEID_OR_END; + + buf = buf2; + buf = buf + skip; + break; + } + case STATE_NEXT_CACHEID_OR_END: { + char *buf2, *string, *dotcommabuf; + int len, skip = 0; + + if (strlen(buf) < 4) + break; + if (strncmp(buf, "type", 4) == 0) { + curstate = STATE_NEXT_TYPE; + break; + } + + buf = strstr(buf, "cache-id="); + if (buf == NULL) { + log_error("cache-id= not found when expected"); + return 0; + } + if (strlen(buf) <= 9) { + log_error("invalid cache-id="); + return 0; + } + /* skip cache-id= */ + buf = buf + 9; + + dotcommabuf = strstr(buf, ";"); + /* the end */ + if (dotcommabuf == NULL) { + buf2 = buf + strlen(buf); + skip = 0; + } else { + buf2 = dotcommabuf; + buf2 = buf2 + 1; + skip = 0; + } + len = buf2 - buf; + string = strndup(buf, len); + if (string == NULL) { + log_error("enomem for strndup"); + return 0; + } + + r = sd_bus_message_append_basic(m, 's', "--cache-id"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, 's', string); + if (r < 0) + return bus_log_create_error(r); + + free(string); + + buf = buf + skip; + curstate = STATE_NEXT_TYPE; + break; + } + default: + break; + } + } while (strlen(buf) > 4); + + 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 (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) { const char *p; _______________________________________________ systemd-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/systemd-devel
