OmniCube Reference Manualomnicube_utils(3)

omnicube_utils(3)

Library Functions · OmniCube · August 10, 2026

NAME

omnicube_utils - shared shell function library for OmniCube commands

SYNOPSIS

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

DESCRIPTION

utils.sh is the common shell library sourced by nearly every OmniCube command: autosnap(8), autosync(8), autocleansnap(8), manage_zone.sh(8), sync_pool.sh(8), pool_monitor.sh(8), sys_monitor(8), zone_monitor.sh(8), zones_srv_monitor.sh(8), isolate_node.sh(8), create_zone_pool.sh(8), create_zone_config.sh(8), create_iscsi_lun.sh(8) and the other members of the suite. It provides logging with syslog and throttled alert mail, a mkdir-based single-instance lock discipline, a run-level guard, argument validation for values that reach privileged command lines, an SSH pre-flight probe, and backup-policy resolution.

The library must be sourced and never executed: it tests ${BASH_SOURCE[0]} against ${0} and, when they are equal, prints utils.sh must be sourced, not executed on standard error and exits 1.

Source-time actions

Sourcing the library is not side-effect free. In order, it:

1.

Composes OC_SMF from OC_SMF_INSTANCE. A caller that wants configuration from a non-default SMF instance (for example autosync -i NAME for parallel runs against different backup destinations) must set OC_SMF_INSTANCE before sourcing; the instance name is baked into OC_SMF, PROPPREFIX, logtag and any per-instance lock path at source time.

2.

Reads the ZFS user-property prefix with svcprop -p config/site ${OC_SMF}. If the property is missing or empty the library prints PROPPREFIX not initialized on standard error and exits 78. This is the only hard failure at source time besides the execute guard.

3.

Derives script and logtag from $0.

4.

Reads config/lock_group and creates or normalizes ${LOCK_BASE} (mode 1775, group ${LOCK_GROUP}) through _ensure_shared_dir(), because /var/run is tmpfs on illumos and is wiped at every boot. See oc_lock(3).

5.

Reads config/nodes and config/mail_domain, enumerates the locally visible zones with zoneadm list -ni, and records the hostname.

6.

Creates the mail-throttle marker directories: the shared base ${MAIL_THROTTLE_BASE} at mode 1777 and the per-user directory ${MAIL_THROTTLE_DIR} at mode 0700; reads config/mail_throttle_window. See oc_log(3).

7.

Defines the SSH option strings and the associative array _SSH_PROBE_CACHE used to memoize probe results.

8.

Sets PFEXEC from ${EUID}.

Every directory creation and every chgrp(1)/chmod(1) normalization is best-effort and silent: failures are discarded so that sourcing the library never aborts a caller running under set -e. Both directory helpers refuse to operate on a path that is a symbolic link, so that a link planted by an unprivileged user on tmpfs cannot be followed by a later root invocation.

Reading configuration

Every SMF property this suite reads goes through oc_svcprop(), and every property it reads is declared in the service manifest, even when its default is "unset". The two halves are one convention.

Declaring a property gives it a type, so an operator can write

svccfg -s ${OC_SMF} setprop config/vnc_bind = 127.0.0.1

without repeating astring:, and svccfg listprop config/* shows the full set of knobs rather than only the ones somebody has already changed. A property that is meant to default to "unset" is declared with no value - <property name='x' type='astring'/>- never with <propval value=''/>, because svcprop(1) prints an empty astring value as a literal pair of double quotes. A <propval> with an empty value therefore hands every reader the two-character string instead of nothing, which [ -n ... ] reads as set. In zone-mgt that would invert the meaning of the config/nfs_opts test.

oc_svcprop() closes the same gap from the reading side, for the property an operator clears by hand with setprop config/x = \\: it turns that back into an empty string, so a cleared property behaves exactly like one that was never set. Multi-value properties pass through untouched, so arr=($(oc_svcpropconfig/nodes)) keeps working. It is defined above the source-time reads in utils.sh because those run while the file is being sourced.

When adding a property: declare it in /lib/svc/manifest/omnicube/sysadm.xml, document it in the SMF PROPERTIES section of omnicube(7), and read it with oc_svcprop().

Global variables

The following variables are set at source time and are part of the interface; consumers read them directly.

OC_SMF

svc:/omnicube/sysadm:${OC_SMF_INSTANCE:-default}.

OC_SMF_INSTANCE

Not set by the library. Read (if the caller exported it) to select the SMF instance; unset means :default.

PROPPREFIX

From SMF property config/site. Used as the prefix of the ZFS user properties the suite reads and writes (for example ${PROPPREFIX}:is_locked, ${PROPPREFIX}:snappolicy). Mandatory.

script

basename $0.

logtag

${PROPPREFIX}${script/.*/}, i.e. the site prefix followed by the script name with everything from the first dot removed. This is the tag passed to logger(1) and embedded in the subject of every alert mail.

