OmniCube Reference Manualoc_validate(3)

oc_validate(3)

Library Functions · OmniCube · August 10, 2026

NAME

oc_validate, validate_name, validate_dataset, is_in_exact_list, is_snapexists - validate OmniCube identifiers and test list and snapshot membership

SYNOPSIS

amp;. /opt/omnicube/lib/common/utils.sh

validate_name name [kind]
validate_dataset dataset
is_in_exact_list needle [item ...]
is_snapexists snapshot

DESCRIPTION

Almost every value these tools handle — a zone name, a node name, an ssh user, a ZFS dataset — arrives from outside the script: from an operator's command line, from an SMF property such as config/nodes, from a ZFS user property such as ${PROPPREFIX}:snappolicy, or from a backup policy file. Those values are then interpolated into privileged command lines: zonecfg(8), zoneadm(8), zfs(8), zpool(8), stmfadm(8), and — worse — into single-string remote commands passed to ssh(1), where they are re-parsed by a second shell. A value containing a space, a semicolon, a backquote, a $, a pipe, a redirection or a newline would run as a separate privileged command.

The two validators are the choke point for that risk. They are allow-lists, not sanitizers: nothing is stripped or quoted, the value is either accepted unchanged or rejected. Consumers call them before the value reaches a command line, and treat rejection as fatal for that item — see create_iscsi_lun.sh(8) (zone name into stmfadm/zfs), create_zone_pool.sh(8) (every node name from config/nodes), and manage_zone.sh(8) (remote dataset names before zfs set over ssh).

validate_name

Validates an identifier: a zone, a node, a host or a user name. kind is a noun used only in the diagnostic and defaults to name.

Accepted:

^[a-zA-Z0-9][a-zA-Z0-9._-]*$

that is, one leading alphanumeric followed by any number of alphanumerics, dots, underscores and hyphens. The leading-alphanumeric requirement rejects a value that begins with a hyphen and would otherwise be read as an option by the command it is passed to, and rejects a leading dot.

Rejected: the empty string, and any value containing anything else — space, tab, newline, ;, $, backquote, |, <, >, &, backslash, single or double quote, slash, colon, at sign, glob characters. On rejection it reports through error() (so the failure reaches syslog and the oc-alert mail, see oc_log(3)) with either

validate_name: empty <kind>

or

validate_name: invalid <kind> '<name>' (allowed: ...)

validate_dataset

Validates a ZFS dataset name. Identical to validate_name() except that the forward slash is also accepted, since a dataset name is a path:

^[a-zA-Z0-9][a-zA-Z0-9._/-]*$

The leading character still must be alphanumeric, so an absolute path or a -o style argument cannot pass. There is no kind argument; diagnostics name the function:

validate_dataset: empty dataset
validate_dataset: invalid dataset '<ds>' (allowed: ...)

Note that @ is not accepted, so a snapshot name cannot be validated with this function; callers validate the dataset part and compose the @snapname suffix themselves.

is_in_exact_list

Tests whether needle equals any of the remaining arguments, character for character. Used to gate code paths on astring-list SMF properties, for instance config/monitor_exclude_pools in sys_monitor(8) and config/monitor_exclude_zones in zones_srv_monitor.sh(8), and to de-duplicate tuples in autocleansnap(8).

The comparison uses the literal [[ == ]] form deliberately, not [[ =~ ]]: an entry that happens to contain a regular-expression metacharacter, such as a pool or zone name with a dot in it, must match by character and must not act as a wildcard against unrelated names. An empty list — the usual case, when the SMF knob is unset — always yields false, so callers degrade safely to “nothing is excluded”.

is_snapexists

Tests whether snapshot exists, by running zfs list on it with both standard output and standard error discarded. It is a thin, unprivileged existence probe; autosnap(8) uses it to skip a snapshot it would otherwise try to create twice within one tick. It does not validate its argument, and it does not distinguish “does not exist” from “cannot be read”.

RETURN VALUES

None of these functions calls exit; all four are predicates and are meant to be tested. The idiomatic forms are validate_name "${x}" zone || return 1 and is_in_exact_list "${x}" "${list[@]}" && continue.

validate_name()

0 if name matches the accepted class; 1 if it is empty or contains any other character. Reports through error() before returning 1.

validate_dataset()

0 if dataset matches the accepted class; 1 otherwise, after an error().

is_in_exact_list()

0 on an exact match, 1 if there is no match or the list is empty. Silent in both cases.

is_snapexists()

The status of zfs list: 0 if the snapshot (or any dataset with that name) exists and is visible to the caller, non-zero otherwise. Silent.

ENVIRONMENT

PATH

is_snapexists() requires zfs(8). The three other functions are pure shell and rely on nothing external, except that their diagnostics go through error(), which uses logger(1) and mailx(1).

EXAMPLES

Example 1: validating operator input, fatally

zone=$2
validate_name "${zone}" "zone" || exit 1
${PFEXEC} zonecfg -z "${zone}" info

Example 2: validating configuration read from SMF

for node in ${nodes[@]}; do
    validate_name "${node}" "node (from SMF config/nodes)" || exit 2
done

Example 3: exclusion list and snapshot skip

exclude_zones=($(svcprop -p config/monitor_exclude_zones ${OC_SMF}))
for zone in ${host_zones[@]}; do
    is_in_exact_list "${zone}" "${exclude_zones[@]}" && continue
    is_snapexists "${zone}@daily-$(date +%y-%W-%d)" && continue
done

SECURITY

These validators are the suite's injection boundary for values that reach privileged local commands and, over ssh(1), a remote shell. Two limitations must be understood.

First, they validate characters, not authorization: an accepted zone or dataset name is well-formed, not necessarily one the caller should be allowed to touch. Authorization comes from RBAC, through /etc/security/exec_attr.d/omnicube and /etc/security/prof_attr.d/omnicube.

Second, a validated value is still a string being pasted into a command line. Callers keep quoting it, and the accepted class is deliberately narrow enough that word splitting and glob expansion cannot change its meaning even where an older call site left it unquoted.

SEE ALSO

omnicube_utils(3), oc_log(3), oc_lock(3), oc_runlevel(3), oc_ssh(3), oc_policy(3), create_iscsi_lun.sh(8), create_zone_pool.sh(8), manage_zone.sh(8), autosnap(8), omnicube(7).

NOTES

The accepted classes are narrower than what ZFS and zones actually permit: zfs(8) allows : and % in dataset names, and a colon is common in third-party naming schemes. Such a name cannot be used with this suite. That is intentional — the class was chosen to be safe in a remote shell command line, not to be complete.

ssh_reachable() applies its own, separate pattern to an "[user@]host" target rather than calling validate_name(); see oc_ssh(3).

Rejection is reported with error(), which sends alert mail. A script that validates a long list of values from a misconfigured SMF property produces one alert per distinct bad value, subject to the mail throttle described in oc_log(3).

man3/oc_validate.3generated 2026-09-02 05:17 CEST