+
+int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
+ const char *eq, *field;
+ int r;
+
+ assert(m);
+ assert(assignment);
+
+ eq = strchr(assignment, '=');
+ if (!eq) {
+ log_error("Not an assignment: %s", assignment);
+ return -EINVAL;
+ }
+
+ field = strndupa(assignment, eq - assignment);
+ eq ++;
+
+ if (streq(field, "CPUQuota")) {
+
+ if (isempty(eq)) {
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "v", "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_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100);
+ } else {
+ log_error("CPU quota needs to be in percent.");
+ return -EINVAL;
+ }
+
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 0;
+ }
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (STR_IN_SET(field,
+ "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
+ "SendSIGHUP", "SendSIGKILL")) {
+
+ r = parse_boolean(eq);
+ if (r < 0) {
+ log_error("Failed to parse boolean assignment %s.", assignment);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "b", r);
+
+ } else if (streq(field, "MemoryLimit")) {
+ off_t bytes;
+
+ 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", (uint64_t) bytes);
+
+ } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
+ uint64_t u;
+
+ r = safe_atou64(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"))
+ r = sd_bus_message_append(m, "v", "s", eq);
+
+ 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;
+ off_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, (uint64_t) 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 (rlimit_from_string(field) >= 0) {
+ uint64_t rl;
+
+ if (streq(eq, "infinity"))
+ rl = (uint64_t) -1;
+ else {
+ r = safe_atou64(eq, &rl);
+ if (r < 0) {
+ log_error("Invalid resource limit: %s", eq);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "t", rl);
+
+ } 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 (streq(field, "Environment")) {
+
+ r = sd_bus_message_append(m, "v", "as", 1, eq);
+
+ } 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 {
+ log_error("Unknown assignment %s.", assignment);
+ return -EINVAL;
+ }
+
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 0;
+}