static sd_json_variant *arg_identity_extra = NULL;
static sd_json_variant *arg_identity_extra_privileged = NULL;
static sd_json_variant *arg_identity_extra_this_machine = NULL;
+static sd_json_variant *arg_identity_extra_other_machines = NULL;
static sd_json_variant *arg_identity_extra_rlimits = NULL;
static char **arg_identity_filter = NULL; /* this one is also applied to 'privileged' and 'thisMachine' subobjects */
static char **arg_identity_filter_rlimits = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra, sd_json_variant_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_this_machine, sd_json_variant_unrefp);
+STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_other_machines, sd_json_variant_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_privileged, sd_json_variant_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_rlimits, sd_json_variant_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_identity_filter, strv_freep);
!sd_json_variant_is_blank_object(arg_identity_extra) ||
!sd_json_variant_is_blank_object(arg_identity_extra_privileged) ||
!sd_json_variant_is_blank_object(arg_identity_extra_this_machine) ||
+ !sd_json_variant_is_blank_object(arg_identity_extra_other_machines) ||
!sd_json_variant_is_blank_object(arg_identity_extra_rlimits) ||
!strv_isempty(arg_identity_filter) ||
!strv_isempty(arg_identity_filter_rlimits) ||
if (r < 0)
return log_error_errno(r, "Failed to merge identities: %m");
- if (arg_identity_extra_this_machine || !strv_isempty(arg_identity_filter)) {
+ if (arg_identity_extra_this_machine || arg_identity_extra_other_machines || !strv_isempty(arg_identity_filter)) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *per_machine = NULL, *mmid = NULL;
sd_id128_t mid;
per_machine = sd_json_variant_ref(sd_json_variant_by_key(v, "perMachine"));
if (per_machine) {
- _cleanup_(sd_json_variant_unrefp) sd_json_variant *npm = NULL, *add = NULL;
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *npm = NULL, *positive = NULL, *negative = NULL;
_cleanup_free_ sd_json_variant **array = NULL;
sd_json_variant *z;
size_t i = 0;
if (!sd_json_variant_is_array(per_machine))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "perMachine field is not an array, refusing.");
- array = new(sd_json_variant*, sd_json_variant_elements(per_machine) + 1);
+ array = new(sd_json_variant*, sd_json_variant_elements(per_machine) + 2);
if (!array)
return log_oom();
array[i++] = z;
u = sd_json_variant_by_key(z, "matchMachineId");
- if (!u)
- continue;
-
- if (!sd_json_variant_equal(u, mmid))
- continue;
+ if (u && sd_json_variant_equal(u, mmid))
+ r = sd_json_variant_merge_object(&positive, z);
+ else {
+ u = sd_json_variant_by_key(z, "matchNotMachineId");
+ if (!u || !sd_json_variant_equal(u, mmid))
+ continue;
- r = sd_json_variant_merge_object(&add, z);
+ r = sd_json_variant_merge_object(&negative, z);
+ }
if (r < 0)
return log_error_errno(r, "Failed to merge perMachine entry: %m");
i--;
}
- r = sd_json_variant_filter(&add, arg_identity_filter);
+ r = sd_json_variant_filter(&positive, arg_identity_filter);
if (r < 0)
return log_error_errno(r, "Failed to filter perMachine: %m");
- r = sd_json_variant_merge_object(&add, arg_identity_extra_this_machine);
+ r = sd_json_variant_filter(&negative, arg_identity_filter);
+ if (r < 0)
+ return log_error_errno(r, "Failed to filter perMachine: %m");
+
+ r = sd_json_variant_merge_object(&positive, arg_identity_extra_this_machine);
+ if (r < 0)
+ return log_error_errno(r, "Failed to merge in perMachine fields: %m");
+
+ r = sd_json_variant_merge_object(&negative, arg_identity_extra_other_machines);
if (r < 0)
return log_error_errno(r, "Failed to merge in perMachine fields: %m");
if (arg_identity_filter_rlimits || arg_identity_extra_rlimits) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *rlv = NULL;
- rlv = sd_json_variant_ref(sd_json_variant_by_key(add, "resourceLimits"));
+ rlv = sd_json_variant_ref(sd_json_variant_by_key(positive, "resourceLimits"));
r = sd_json_variant_filter(&rlv, arg_identity_filter_rlimits);
if (r < 0)
return log_error_errno(r, "Failed to set resource limits: %m");
if (sd_json_variant_is_blank_object(rlv)) {
- r = sd_json_variant_filter(&add, STRV_MAKE("resourceLimits"));
+ r = sd_json_variant_filter(&positive, STRV_MAKE("resourceLimits"));
if (r < 0)
return log_error_errno(r, "Failed to drop resource limits field from identity: %m");
} else {
- r = sd_json_variant_set_field(&add, "resourceLimits", rlv);
+ r = sd_json_variant_set_field(&positive, "resourceLimits", rlv);
if (r < 0)
return log_error_errno(r, "Failed to update resource limits of identity: %m");
}
}
- if (!sd_json_variant_is_blank_object(add)) {
- r = sd_json_variant_set_field(&add, "matchMachineId", mmid);
+ if (!sd_json_variant_is_blank_object(positive)) {
+ r = sd_json_variant_set_field(&positive, "matchMachineId", mmid);
if (r < 0)
return log_error_errno(r, "Failed to set matchMachineId field: %m");
- array[i++] = add;
+ array[i++] = positive;
+ }
+
+ if (!sd_json_variant_is_blank_object(negative)) {
+ r = sd_json_variant_set_field(&negative, "matchNotMachineId", mmid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set matchNotMachineId field: %m");
+
+ array[i++] = negative;
}
r = sd_json_variant_new_array(&npm, array, i);
sd_json_variant_unref(per_machine);
per_machine = TAKE_PTR(npm);
} else {
- _cleanup_(sd_json_variant_unrefp) sd_json_variant *item = sd_json_variant_ref(arg_identity_extra_this_machine);
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *positive = sd_json_variant_ref(arg_identity_extra_this_machine),
+ *negative = sd_json_variant_ref(arg_identity_extra_other_machines);
if (arg_identity_extra_rlimits) {
- r = sd_json_variant_set_field(&item, "resourceLimits", arg_identity_extra_rlimits);
+ r = sd_json_variant_set_field(&positive, "resourceLimits", arg_identity_extra_rlimits);
if (r < 0)
return log_error_errno(r, "Failed to update resource limits of identity: %m");
}
- r = sd_json_variant_set_field(&item, "matchMachineId", mmid);
- if (r < 0)
- return log_error_errno(r, "Failed to set matchMachineId field: %m");
+ if (positive) {
+ r = sd_json_variant_set_field(&positive, "matchMachineId", mmid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set matchMachineId field: %m");
- r = sd_json_variant_append_array(&per_machine, item);
- if (r < 0)
- return log_error_errno(r, "Failed to append to perMachine array: %m");
+ r = sd_json_variant_append_array(&per_machine, positive);
+ if (r < 0)
+ return log_error_errno(r, "Failed to append to perMachine array: %m");
+ }
+
+ if (negative) {
+ r = sd_json_variant_set_field(&negative, "matchNotMachineId", mmid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set matchNotMachineId field: %m");
+
+ r = sd_json_variant_append_array(&per_machine, negative);
+ if (r < 0)
+ return log_error_errno(r, "Failed to append to perMachine array: %m");
+ }
}
r = sd_json_variant_set_field(&v, "perMachine", per_machine);
ARG_DEFAULT_AREA,
ARG_KEY_NAME,
ARG_SEIZE,
+ ARG_MATCH,
};
static const struct option options[] = {
{ "default-area", required_argument, NULL, ARG_DEFAULT_AREA },
{ "key-name", required_argument, NULL, ARG_KEY_NAME },
{ "seize", required_argument, NULL, ARG_SEIZE },
+ { "match", required_argument, NULL, ARG_MATCH },
{}
};
int r;
+ /* This points to one of arg_identity_extra, arg_identity_extra_this_machine,
+ * arg_identity_extra_other_machines, in order to redirect changes on the next property being set to
+ * this part of the identity, instead of the default. */
+ sd_json_variant **match_identity = NULL;
+
assert(argc >= 0);
assert(argv);
for (;;) {
int c;
- c = getopt_long(argc, argv, "hH:M:I:c:d:u:G:k:s:e:b:jPE", options, NULL);
+ c = getopt_long(argc, argv, "hH:M:I:c:d:u:G:k:s:e:b:jPENAT", options, NULL);
if (c < 0)
break;
if (!valid_gecos(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Real name '%s' not a valid GECOS field.", optarg);
- r = sd_json_variant_set_field_string(&arg_identity_extra, "realName", optarg);
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra, "realName", optarg);
if (r < 0)
return log_error_errno(r, "Failed to set realName field: %m");
break;
}
- r = sd_json_variant_set_field_string(&arg_identity_extra, field, optarg);
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra, field, optarg);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return log_error_errno(r, "Failed to validate CIFS service name: %s", optarg);
- r = sd_json_variant_set_field_string(&arg_identity_extra, "cifsService", optarg);
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra, "cifsService", optarg);
if (r < 0)
return log_error_errno(r, "Failed to set cifsService field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse nice level: %s", optarg);
- r = sd_json_variant_set_field_integer(&arg_identity_extra, "niceLevel", nc);
+ r = sd_json_variant_set_field_integer(match_identity ?: &arg_identity_extra, "niceLevel", nc);
if (r < 0)
return log_error_errno(r, "Failed to set niceLevel field: %m");
if (r < 0)
return r;
- r = sd_json_variant_set_field_string(&arg_identity_extra_this_machine, field, v);
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra_this_machine, field, v);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", v);
if (!valid_shell(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Shell '%s' not valid.", optarg);
- r = sd_json_variant_set_field_string(&arg_identity_extra, "shell", optarg);
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra, "shell", optarg);
if (r < 0)
return log_error_errno(r, "Failed to set shell field: %m");
break;
}
- e = sd_json_variant_by_key(arg_identity_extra, "environment");
+ e = sd_json_variant_by_key(match_identity ? *match_identity: arg_identity_extra, "environment");
if (e) {
r = sd_json_variant_strv(e, &l);
if (r < 0)
if (r < 0)
return log_error_errno(r, "Failed to allocate environment list JSON: %m");
- r = sd_json_variant_set_field(&arg_identity_extra, "environment", ne);
+ r = sd_json_variant_set_field(match_identity ?: &arg_identity_extra, "environment", ne);
if (r < 0)
return log_error_errno(r, "Failed to set environment list: %m");
}
case ARG_TIMEZONE:
-
if (isempty(optarg)) {
r = drop_from_identity("timeZone");
if (r < 0)
if (!timezone_is_valid(optarg, LOG_DEBUG))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Timezone '%s' is not valid.", optarg);
- r = sd_json_variant_set_field_string(&arg_identity_extra, "timeZone", optarg);
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra, "timeZone", optarg);
if (r < 0)
return log_error_errno(r, "Failed to set timezone field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse %s boolean: %m", field);
- r = sd_json_variant_set_field_boolean(&arg_identity_extra, field, r > 0);
+ r = sd_json_variant_set_field_boolean(match_identity ?: &arg_identity_extra, field, r > 0);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return r;
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra_this_machine, "diskSize", arg_disk_size);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra_this_machine, "diskSize", arg_disk_size);
if (r < 0)
return log_error_errno(r, "Failed to set diskSize field: %m");
if (r < 0)
return r;
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra_this_machine, "diskSizeRelative", arg_disk_size_relative);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra_this_machine, "diskSizeRelative", arg_disk_size_relative);
if (r < 0)
return log_error_errno(r, "Failed to set diskSizeRelative field: %m");
}
/* Automatically turn off the rebalance logic if user configured a size explicitly */
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra_this_machine, "rebalanceWeight", REBALANCE_WEIGHT_OFF);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra_this_machine, "rebalanceWeight", REBALANCE_WEIGHT_OFF);
if (r < 0)
return log_error_errno(r, "Failed to set rebalanceWeight field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse --luks-discard= parameter: %s", optarg);
- r = sd_json_variant_set_field_boolean(&arg_identity_extra, "luksDiscard", r);
+ r = sd_json_variant_set_field_boolean(match_identity ?: &arg_identity_extra, "luksDiscard", r);
if (r < 0)
return log_error_errno(r, "Failed to set discard field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse --luks-offline-discard= parameter: %s", optarg);
- r = sd_json_variant_set_field_boolean(&arg_identity_extra, "luksOfflineDiscard", r);
+ r = sd_json_variant_set_field_boolean(match_identity ?: &arg_identity_extra, "luksOfflineDiscard", r);
if (r < 0)
return log_error_errno(r, "Failed to set offline discard field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse %s parameter: %s", field, optarg);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field, n);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, field, n);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return r;
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, "luksSectorSize", ss);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, "luksSectorSize", ss);
if (r < 0)
return log_error_errno(r, "Failed to set sector size field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse umask: %m");
- r = sd_json_variant_set_field_integer(&arg_identity_extra, "umask", m);
+ r = sd_json_variant_set_field_integer(match_identity ?: &arg_identity_extra, "umask", m);
if (r < 0)
return log_error_errno(r, "Failed to set umask field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse %s parameter: %m", field);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field, n);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, field, n);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
break;
if (r < 0)
return log_error_errno(r, "Failed to parse %s parameter: %m", field);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field, n);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, field, n);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
break;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parameter for %s field not valid: %s", field, optarg);
r = sd_json_variant_set_field_string(
- IN_SET(c, ARG_STORAGE, ARG_FS_TYPE) ?
- &arg_identity_extra_this_machine :
- &arg_identity_extra, field, optarg);
+ match_identity ?: (IN_SET(c, ARG_STORAGE, ARG_FS_TYPE) ?
+ &arg_identity_extra_this_machine :
+ &arg_identity_extra), field, optarg);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return log_error_errno(r, "Failed to parse %s field: %s", field, optarg);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field, t);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, field, t);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return log_error_errno(r, "Failed to create group list JSON: %m");
- r = sd_json_variant_set_field(&arg_identity_extra, "memberOf", mo);
+ r = sd_json_variant_set_field(match_identity ?: &arg_identity_extra, "memberOf", mo);
if (r < 0)
return log_error_errno(r, "Failed to update group list: %m");
}
if (r < 0)
return log_error_errno(r, "Failed to parse --tasks-max= parameter: %s", optarg);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, "tasksMax", u);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, "tasksMax", u);
if (r < 0)
return log_error_errno(r, "Failed to set tasksMax field: %m");
if (r < 0)
return log_error_errno(r, "Failed to parse %s parameter: %s", field, optarg);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra_this_machine, field, u);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra_this_machine, field, u);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (!CGROUP_WEIGHT_IS_OK(u))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Weight %" PRIu64 " is out of valid weight range.", u);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field, u);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, field, u);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return log_error_errno(r, "Failed to parse --auto-resize-mode= argument: %s", optarg);
- r = sd_json_variant_set_field_string(&arg_identity_extra, "autoResizeMode", auto_resize_mode_to_string(r));
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra, "autoResizeMode", auto_resize_mode_to_string(r));
if (r < 0)
return log_error_errno(r, "Failed to set autoResizeMode field: %m");
return r;
/* Add to main identity */
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, "rebalanceWeight", u);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, "rebalanceWeight", u);
if (r < 0)
return log_error_errno(r, "Failed to set rebalanceWeight field: %m");
if (r < 0)
return r;
- r = sd_json_variant_set_field_boolean(&arg_identity_extra, "dropCaches", r);
+ r = sd_json_variant_set_field_boolean(match_identity ?: &arg_identity_extra, "dropCaches", r);
if (r < 0)
return log_error_errno(r, "Failed to set drop caches field: %m");
if (capability_set_to_strv(updated, &l) < 0)
return log_oom();
- r = sd_json_variant_set_field_strv(&arg_identity_extra, field, l);
+ r = sd_json_variant_set_field_strv(match_identity ?: &arg_identity_extra, field, l);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return log_error_errno(r, "Failed to parse %s/%s parameter: %s", field, field_scale, optarg);
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field, u);
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, field, u);
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field);
if (r < 0)
return r;
} else {
- r = sd_json_variant_set_field_unsigned(&arg_identity_extra, field_scale, UINT32_SCALE_FROM_PERMYRIAD(r));
+ r = sd_json_variant_set_field_unsigned(match_identity ?: &arg_identity_extra, field_scale, UINT32_SCALE_FROM_PERMYRIAD(r));
if (r < 0)
return log_error_errno(r, "Failed to set %s field: %m", field_scale);
if (!filename_is_valid(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parameter for default area field not valid: %s", optarg);
- r = sd_json_variant_set_field_string(&arg_identity_extra, "defaultArea", optarg);
+ r = sd_json_variant_set_field_string(match_identity ?: &arg_identity_extra, "defaultArea", optarg);
if (r < 0)
return log_error_errno(r, "Failed to set default area field: %m");
return r;
break;
+ case ARG_MATCH:
+ if (streq(optarg, "any"))
+ match_identity = &arg_identity_extra;
+ else if (streq(optarg, "this"))
+ match_identity = &arg_identity_extra_this_machine;
+ else if (streq(optarg, "other"))
+ match_identity = &arg_identity_extra_other_machines;
+ else if (streq(optarg, "auto"))
+ match_identity = NULL;
+ else
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--machine= argument not understood. Refusing.");
+ break;
+
+ case 'A':
+ match_identity = &arg_identity_extra;
+ break;
+ case 'T':
+ match_identity = &arg_identity_extra_this_machine;
+ break;
+ case 'N':
+ match_identity = &arg_identity_extra_other_machines;
+ break;
+
case '?':
return -EINVAL;