LOCK_BASE

/var/run/omnicube, hard-coded. Parent of all lock directories and of the mail-throttle tree.

LOCK_GROUP

From SMF property config/lock_group, accepted only when it matches ^[a-zA-Z0-9_-]+$; otherwise sysadmin. Group owner of ${LOCK_BASE}.

isolate_lock

${LOCK_BASE}/isolate_node.lock, the node isolation marker maintained by isolate_node.sh(8) and tested by the monitors.

nodes

Array, from SMF property config/nodes (an astring list of cluster node names).

host_zones

Array, from zoneadm list -ni at source time: the zones installed on this host.

curr_host

hostname.

MAIL_DOMAIN

From SMF property config/mail_domain. Used to build the envelope sender ${HOSTNAME}@${MAIL_DOMAIN}.

MAIL_THROTTLE_BASE

${LOCK_BASE}/mail_throttle.

MAIL_THROTTLE_DIR

${MAIL_THROTTLE_BASE}/<user>, where <user> is id -run or the literal unknown when that fails. Throttling is therefore per uid.

MAIL_THROTTLE_WINDOW

From SMF property config/mail_throttle_window, in seconds; accepted only when it matches ^[0-9]+$; otherwise 3600.

_SSH_OPTS

-o ConnectTimeout=5 -o ConnectionAttempts=5 -o BatchMode=yes -o StrictHostKeyChecking=yes.

_SSH_CMD

ssh ${_SSH_OPTS}.

_SCP_CMD

scp -q ${_SSH_OPTS}.

_SSH_PROBE_OPTS

-n -o ConnectTimeout=5 -o ConnectionAttempts=1 -o BatchMode=yes -o StrictHostKeyChecking=yes, used only by the reachability probe. See oc_ssh(3).

PFEXEC

Empty when ${EUID} is 0, otherwise pfexec. It must be used unquoted so that the empty value disappears from the command line instead of being passed as an empty first argument: ${PFEXEC} zlogin "${zone}" 'svcs -xv'. The effective uid, not the real uid, is the correct test because the exec_attr(5) entries grant these tools uid=0 or euid=0.

_SSH_PROBE_CACHE is an associative array holding per-process probe verdicts and is private to oc_ssh(3).

Function index

info(),warning(),error()

Log to stdout/stderr and syslog; warning and error also send throttled mail. See oc_log(3).

_send_mail(),_should_send_mail()

Mail delivery and the throttle decision. See oc_log(3).

acquire_lock_or_exit(),_ensure_shared_dir()

Single-instance locking and shared-directory normalization. See oc_lock(3).

_current_runlevel(),is_shutting_down(),abort_if_shutting_down()

Run-level guard. See oc_runlevel(3).

validate_name(),validate_dataset(),is_in_exact_list(),is_snapexists()

Argument validation and list/snapshot predicates. See oc_validate(3).

ssh_reachable(),require_ssh(),ssh_probe_reset()

SSH pre-flight probe and its cache. See oc_ssh(3).

oc_svcprop()

Read one SMF property, normalizing SMF's spelling of "empty". See Reading configuration above.

kill_zone_console(),_zone_console_pids()

Stop a zone's VNC console relay and wait for it, so its pool can be exported. See oc_console(3).

get_snap_policy_path(),_bkp_priv()

Backup policy resolution and the remote privilege prefix. See oc_policy(3).

Names beginning with an underscore are internal helpers; they are documented because their behaviour is visible in logs and in policy files, not because they are meant to be called from new code.

Portability

