1eda14cbcSMatt Macy#!/bin/sh
2e92ffd9bSMartin Matuska# shellcheck disable=SC2154,SC3043
3eda14cbcSMatt Macy# zed-functions.sh
4eda14cbcSMatt Macy#
5eda14cbcSMatt Macy# ZED helper functions for use in ZEDLETs
6eda14cbcSMatt Macy
7eda14cbcSMatt Macy
8eda14cbcSMatt Macy# Variable Defaults
9eda14cbcSMatt Macy#
10eda14cbcSMatt Macy: "${ZED_LOCKDIR:="/var/lock"}"
11eda14cbcSMatt Macy: "${ZED_NOTIFY_INTERVAL_SECS:=3600}"
12eda14cbcSMatt Macy: "${ZED_NOTIFY_VERBOSE:=0}"
13eda14cbcSMatt Macy: "${ZED_RUNDIR:="/var/run"}"
14eda14cbcSMatt Macy: "${ZED_SYSLOG_PRIORITY:="daemon.notice"}"
15eda14cbcSMatt Macy: "${ZED_SYSLOG_TAG:="zed"}"
16eda14cbcSMatt Macy
17eda14cbcSMatt MacyZED_FLOCK_FD=8
18eda14cbcSMatt Macy
19eda14cbcSMatt Macy
20eda14cbcSMatt Macy# zed_check_cmd (cmd, ...)
21eda14cbcSMatt Macy#
22eda14cbcSMatt Macy# For each argument given, search PATH for the executable command [cmd].
23eda14cbcSMatt Macy# Log a message if [cmd] is not found.
24eda14cbcSMatt Macy#
25eda14cbcSMatt Macy# Arguments
26eda14cbcSMatt Macy#   cmd: name of executable command for which to search
27eda14cbcSMatt Macy#
28eda14cbcSMatt Macy# Return
29eda14cbcSMatt Macy#   0 if all commands are found in PATH and are executable
30eda14cbcSMatt Macy#   n for a count of the command executables that are not found
31eda14cbcSMatt Macy#
32eda14cbcSMatt Macyzed_check_cmd()
33eda14cbcSMatt Macy{
34eda14cbcSMatt Macy    local cmd
35eda14cbcSMatt Macy    local rv=0
36eda14cbcSMatt Macy
37eda14cbcSMatt Macy    for cmd; do
38eda14cbcSMatt Macy        if ! command -v "${cmd}" >/dev/null 2>&1; then
39eda14cbcSMatt Macy            zed_log_err "\"${cmd}\" not installed"
40eda14cbcSMatt Macy            rv=$((rv + 1))
41eda14cbcSMatt Macy        fi
42eda14cbcSMatt Macy    done
43eda14cbcSMatt Macy    return "${rv}"
44eda14cbcSMatt Macy}
45eda14cbcSMatt Macy
46eda14cbcSMatt Macy
47eda14cbcSMatt Macy# zed_log_msg (msg, ...)
48eda14cbcSMatt Macy#
49eda14cbcSMatt Macy# Write all argument strings to the system log.
50eda14cbcSMatt Macy#
51eda14cbcSMatt Macy# Globals
52eda14cbcSMatt Macy#   ZED_SYSLOG_PRIORITY
53eda14cbcSMatt Macy#   ZED_SYSLOG_TAG
54eda14cbcSMatt Macy#
55eda14cbcSMatt Macy# Return
56eda14cbcSMatt Macy#   nothing
57eda14cbcSMatt Macy#
58eda14cbcSMatt Macyzed_log_msg()
59eda14cbcSMatt Macy{
60eda14cbcSMatt Macy    logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "$@"
61eda14cbcSMatt Macy}
62eda14cbcSMatt Macy
63eda14cbcSMatt Macy
64eda14cbcSMatt Macy# zed_log_err (msg, ...)
65eda14cbcSMatt Macy#
66eda14cbcSMatt Macy# Write an error message to the system log.  This message will contain the
67eda14cbcSMatt Macy# script name, EID, and all argument strings.
68eda14cbcSMatt Macy#
69eda14cbcSMatt Macy# Globals
70eda14cbcSMatt Macy#   ZED_SYSLOG_PRIORITY
71eda14cbcSMatt Macy#   ZED_SYSLOG_TAG
72eda14cbcSMatt Macy#   ZEVENT_EID
73eda14cbcSMatt Macy#
74eda14cbcSMatt Macy# Return
75eda14cbcSMatt Macy#   nothing
76eda14cbcSMatt Macy#
77eda14cbcSMatt Macyzed_log_err()
78eda14cbcSMatt Macy{
79716fd348SMartin Matuska    zed_log_msg "error: ${0##*/}:""${ZEVENT_EID:+" eid=${ZEVENT_EID}:"}" "$@"
80eda14cbcSMatt Macy}
81eda14cbcSMatt Macy
82eda14cbcSMatt Macy
83eda14cbcSMatt Macy# zed_lock (lockfile, [fd])
84eda14cbcSMatt Macy#
85eda14cbcSMatt Macy# Obtain an exclusive (write) lock on [lockfile].  If the lock cannot be
86eda14cbcSMatt Macy# immediately acquired, wait until it becomes available.
87eda14cbcSMatt Macy#
88eda14cbcSMatt Macy# Every zed_lock() must be paired with a corresponding zed_unlock().
89eda14cbcSMatt Macy#
90eda14cbcSMatt Macy# By default, flock-style locks associate the lockfile with file descriptor 8.
91eda14cbcSMatt Macy# The bash manpage warns that file descriptors >9 should be used with care as
92eda14cbcSMatt Macy# they may conflict with file descriptors used internally by the shell.  File
93eda14cbcSMatt Macy# descriptor 9 is reserved for zed_rate_limit().  If concurrent locks are held
94eda14cbcSMatt Macy# within the same process, they must use different file descriptors (preferably
95eda14cbcSMatt Macy# decrementing from 8); otherwise, obtaining a new lock with a given file
96eda14cbcSMatt Macy# descriptor will release the previous lock associated with that descriptor.
97eda14cbcSMatt Macy#
98eda14cbcSMatt Macy# Arguments
99eda14cbcSMatt Macy#   lockfile: pathname of the lock file; the lock will be stored in
100eda14cbcSMatt Macy#     ZED_LOCKDIR unless the pathname contains a "/".
101eda14cbcSMatt Macy#   fd: integer for the file descriptor used by flock (OPTIONAL unless holding
102eda14cbcSMatt Macy#     concurrent locks)
103eda14cbcSMatt Macy#
104eda14cbcSMatt Macy# Globals
105eda14cbcSMatt Macy#   ZED_FLOCK_FD
106eda14cbcSMatt Macy#   ZED_LOCKDIR
107eda14cbcSMatt Macy#
108eda14cbcSMatt Macy# Return
109eda14cbcSMatt Macy#   nothing
110eda14cbcSMatt Macy#
111eda14cbcSMatt Macyzed_lock()
112eda14cbcSMatt Macy{
113eda14cbcSMatt Macy    local lockfile="$1"
114eda14cbcSMatt Macy    local fd="${2:-${ZED_FLOCK_FD}}"
115eda14cbcSMatt Macy    local umask_bak
116eda14cbcSMatt Macy    local err
117eda14cbcSMatt Macy
118eda14cbcSMatt Macy    [ -n "${lockfile}" ] || return
119eda14cbcSMatt Macy    if ! expr "${lockfile}" : '.*/' >/dev/null 2>&1; then
120eda14cbcSMatt Macy        lockfile="${ZED_LOCKDIR}/${lockfile}"
121eda14cbcSMatt Macy    fi
122eda14cbcSMatt Macy
123eda14cbcSMatt Macy    umask_bak="$(umask)"
124eda14cbcSMatt Macy    umask 077
125eda14cbcSMatt Macy
126eda14cbcSMatt Macy    # Obtain a lock on the file bound to the given file descriptor.
127eda14cbcSMatt Macy    #
1283ff01b23SMartin Matuska    eval "exec ${fd}>> '${lockfile}'"
12916038816SMartin Matuska    if ! err="$(flock --exclusive "${fd}" 2>&1)"; then
130eda14cbcSMatt Macy        zed_log_err "failed to lock \"${lockfile}\": ${err}"
131eda14cbcSMatt Macy    fi
132eda14cbcSMatt Macy
133eda14cbcSMatt Macy    umask "${umask_bak}"
134eda14cbcSMatt Macy}
135eda14cbcSMatt Macy
136eda14cbcSMatt Macy
137eda14cbcSMatt Macy# zed_unlock (lockfile, [fd])
138eda14cbcSMatt Macy#
139eda14cbcSMatt Macy# Release the lock on [lockfile].
140eda14cbcSMatt Macy#
141eda14cbcSMatt Macy# Arguments
142eda14cbcSMatt Macy#   lockfile: pathname of the lock file
143eda14cbcSMatt Macy#   fd: integer for the file descriptor used by flock (must match the file
144eda14cbcSMatt Macy#     descriptor passed to the zed_lock function call)
145eda14cbcSMatt Macy#
146eda14cbcSMatt Macy# Globals
147eda14cbcSMatt Macy#   ZED_FLOCK_FD
148eda14cbcSMatt Macy#   ZED_LOCKDIR
149eda14cbcSMatt Macy#
150eda14cbcSMatt Macy# Return
151eda14cbcSMatt Macy#   nothing
152eda14cbcSMatt Macy#
153eda14cbcSMatt Macyzed_unlock()
154eda14cbcSMatt Macy{
155eda14cbcSMatt Macy    local lockfile="$1"
156eda14cbcSMatt Macy    local fd="${2:-${ZED_FLOCK_FD}}"
157eda14cbcSMatt Macy    local err
158eda14cbcSMatt Macy
159eda14cbcSMatt Macy    [ -n "${lockfile}" ] || return
160eda14cbcSMatt Macy    if ! expr "${lockfile}" : '.*/' >/dev/null 2>&1; then
161eda14cbcSMatt Macy        lockfile="${ZED_LOCKDIR}/${lockfile}"
162eda14cbcSMatt Macy    fi
163eda14cbcSMatt Macy
164eda14cbcSMatt Macy    # Release the lock and close the file descriptor.
16516038816SMartin Matuska    if ! err="$(flock --unlock "${fd}" 2>&1)"; then
166eda14cbcSMatt Macy        zed_log_err "failed to unlock \"${lockfile}\": ${err}"
167eda14cbcSMatt Macy    fi
168eda14cbcSMatt Macy    eval "exec ${fd}>&-"
169eda14cbcSMatt Macy}
170eda14cbcSMatt Macy
171eda14cbcSMatt Macy
172eda14cbcSMatt Macy# zed_notify (subject, pathname)
173eda14cbcSMatt Macy#
174eda14cbcSMatt Macy# Send a notification via all available methods.
175eda14cbcSMatt Macy#
176eda14cbcSMatt Macy# Arguments
177eda14cbcSMatt Macy#   subject: notification subject
178eda14cbcSMatt Macy#   pathname: pathname containing the notification message (OPTIONAL)
179eda14cbcSMatt Macy#
180eda14cbcSMatt Macy# Return
181eda14cbcSMatt Macy#   0: notification succeeded via at least one method
182eda14cbcSMatt Macy#   1: notification failed
183eda14cbcSMatt Macy#   2: no notification methods configured
184eda14cbcSMatt Macy#
185eda14cbcSMatt Macyzed_notify()
186eda14cbcSMatt Macy{
187eda14cbcSMatt Macy    local subject="$1"
188eda14cbcSMatt Macy    local pathname="$2"
189eda14cbcSMatt Macy    local num_success=0
190eda14cbcSMatt Macy    local num_failure=0
191eda14cbcSMatt Macy
192eda14cbcSMatt Macy    zed_notify_email "${subject}" "${pathname}"; rv=$?
193eda14cbcSMatt Macy    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
194eda14cbcSMatt Macy    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
195eda14cbcSMatt Macy
196eda14cbcSMatt Macy    zed_notify_pushbullet "${subject}" "${pathname}"; rv=$?
197eda14cbcSMatt Macy    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
198eda14cbcSMatt Macy    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
199eda14cbcSMatt Macy
200eda14cbcSMatt Macy    zed_notify_slack_webhook "${subject}" "${pathname}"; rv=$?
201eda14cbcSMatt Macy    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
202eda14cbcSMatt Macy    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
203eda14cbcSMatt Macy
20416038816SMartin Matuska    zed_notify_pushover "${subject}" "${pathname}"; rv=$?
20516038816SMartin Matuska    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
20616038816SMartin Matuska    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
20716038816SMartin Matuska
2083494f7c0SMartin Matuska    zed_notify_ntfy "${subject}" "${pathname}"; rv=$?
2093494f7c0SMartin Matuska    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
2103494f7c0SMartin Matuska    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
2113494f7c0SMartin Matuska
212*f552d7adSMartin Matuska    zed_notify_gotify "${subject}" "${pathname}"; rv=$?
213*f552d7adSMartin Matuska    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
214*f552d7adSMartin Matuska    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
215*f552d7adSMartin Matuska
216eda14cbcSMatt Macy    [ "${num_success}" -gt 0 ] && return 0
217eda14cbcSMatt Macy    [ "${num_failure}" -gt 0 ] && return 1
218eda14cbcSMatt Macy    return 2
219eda14cbcSMatt Macy}
220eda14cbcSMatt Macy
221eda14cbcSMatt Macy
222eda14cbcSMatt Macy# zed_notify_email (subject, pathname)
223eda14cbcSMatt Macy#
224eda14cbcSMatt Macy# Send a notification via email to the address specified by ZED_EMAIL_ADDR.
225eda14cbcSMatt Macy#
226eda14cbcSMatt Macy# Requires the mail executable to be installed in the standard PATH, or
227eda14cbcSMatt Macy# ZED_EMAIL_PROG to be defined with the pathname of an executable capable of
228eda14cbcSMatt Macy# reading a message body from stdin.
229eda14cbcSMatt Macy#
230eda14cbcSMatt Macy# Command-line options to the mail executable can be specified in
231eda14cbcSMatt Macy# ZED_EMAIL_OPTS.  This undergoes the following keyword substitutions:
232eda14cbcSMatt Macy# - @ADDRESS@ is replaced with the space-delimited recipient email address(es)
233eda14cbcSMatt Macy# - @SUBJECT@ is replaced with the notification subject
234e3aa18adSMartin Matuska#   If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
235e3aa18adSMartin Matuska#
236eda14cbcSMatt Macy#
237eda14cbcSMatt Macy# Arguments
238eda14cbcSMatt Macy#   subject: notification subject
239eda14cbcSMatt Macy#   pathname: pathname containing the notification message (OPTIONAL)
240eda14cbcSMatt Macy#
241eda14cbcSMatt Macy# Globals
242eda14cbcSMatt Macy#   ZED_EMAIL_PROG
243eda14cbcSMatt Macy#   ZED_EMAIL_OPTS
244eda14cbcSMatt Macy#   ZED_EMAIL_ADDR
245eda14cbcSMatt Macy#
246eda14cbcSMatt Macy# Return
247eda14cbcSMatt Macy#   0: notification sent
248eda14cbcSMatt Macy#   1: notification failed
249eda14cbcSMatt Macy#   2: not configured
250eda14cbcSMatt Macy#
251eda14cbcSMatt Macyzed_notify_email()
252eda14cbcSMatt Macy{
253e3aa18adSMartin Matuska    local subject="${1:-"ZED notification"}"
254eda14cbcSMatt Macy    local pathname="${2:-"/dev/null"}"
255eda14cbcSMatt Macy
256eda14cbcSMatt Macy    : "${ZED_EMAIL_PROG:="mail"}"
257eda14cbcSMatt Macy    : "${ZED_EMAIL_OPTS:="-s '@SUBJECT@' @ADDRESS@"}"
258eda14cbcSMatt Macy
259eda14cbcSMatt Macy    # For backward compatibility with ZED_EMAIL.
260eda14cbcSMatt Macy    if [ -n "${ZED_EMAIL}" ] && [ -z "${ZED_EMAIL_ADDR}" ]; then
261eda14cbcSMatt Macy        ZED_EMAIL_ADDR="${ZED_EMAIL}"
262eda14cbcSMatt Macy    fi
263eda14cbcSMatt Macy    [ -n "${ZED_EMAIL_ADDR}" ] || return 2
264eda14cbcSMatt Macy
265eda14cbcSMatt Macy    zed_check_cmd "${ZED_EMAIL_PROG}" || return 1
266eda14cbcSMatt Macy
267eda14cbcSMatt Macy    [ -n "${subject}" ] || return 1
268eda14cbcSMatt Macy    if [ ! -r "${pathname}" ]; then
269eda14cbcSMatt Macy        zed_log_err \
270dae17134SMartin Matuska                "${ZED_EMAIL_PROG##*/} cannot read \"${pathname}\""
271eda14cbcSMatt Macy        return 1
272eda14cbcSMatt Macy    fi
273eda14cbcSMatt Macy
274e3aa18adSMartin Matuska    # construct cmdline options
275e3aa18adSMartin Matuska    ZED_EMAIL_OPTS_PARSED="$(echo "${ZED_EMAIL_OPTS}" \
276eda14cbcSMatt Macy        | sed   -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \
277eda14cbcSMatt Macy                -e "s/@SUBJECT@/${subject}/g")"
278eda14cbcSMatt Macy
279e3aa18adSMartin Matuska    # pipe message to email prog
280e92ffd9bSMartin Matuska    # shellcheck disable=SC2086,SC2248
281e3aa18adSMartin Matuska    {
282e3aa18adSMartin Matuska        # no subject passed as option?
283e3aa18adSMartin Matuska        if [ "${ZED_EMAIL_OPTS%@SUBJECT@*}" = "${ZED_EMAIL_OPTS}" ] ; then
284e3aa18adSMartin Matuska            # inject subject header
285e3aa18adSMartin Matuska            printf "Subject: %s\n" "${subject}"
286e3aa18adSMartin Matuska        fi
287e3aa18adSMartin Matuska        # output message
288e3aa18adSMartin Matuska        cat "${pathname}"
289e3aa18adSMartin Matuska    } |
290e3aa18adSMartin Matuska    eval ${ZED_EMAIL_PROG} ${ZED_EMAIL_OPTS_PARSED} >/dev/null 2>&1
291eda14cbcSMatt Macy    rv=$?
292eda14cbcSMatt Macy    if [ "${rv}" -ne 0 ]; then
293dae17134SMartin Matuska        zed_log_err "${ZED_EMAIL_PROG##*/} exit=${rv}"
294eda14cbcSMatt Macy        return 1
295eda14cbcSMatt Macy    fi
296eda14cbcSMatt Macy    return 0
297eda14cbcSMatt Macy}
298eda14cbcSMatt Macy
299eda14cbcSMatt Macy
300eda14cbcSMatt Macy# zed_notify_pushbullet (subject, pathname)
301eda14cbcSMatt Macy#
302eda14cbcSMatt Macy# Send a notification via Pushbullet <https://www.pushbullet.com/>.
303eda14cbcSMatt Macy# The access token (ZED_PUSHBULLET_ACCESS_TOKEN) identifies this client to the
304eda14cbcSMatt Macy# Pushbullet server.  The optional channel tag (ZED_PUSHBULLET_CHANNEL_TAG) is
305eda14cbcSMatt Macy# for pushing to notification feeds that can be subscribed to; if a channel is
306eda14cbcSMatt Macy# not defined, push notifications will instead be sent to all devices
307eda14cbcSMatt Macy# associated with the account specified by the access token.
308eda14cbcSMatt Macy#
309eda14cbcSMatt Macy# Requires awk, curl, and sed executables to be installed in the standard PATH.
310eda14cbcSMatt Macy#
311eda14cbcSMatt Macy# References
312eda14cbcSMatt Macy#   https://docs.pushbullet.com/
313eda14cbcSMatt Macy#   https://www.pushbullet.com/security
314eda14cbcSMatt Macy#
315eda14cbcSMatt Macy# Arguments
316eda14cbcSMatt Macy#   subject: notification subject
317eda14cbcSMatt Macy#   pathname: pathname containing the notification message (OPTIONAL)
318eda14cbcSMatt Macy#
319eda14cbcSMatt Macy# Globals
320eda14cbcSMatt Macy#   ZED_PUSHBULLET_ACCESS_TOKEN
321eda14cbcSMatt Macy#   ZED_PUSHBULLET_CHANNEL_TAG
322eda14cbcSMatt Macy#
323eda14cbcSMatt Macy# Return
324eda14cbcSMatt Macy#   0: notification sent
325eda14cbcSMatt Macy#   1: notification failed
326eda14cbcSMatt Macy#   2: not configured
327eda14cbcSMatt Macy#
328eda14cbcSMatt Macyzed_notify_pushbullet()
329eda14cbcSMatt Macy{
330eda14cbcSMatt Macy    local subject="$1"
331eda14cbcSMatt Macy    local pathname="${2:-"/dev/null"}"
332eda14cbcSMatt Macy    local msg_body
333eda14cbcSMatt Macy    local msg_tag
334eda14cbcSMatt Macy    local msg_json
335eda14cbcSMatt Macy    local msg_out
336eda14cbcSMatt Macy    local msg_err
337eda14cbcSMatt Macy    local url="https://api.pushbullet.com/v2/pushes"
338eda14cbcSMatt Macy
339eda14cbcSMatt Macy    [ -n "${ZED_PUSHBULLET_ACCESS_TOKEN}" ] || return 2
340eda14cbcSMatt Macy
341eda14cbcSMatt Macy    [ -n "${subject}" ] || return 1
342eda14cbcSMatt Macy    if [ ! -r "${pathname}" ]; then
343eda14cbcSMatt Macy        zed_log_err "pushbullet cannot read \"${pathname}\""
344eda14cbcSMatt Macy        return 1
345eda14cbcSMatt Macy    fi
346eda14cbcSMatt Macy
347eda14cbcSMatt Macy    zed_check_cmd "awk" "curl" "sed" || return 1
348eda14cbcSMatt Macy
349eda14cbcSMatt Macy    # Escape the following characters in the message body for JSON:
350eda14cbcSMatt Macy    # newline, backslash, double quote, horizontal tab, vertical tab,
351eda14cbcSMatt Macy    # and carriage return.
352eda14cbcSMatt Macy    #
353eda14cbcSMatt Macy    msg_body="$(awk '{ ORS="\\n" } { gsub(/\\/, "\\\\"); gsub(/"/, "\\\"");
354eda14cbcSMatt Macy        gsub(/\t/, "\\t"); gsub(/\f/, "\\f"); gsub(/\r/, "\\r"); print }' \
355eda14cbcSMatt Macy        "${pathname}")"
356eda14cbcSMatt Macy
357eda14cbcSMatt Macy    # Push to a channel if one is configured.
358eda14cbcSMatt Macy    #
359eda14cbcSMatt Macy    [ -n "${ZED_PUSHBULLET_CHANNEL_TAG}" ] && msg_tag="$(printf \
360eda14cbcSMatt Macy        '"channel_tag": "%s", ' "${ZED_PUSHBULLET_CHANNEL_TAG}")"
361eda14cbcSMatt Macy
362eda14cbcSMatt Macy    # Construct the JSON message for pushing a note.
363eda14cbcSMatt Macy    #
364eda14cbcSMatt Macy    msg_json="$(printf '{%s"type": "note", "title": "%s", "body": "%s"}' \
365eda14cbcSMatt Macy        "${msg_tag}" "${subject}" "${msg_body}")"
366eda14cbcSMatt Macy
367eda14cbcSMatt Macy    # Send the POST request and check for errors.
368eda14cbcSMatt Macy    #
369eda14cbcSMatt Macy    msg_out="$(curl -u "${ZED_PUSHBULLET_ACCESS_TOKEN}:" -X POST "${url}" \
370eda14cbcSMatt Macy        --header "Content-Type: application/json" --data-binary "${msg_json}" \
371eda14cbcSMatt Macy        2>/dev/null)"; rv=$?
372eda14cbcSMatt Macy    if [ "${rv}" -ne 0 ]; then
373eda14cbcSMatt Macy        zed_log_err "curl exit=${rv}"
374eda14cbcSMatt Macy        return 1
375eda14cbcSMatt Macy    fi
376eda14cbcSMatt Macy    msg_err="$(echo "${msg_out}" \
377eda14cbcSMatt Macy        | sed -n -e 's/.*"error" *:.*"message" *: *"\([^"]*\)".*/\1/p')"
378eda14cbcSMatt Macy    if [ -n "${msg_err}" ]; then
379eda14cbcSMatt Macy        zed_log_err "pushbullet \"${msg_err}"\"
380eda14cbcSMatt Macy        return 1
381eda14cbcSMatt Macy    fi
382eda14cbcSMatt Macy    return 0
383eda14cbcSMatt Macy}
384eda14cbcSMatt Macy
385eda14cbcSMatt Macy
386eda14cbcSMatt Macy# zed_notify_slack_webhook (subject, pathname)
387eda14cbcSMatt Macy#
388eda14cbcSMatt Macy# Notification via Slack Webhook <https://api.slack.com/incoming-webhooks>.
389eda14cbcSMatt Macy# The Webhook URL (ZED_SLACK_WEBHOOK_URL) identifies this client to the
390eda14cbcSMatt Macy# Slack channel.
391eda14cbcSMatt Macy#
392eda14cbcSMatt Macy# Requires awk, curl, and sed executables to be installed in the standard PATH.
393eda14cbcSMatt Macy#
394eda14cbcSMatt Macy# References
395eda14cbcSMatt Macy#   https://api.slack.com/incoming-webhooks
396eda14cbcSMatt Macy#
397eda14cbcSMatt Macy# Arguments
398eda14cbcSMatt Macy#   subject: notification subject
399eda14cbcSMatt Macy#   pathname: pathname containing the notification message (OPTIONAL)
400eda14cbcSMatt Macy#
401eda14cbcSMatt Macy# Globals
402eda14cbcSMatt Macy#   ZED_SLACK_WEBHOOK_URL
403eda14cbcSMatt Macy#
404eda14cbcSMatt Macy# Return
405eda14cbcSMatt Macy#   0: notification sent
406eda14cbcSMatt Macy#   1: notification failed
407eda14cbcSMatt Macy#   2: not configured
408eda14cbcSMatt Macy#
409eda14cbcSMatt Macyzed_notify_slack_webhook()
410eda14cbcSMatt Macy{
411eda14cbcSMatt Macy    [ -n "${ZED_SLACK_WEBHOOK_URL}" ] || return 2
412eda14cbcSMatt Macy
413eda14cbcSMatt Macy    local subject="$1"
414eda14cbcSMatt Macy    local pathname="${2:-"/dev/null"}"
415eda14cbcSMatt Macy    local msg_body
416eda14cbcSMatt Macy    local msg_tag
417eda14cbcSMatt Macy    local msg_json
418eda14cbcSMatt Macy    local msg_out
419eda14cbcSMatt Macy    local msg_err
420eda14cbcSMatt Macy    local url="${ZED_SLACK_WEBHOOK_URL}"
421eda14cbcSMatt Macy
422eda14cbcSMatt Macy    [ -n "${subject}" ] || return 1
423eda14cbcSMatt Macy    if [ ! -r "${pathname}" ]; then
424eda14cbcSMatt Macy        zed_log_err "slack webhook cannot read \"${pathname}\""
425eda14cbcSMatt Macy        return 1
426eda14cbcSMatt Macy    fi
427eda14cbcSMatt Macy
428eda14cbcSMatt Macy    zed_check_cmd "awk" "curl" "sed" || return 1
429eda14cbcSMatt Macy
430eda14cbcSMatt Macy    # Escape the following characters in the message body for JSON:
431eda14cbcSMatt Macy    # newline, backslash, double quote, horizontal tab, vertical tab,
432eda14cbcSMatt Macy    # and carriage return.
433eda14cbcSMatt Macy    #
434eda14cbcSMatt Macy    msg_body="$(awk '{ ORS="\\n" } { gsub(/\\/, "\\\\"); gsub(/"/, "\\\"");
435eda14cbcSMatt Macy        gsub(/\t/, "\\t"); gsub(/\f/, "\\f"); gsub(/\r/, "\\r"); print }' \
436eda14cbcSMatt Macy        "${pathname}")"
437eda14cbcSMatt Macy
438eda14cbcSMatt Macy    # Construct the JSON message for posting.
439eda14cbcSMatt Macy    #
440c03c5b1cSMartin Matuska    msg_json="$(printf '{"text": "*%s*\\n%s"}' "${subject}" "${msg_body}" )"
441eda14cbcSMatt Macy
442eda14cbcSMatt Macy    # Send the POST request and check for errors.
443eda14cbcSMatt Macy    #
444eda14cbcSMatt Macy    msg_out="$(curl -X POST "${url}" \
445eda14cbcSMatt Macy        --header "Content-Type: application/json" --data-binary "${msg_json}" \
446eda14cbcSMatt Macy        2>/dev/null)"; rv=$?
447eda14cbcSMatt Macy    if [ "${rv}" -ne 0 ]; then
448eda14cbcSMatt Macy        zed_log_err "curl exit=${rv}"
449eda14cbcSMatt Macy        return 1
450eda14cbcSMatt Macy    fi
451eda14cbcSMatt Macy    msg_err="$(echo "${msg_out}" \
452eda14cbcSMatt Macy        | sed -n -e 's/.*"error" *:.*"message" *: *"\([^"]*\)".*/\1/p')"
453eda14cbcSMatt Macy    if [ -n "${msg_err}" ]; then
454eda14cbcSMatt Macy        zed_log_err "slack webhook \"${msg_err}"\"
455eda14cbcSMatt Macy        return 1
456eda14cbcSMatt Macy    fi
457eda14cbcSMatt Macy    return 0
458eda14cbcSMatt Macy}
459eda14cbcSMatt Macy
46016038816SMartin Matuska# zed_notify_pushover (subject, pathname)
46116038816SMartin Matuska#
46216038816SMartin Matuska# Send a notification via Pushover <https://pushover.net/>.
46316038816SMartin Matuska# The access token (ZED_PUSHOVER_TOKEN) identifies this client to the
46416038816SMartin Matuska# Pushover server. The user token (ZED_PUSHOVER_USER) defines the user or
46516038816SMartin Matuska# group to which the notification will be sent.
46616038816SMartin Matuska#
46716038816SMartin Matuska# Requires curl and sed executables to be installed in the standard PATH.
46816038816SMartin Matuska#
46916038816SMartin Matuska# References
47016038816SMartin Matuska#   https://pushover.net/api
47116038816SMartin Matuska#
47216038816SMartin Matuska# Arguments
47316038816SMartin Matuska#   subject: notification subject
47416038816SMartin Matuska#   pathname: pathname containing the notification message (OPTIONAL)
47516038816SMartin Matuska#
47616038816SMartin Matuska# Globals
47716038816SMartin Matuska#   ZED_PUSHOVER_TOKEN
47816038816SMartin Matuska#   ZED_PUSHOVER_USER
47916038816SMartin Matuska#
48016038816SMartin Matuska# Return
48116038816SMartin Matuska#   0: notification sent
48216038816SMartin Matuska#   1: notification failed
48316038816SMartin Matuska#   2: not configured
48416038816SMartin Matuska#
48516038816SMartin Matuskazed_notify_pushover()
48616038816SMartin Matuska{
48716038816SMartin Matuska    local subject="$1"
48816038816SMartin Matuska    local pathname="${2:-"/dev/null"}"
48916038816SMartin Matuska    local msg_body
49016038816SMartin Matuska    local msg_out
49116038816SMartin Matuska    local msg_err
49216038816SMartin Matuska    local url="https://api.pushover.net/1/messages.json"
49316038816SMartin Matuska
49416038816SMartin Matuska    [ -n "${ZED_PUSHOVER_TOKEN}" ] && [ -n "${ZED_PUSHOVER_USER}" ] || return 2
49516038816SMartin Matuska
49616038816SMartin Matuska    if [ ! -r "${pathname}" ]; then
49716038816SMartin Matuska        zed_log_err "pushover cannot read \"${pathname}\""
49816038816SMartin Matuska        return 1
49916038816SMartin Matuska    fi
50016038816SMartin Matuska
50116038816SMartin Matuska    zed_check_cmd "curl" "sed" || return 1
50216038816SMartin Matuska
50316038816SMartin Matuska    # Read the message body in.
50416038816SMartin Matuska    #
50516038816SMartin Matuska    msg_body="$(cat "${pathname}")"
50616038816SMartin Matuska
50716038816SMartin Matuska    if [ -z "${msg_body}" ]
50816038816SMartin Matuska    then
50916038816SMartin Matuska        msg_body=$subject
51016038816SMartin Matuska        subject=""
51116038816SMartin Matuska    fi
51216038816SMartin Matuska
51316038816SMartin Matuska    # Send the POST request and check for errors.
51416038816SMartin Matuska    #
51516038816SMartin Matuska    msg_out="$( \
51616038816SMartin Matuska        curl \
51716038816SMartin Matuska        --form-string "token=${ZED_PUSHOVER_TOKEN}" \
51816038816SMartin Matuska        --form-string "user=${ZED_PUSHOVER_USER}" \
51916038816SMartin Matuska        --form-string "message=${msg_body}" \
52016038816SMartin Matuska        --form-string "title=${subject}" \
52116038816SMartin Matuska        "${url}" \
52216038816SMartin Matuska        2>/dev/null \
52316038816SMartin Matuska        )"; rv=$?
52416038816SMartin Matuska    if [ "${rv}" -ne 0 ]; then
52516038816SMartin Matuska        zed_log_err "curl exit=${rv}"
52616038816SMartin Matuska        return 1
52716038816SMartin Matuska    fi
52816038816SMartin Matuska    msg_err="$(echo "${msg_out}" \
52916038816SMartin Matuska        | sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
53016038816SMartin Matuska    if [ -n "${msg_err}" ]; then
53116038816SMartin Matuska        zed_log_err "pushover \"${msg_err}"\"
53216038816SMartin Matuska        return 1
53316038816SMartin Matuska    fi
53416038816SMartin Matuska    return 0
53516038816SMartin Matuska}
53616038816SMartin Matuska
53716038816SMartin Matuska
5383494f7c0SMartin Matuska# zed_notify_ntfy (subject, pathname)
5393494f7c0SMartin Matuska#
5403494f7c0SMartin Matuska# Send a notification via Ntfy.sh <https://ntfy.sh/>.
5413494f7c0SMartin Matuska# The ntfy topic (ZED_NTFY_TOPIC) identifies the topic that the notification
5423494f7c0SMartin Matuska# will be sent to Ntfy.sh server. The ntfy url (ZED_NTFY_URL) defines the
5433494f7c0SMartin Matuska# self-hosted or provided hosted ntfy service location. The ntfy access token
5443494f7c0SMartin Matuska# <https://docs.ntfy.sh/publish/#access-tokens> (ZED_NTFY_ACCESS_TOKEN) reprsents an
5453494f7c0SMartin Matuska# access token that could be used if a topic is read/write protected. If a
5463494f7c0SMartin Matuska# topic can be written to publicaly, a ZED_NTFY_ACCESS_TOKEN is not required.
5473494f7c0SMartin Matuska#
5483494f7c0SMartin Matuska# Requires curl and sed executables to be installed in the standard PATH.
5493494f7c0SMartin Matuska#
5503494f7c0SMartin Matuska# References
5513494f7c0SMartin Matuska#   https://docs.ntfy.sh
5523494f7c0SMartin Matuska#
5533494f7c0SMartin Matuska# Arguments
5543494f7c0SMartin Matuska#   subject: notification subject
5553494f7c0SMartin Matuska#   pathname: pathname containing the notification message (OPTIONAL)
5563494f7c0SMartin Matuska#
5573494f7c0SMartin Matuska# Globals
5583494f7c0SMartin Matuska#   ZED_NTFY_TOPIC
5593494f7c0SMartin Matuska#   ZED_NTFY_ACCESS_TOKEN (OPTIONAL)
5603494f7c0SMartin Matuska#   ZED_NTFY_URL
5613494f7c0SMartin Matuska#
5623494f7c0SMartin Matuska# Return
5633494f7c0SMartin Matuska#   0: notification sent
5643494f7c0SMartin Matuska#   1: notification failed
5653494f7c0SMartin Matuska#   2: not configured
5663494f7c0SMartin Matuska#
5673494f7c0SMartin Matuskazed_notify_ntfy()
5683494f7c0SMartin Matuska{
5693494f7c0SMartin Matuska    local subject="$1"
5703494f7c0SMartin Matuska    local pathname="${2:-"/dev/null"}"
5713494f7c0SMartin Matuska    local msg_body
5723494f7c0SMartin Matuska    local msg_out
5733494f7c0SMartin Matuska    local msg_err
5743494f7c0SMartin Matuska
5753494f7c0SMartin Matuska    [ -n "${ZED_NTFY_TOPIC}" ] || return 2
5763494f7c0SMartin Matuska    local url="${ZED_NTFY_URL:-"https://ntfy.sh"}/${ZED_NTFY_TOPIC}"
5773494f7c0SMartin Matuska
5783494f7c0SMartin Matuska    if [ ! -r "${pathname}" ]; then
5793494f7c0SMartin Matuska        zed_log_err "ntfy cannot read \"${pathname}\""
5803494f7c0SMartin Matuska        return 1
5813494f7c0SMartin Matuska    fi
5823494f7c0SMartin Matuska
5833494f7c0SMartin Matuska    zed_check_cmd "curl" "sed" || return 1
5843494f7c0SMartin Matuska
5853494f7c0SMartin Matuska    # Read the message body in.
5863494f7c0SMartin Matuska    #
5873494f7c0SMartin Matuska    msg_body="$(cat "${pathname}")"
5883494f7c0SMartin Matuska
5893494f7c0SMartin Matuska    if [ -z "${msg_body}" ]
5903494f7c0SMartin Matuska    then
5913494f7c0SMartin Matuska        msg_body=$subject
5923494f7c0SMartin Matuska        subject=""
5933494f7c0SMartin Matuska    fi
5943494f7c0SMartin Matuska
5953494f7c0SMartin Matuska    # Send the POST request and check for errors.
5963494f7c0SMartin Matuska    #
5973494f7c0SMartin Matuska    if [ -n "${ZED_NTFY_ACCESS_TOKEN}" ]; then
5983494f7c0SMartin Matuska        msg_out="$( \
5993494f7c0SMartin Matuska        curl \
6003494f7c0SMartin Matuska        -u ":${ZED_NTFY_ACCESS_TOKEN}" \
6013494f7c0SMartin Matuska        -H "Title: ${subject}" \
6023494f7c0SMartin Matuska        -d "${msg_body}" \
6033494f7c0SMartin Matuska        -H "Priority: high" \
6043494f7c0SMartin Matuska        "${url}" \
6053494f7c0SMartin Matuska        2>/dev/null \
6063494f7c0SMartin Matuska        )"; rv=$?
6073494f7c0SMartin Matuska    else
6083494f7c0SMartin Matuska        msg_out="$( \
6093494f7c0SMartin Matuska        curl \
6103494f7c0SMartin Matuska        -H "Title: ${subject}" \
6113494f7c0SMartin Matuska        -d "${msg_body}" \
6123494f7c0SMartin Matuska        -H "Priority: high" \
6133494f7c0SMartin Matuska        "${url}" \
6143494f7c0SMartin Matuska        2>/dev/null \
6153494f7c0SMartin Matuska        )"; rv=$?
6163494f7c0SMartin Matuska    fi
6173494f7c0SMartin Matuska    if [ "${rv}" -ne 0 ]; then
6183494f7c0SMartin Matuska        zed_log_err "curl exit=${rv}"
6193494f7c0SMartin Matuska        return 1
6203494f7c0SMartin Matuska    fi
6213494f7c0SMartin Matuska    msg_err="$(echo "${msg_out}" \
6223494f7c0SMartin Matuska        | sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
6233494f7c0SMartin Matuska    if [ -n "${msg_err}" ]; then
6243494f7c0SMartin Matuska        zed_log_err "ntfy \"${msg_err}"\"
6253494f7c0SMartin Matuska        return 1
6263494f7c0SMartin Matuska    fi
6273494f7c0SMartin Matuska    return 0
6283494f7c0SMartin Matuska}
6293494f7c0SMartin Matuska
6303494f7c0SMartin Matuska
631*f552d7adSMartin Matuska# zed_notify_gotify (subject, pathname)
632*f552d7adSMartin Matuska#
633*f552d7adSMartin Matuska# Send a notification via Gotify <https://gotify.net/>.
634*f552d7adSMartin Matuska# The Gotify URL (ZED_GOTIFY_URL) defines a self-hosted Gotify location.
635*f552d7adSMartin Matuska# The Gotify application token (ZED_GOTIFY_APPTOKEN) defines a
636*f552d7adSMartin Matuska# Gotify application token which is associated with a message.
637*f552d7adSMartin Matuska# The optional Gotify priority value (ZED_GOTIFY_PRIORITY) overrides the
638*f552d7adSMartin Matuska# default or configured priority at the Gotify server for the application.
639*f552d7adSMartin Matuska#
640*f552d7adSMartin Matuska# Requires curl and sed executables to be installed in the standard PATH.
641*f552d7adSMartin Matuska#
642*f552d7adSMartin Matuska# References
643*f552d7adSMartin Matuska#   https://gotify.net/docs/index
644*f552d7adSMartin Matuska#
645*f552d7adSMartin Matuska# Arguments
646*f552d7adSMartin Matuska#   subject: notification subject
647*f552d7adSMartin Matuska#   pathname: pathname containing the notification message (OPTIONAL)
648*f552d7adSMartin Matuska#
649*f552d7adSMartin Matuska# Globals
650*f552d7adSMartin Matuska#   ZED_GOTIFY_URL
651*f552d7adSMartin Matuska#   ZED_GOTIFY_APPTOKEN
652*f552d7adSMartin Matuska#   ZED_GOTIFY_PRIORITY
653*f552d7adSMartin Matuska#
654*f552d7adSMartin Matuska# Return
655*f552d7adSMartin Matuska#   0: notification sent
656*f552d7adSMartin Matuska#   1: notification failed
657*f552d7adSMartin Matuska#   2: not configured
658*f552d7adSMartin Matuska#
659*f552d7adSMartin Matuskazed_notify_gotify()
660*f552d7adSMartin Matuska{
661*f552d7adSMartin Matuska    local subject="$1"
662*f552d7adSMartin Matuska    local pathname="${2:-"/dev/null"}"
663*f552d7adSMartin Matuska    local msg_body
664*f552d7adSMartin Matuska    local msg_out
665*f552d7adSMartin Matuska    local msg_err
666*f552d7adSMartin Matuska
667*f552d7adSMartin Matuska    [ -n "${ZED_GOTIFY_URL}" ] && [ -n "${ZED_GOTIFY_APPTOKEN}" ] || return 2
668*f552d7adSMartin Matuska    local url="${ZED_GOTIFY_URL}/message?token=${ZED_GOTIFY_APPTOKEN}"
669*f552d7adSMartin Matuska
670*f552d7adSMartin Matuska    if [ ! -r "${pathname}" ]; then
671*f552d7adSMartin Matuska        zed_log_err "gotify cannot read \"${pathname}\""
672*f552d7adSMartin Matuska        return 1
673*f552d7adSMartin Matuska    fi
674*f552d7adSMartin Matuska
675*f552d7adSMartin Matuska    zed_check_cmd "curl" "sed" || return 1
676*f552d7adSMartin Matuska
677*f552d7adSMartin Matuska    # Read the message body in.
678*f552d7adSMartin Matuska    #
679*f552d7adSMartin Matuska    msg_body="$(cat "${pathname}")"
680*f552d7adSMartin Matuska
681*f552d7adSMartin Matuska    if [ -z "${msg_body}" ]
682*f552d7adSMartin Matuska    then
683*f552d7adSMartin Matuska        msg_body=$subject
684*f552d7adSMartin Matuska        subject=""
685*f552d7adSMartin Matuska    fi
686*f552d7adSMartin Matuska
687*f552d7adSMartin Matuska    # Send the POST request and check for errors.
688*f552d7adSMartin Matuska    #
689*f552d7adSMartin Matuska    if [ -n "${ZED_GOTIFY_PRIORITY}" ]; then
690*f552d7adSMartin Matuska        msg_out="$( \
691*f552d7adSMartin Matuska        curl \
692*f552d7adSMartin Matuska        --form-string "title=${subject}" \
693*f552d7adSMartin Matuska        --form-string "message=${msg_body}" \
694*f552d7adSMartin Matuska        --form-string "priority=${ZED_GOTIFY_PRIORITY}" \
695*f552d7adSMartin Matuska        "${url}" \
696*f552d7adSMartin Matuska        2>/dev/null \
697*f552d7adSMartin Matuska        )"; rv=$?
698*f552d7adSMartin Matuska    else
699*f552d7adSMartin Matuska        msg_out="$( \
700*f552d7adSMartin Matuska        curl \
701*f552d7adSMartin Matuska        --form-string "title=${subject}" \
702*f552d7adSMartin Matuska        --form-string "message=${msg_body}" \
703*f552d7adSMartin Matuska        "${url}" \
704*f552d7adSMartin Matuska        2>/dev/null \
705*f552d7adSMartin Matuska        )"; rv=$?
706*f552d7adSMartin Matuska    fi
707*f552d7adSMartin Matuska
708*f552d7adSMartin Matuska    if [ "${rv}" -ne 0 ]; then
709*f552d7adSMartin Matuska        zed_log_err "curl exit=${rv}"
710*f552d7adSMartin Matuska        return 1
711*f552d7adSMartin Matuska    fi
712*f552d7adSMartin Matuska    msg_err="$(echo "${msg_out}" \
713*f552d7adSMartin Matuska        | sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
714*f552d7adSMartin Matuska    if [ -n "${msg_err}" ]; then
715*f552d7adSMartin Matuska        zed_log_err "gotify \"${msg_err}"\"
716*f552d7adSMartin Matuska        return 1
717*f552d7adSMartin Matuska    fi
718*f552d7adSMartin Matuska    return 0
719*f552d7adSMartin Matuska}
720*f552d7adSMartin Matuska
721*f552d7adSMartin Matuska
7223494f7c0SMartin Matuska
723eda14cbcSMatt Macy# zed_rate_limit (tag, [interval])
724eda14cbcSMatt Macy#
725eda14cbcSMatt Macy# Check whether an event of a given type [tag] has already occurred within the
726eda14cbcSMatt Macy# last [interval] seconds.
727eda14cbcSMatt Macy#
728eda14cbcSMatt Macy# This function obtains a lock on the statefile using file descriptor 9.
729eda14cbcSMatt Macy#
730eda14cbcSMatt Macy# Arguments
731eda14cbcSMatt Macy#   tag: arbitrary string for grouping related events to rate-limit
732eda14cbcSMatt Macy#   interval: time interval in seconds (OPTIONAL)
733eda14cbcSMatt Macy#
734eda14cbcSMatt Macy# Globals
735eda14cbcSMatt Macy#   ZED_NOTIFY_INTERVAL_SECS
736eda14cbcSMatt Macy#   ZED_RUNDIR
737eda14cbcSMatt Macy#
738eda14cbcSMatt Macy# Return
739eda14cbcSMatt Macy#   0 if the event should be processed
740eda14cbcSMatt Macy#   1 if the event should be dropped
741eda14cbcSMatt Macy#
742eda14cbcSMatt Macy# State File Format
743eda14cbcSMatt Macy#   time;tag
744eda14cbcSMatt Macy#
745eda14cbcSMatt Macyzed_rate_limit()
746eda14cbcSMatt Macy{
747eda14cbcSMatt Macy    local tag="$1"
748eda14cbcSMatt Macy    local interval="${2:-${ZED_NOTIFY_INTERVAL_SECS}}"
749eda14cbcSMatt Macy    local lockfile="zed.zedlet.state.lock"
750eda14cbcSMatt Macy    local lockfile_fd=9
751eda14cbcSMatt Macy    local statefile="${ZED_RUNDIR}/zed.zedlet.state"
752eda14cbcSMatt Macy    local time_now
753eda14cbcSMatt Macy    local time_prev
754eda14cbcSMatt Macy    local umask_bak
755eda14cbcSMatt Macy    local rv=0
756eda14cbcSMatt Macy
757eda14cbcSMatt Macy    [ -n "${tag}" ] || return 0
758eda14cbcSMatt Macy
759eda14cbcSMatt Macy    zed_lock "${lockfile}" "${lockfile_fd}"
760eda14cbcSMatt Macy    time_now="$(date +%s)"
761eda14cbcSMatt Macy    time_prev="$(grep -E "^[0-9]+;${tag}\$" "${statefile}" 2>/dev/null \
762eda14cbcSMatt Macy        | tail -1 | cut -d\; -f1)"
763eda14cbcSMatt Macy
764eda14cbcSMatt Macy    if [ -n "${time_prev}" ] \
765eda14cbcSMatt Macy            && [ "$((time_now - time_prev))" -lt "${interval}" ]; then
766eda14cbcSMatt Macy        rv=1
767eda14cbcSMatt Macy    else
768eda14cbcSMatt Macy        umask_bak="$(umask)"
769eda14cbcSMatt Macy        umask 077
770eda14cbcSMatt Macy        grep -E -v "^[0-9]+;${tag}\$" "${statefile}" 2>/dev/null \
771eda14cbcSMatt Macy            > "${statefile}.$$"
772eda14cbcSMatt Macy        echo "${time_now};${tag}" >> "${statefile}.$$"
773eda14cbcSMatt Macy        mv -f "${statefile}.$$" "${statefile}"
774eda14cbcSMatt Macy        umask "${umask_bak}"
775eda14cbcSMatt Macy    fi
776eda14cbcSMatt Macy
777eda14cbcSMatt Macy    zed_unlock "${lockfile}" "${lockfile_fd}"
778eda14cbcSMatt Macy    return "${rv}"
779eda14cbcSMatt Macy}
780eda14cbcSMatt Macy
781eda14cbcSMatt Macy
782eda14cbcSMatt Macy# zed_guid_to_pool (guid)
783eda14cbcSMatt Macy#
784eda14cbcSMatt Macy# Convert a pool GUID into its pool name (like "tank")
785eda14cbcSMatt Macy# Arguments
786eda14cbcSMatt Macy#   guid: pool GUID (decimal or hex)
787eda14cbcSMatt Macy#
788eda14cbcSMatt Macy# Return
789eda14cbcSMatt Macy#   Pool name
790eda14cbcSMatt Macy#
791eda14cbcSMatt Macyzed_guid_to_pool()
792eda14cbcSMatt Macy{
793eda14cbcSMatt Macy	if [ -z "$1" ] ; then
794eda14cbcSMatt Macy		return
795eda14cbcSMatt Macy	fi
796eda14cbcSMatt Macy
79716038816SMartin Matuska	guid="$(printf "%u" "$1")"
79816038816SMartin Matuska	$ZPOOL get -H -ovalue,name guid | awk '$1 == '"$guid"' {print $2; exit}'
799eda14cbcSMatt Macy}
800eda14cbcSMatt Macy
801eda14cbcSMatt Macy# zed_exit_if_ignoring_this_event
802eda14cbcSMatt Macy#
803eda14cbcSMatt Macy# Exit the script if we should ignore this event, as determined by
804eda14cbcSMatt Macy# $ZED_SYSLOG_SUBCLASS_INCLUDE and $ZED_SYSLOG_SUBCLASS_EXCLUDE in zed.rc.
805eda14cbcSMatt Macy# This function assumes you've imported the normal zed variables.
806eda14cbcSMatt Macyzed_exit_if_ignoring_this_event()
807eda14cbcSMatt Macy{
808eda14cbcSMatt Macy	if [ -n "${ZED_SYSLOG_SUBCLASS_INCLUDE}" ]; then
809eda14cbcSMatt Macy	    eval "case ${ZEVENT_SUBCLASS} in
810eda14cbcSMatt Macy	    ${ZED_SYSLOG_SUBCLASS_INCLUDE});;
811eda14cbcSMatt Macy	    *) exit 0;;
812eda14cbcSMatt Macy	    esac"
813eda14cbcSMatt Macy	elif [ -n "${ZED_SYSLOG_SUBCLASS_EXCLUDE}" ]; then
814eda14cbcSMatt Macy	    eval "case ${ZEVENT_SUBCLASS} in
815eda14cbcSMatt Macy	    ${ZED_SYSLOG_SUBCLASS_EXCLUDE}) exit 0;;
816eda14cbcSMatt Macy	    *);;
817eda14cbcSMatt Macy	    esac"
818eda14cbcSMatt Macy	fi
819eda14cbcSMatt Macy}
820