The library is bash code and is sourced by #!/usr/bin/bash scripts. It depends on bash features that ksh93 either lacks or interprets differently: ${BASH_SOURCE[0]} for the execute guard, ${HOSTNAME} in the mail sender, declare -A for the probe cache, [[ ... =~ ... ]] for every validation pattern, ${script/.*/} pattern substitution for logtag, and name=(...) array assignment for nodes, host_zones and MAIL_DOMAIN. Under ksh93 the same array syntax creates a compound variable, and $0 inside a function name { ... } block is the function name rather than the script, which would corrupt script and logtag. Members of the suite that are not bash, such as qemu-monitor-command(8) (ksh) and logadm(8) (sh), therefore do not source this library.

Two functions carry a calling-convention restriction that follows from being shell state or from calling exit: ssh_reachable() must be called as a statement and not inside $(), where cache updates would be discarded with the subshell, and abort_if_shutting_down() must not be called inside $() or a pipeline, where exit would only leave the subshell.

EXIT STATUS

Sourcing the library succeeds silently, or terminates the caller with:

1

The file was executed instead of sourced.

78

PROPPREFIX is not initialized, i.e. config/site is missing on ${OC_SMF}. The value follows the EX_CONFIG convention of <sysexits.h>.

FILES

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

The library itself.

/var/run/omnicube

${LOCK_BASE}; lock directories, mode 1775, group ${LOCK_GROUP}.

/var/run/omnicube/isolate_node.lock

Node isolation marker.

/var/run/omnicube/mail_throttle

Mail throttle base, mode 1777.

/var/run/omnicube/mail_throttle/<user>

Per-user marker directory, mode 0700.

/var/opt/omnicube/backup/policies/<policy>.conf

Site snapshot policies.

/opt/omnicube/backup/policies/default.conf

Packaged fallback policy.

/etc/nologin

Presence means a shutdown is in progress.

ENVIRONMENT

OC_SMF_INSTANCE

Selects the SMF instance whose properties are read. Must be set before the library is sourced. Unset means default.

OC_IGNORE_RUNLEVEL

When non-empty, abort_if_shutting_down() returns instead of exiting. See oc_runlevel(3).

USER

Used by _send_mail() as the default recipient; set to system when empty.

HOSTNAME

Used in the envelope sender address.

PATH

Must reach svcprop(1), zoneadm(8), zfs(8), logger(1), mailx(1), digest(1), who(1), ssh(1) and pfexec(1).

EXAMPLES

Example 1: standard prologue of a cron or SMF job

#!/usr/bin/bash
amp;. /opt/omnicube/lib/common/utils.sh
LOCK_DIR=${LOCK_BASE}/${logtag}.myjob.lock
acquire_lock_or_exit "${LOCK_DIR}"
trap '[[ -d ${LOCK_DIR} ]] && rmdir ${LOCK_DIR} 2>/dev/null' EXIT HUP INT TERM
abort_if_shutting_down
info "starting"

Example 2: reading configuration from a non-default instance

OC_SMF_INSTANCE=offsite
amp;. /opt/omnicube/lib/common/utils.sh
info "using ${OC_SMF} with prefix ${PROPPREFIX}"

Example 3: a privileged local command and a remote one

${PFEXEC} zfs set ${PROPPREFIX}:is_locked=true "${pool}"
${_SSH_CMD} "${node}" "pfexec zpool import ${pool}"

SEE ALSO

oc_log(3), oc_lock(3), oc_runlevel(3), oc_validate(3), oc_ssh(3), oc_policy(3), default.conf(5), autosnap(8), autosync(8), manage_zone.sh(8), sync_pool.sh(8), isolate_node.sh(8), omnicube(7).

NOTES

host_zones and nodes are snapshots taken at source time; a zone installed or a node added while a long-running monitor is in its loop is not seen until the next invocation.

The library reads SMF properties with svcprop(1) at source time only. Changing config/site, config/nodes, config/lock_group or config/mail_throttle_window has no effect on processes that are already running.

Sourcing is deliberately tolerant: only a missing config/site aborts. A failure to create ${LOCK_BASE} is not reported at source time; it surfaces later as a lock acquisition failure from acquire_lock_or_exit().

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