Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/cmd/zed/zed.d/zed-functions.sh
48529 views
1
#!/bin/sh
2
# shellcheck disable=SC2154,SC3043
3
# zed-functions.sh
4
#
5
# ZED helper functions for use in ZEDLETs
6
7
8
# Variable Defaults
9
#
10
: "${ZED_LOCKDIR:="/var/lock"}"
11
: "${ZED_NOTIFY_INTERVAL_SECS:=3600}"
12
: "${ZED_NOTIFY_VERBOSE:=0}"
13
: "${ZED_RUNDIR:="/var/run"}"
14
: "${ZED_SYSLOG_PRIORITY:="daemon.notice"}"
15
: "${ZED_SYSLOG_TAG:="zed"}"
16
17
ZED_FLOCK_FD=8
18
19
20
# zed_check_cmd (cmd, ...)
21
#
22
# For each argument given, search PATH for the executable command [cmd].
23
# Log a message if [cmd] is not found.
24
#
25
# Arguments
26
# cmd: name of executable command for which to search
27
#
28
# Return
29
# 0 if all commands are found in PATH and are executable
30
# n for a count of the command executables that are not found
31
#
32
zed_check_cmd()
33
{
34
local cmd
35
local rv=0
36
37
for cmd; do
38
if ! command -v "${cmd}" >/dev/null 2>&1; then
39
zed_log_err "\"${cmd}\" not installed"
40
rv=$((rv + 1))
41
fi
42
done
43
return "${rv}"
44
}
45
46
47
# zed_log_msg (msg, ...)
48
#
49
# Write all argument strings to the system log.
50
#
51
# Globals
52
# ZED_SYSLOG_PRIORITY
53
# ZED_SYSLOG_TAG
54
#
55
# Return
56
# nothing
57
#
58
zed_log_msg()
59
{
60
logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "$@"
61
}
62
63
64
# zed_log_err (msg, ...)
65
#
66
# Write an error message to the system log. This message will contain the
67
# script name, EID, and all argument strings.
68
#
69
# Globals
70
# ZED_SYSLOG_PRIORITY
71
# ZED_SYSLOG_TAG
72
# ZEVENT_EID
73
#
74
# Return
75
# nothing
76
#
77
zed_log_err()
78
{
79
zed_log_msg "error: ${0##*/}:""${ZEVENT_EID:+" eid=${ZEVENT_EID}:"}" "$@"
80
}
81
82
83
# zed_lock (lockfile, [fd])
84
#
85
# Obtain an exclusive (write) lock on [lockfile]. If the lock cannot be
86
# immediately acquired, wait until it becomes available.
87
#
88
# Every zed_lock() must be paired with a corresponding zed_unlock().
89
#
90
# By default, flock-style locks associate the lockfile with file descriptor 8.
91
# The bash manpage warns that file descriptors >9 should be used with care as
92
# they may conflict with file descriptors used internally by the shell. File
93
# descriptor 9 is reserved for zed_rate_limit(). If concurrent locks are held
94
# within the same process, they must use different file descriptors (preferably
95
# decrementing from 8); otherwise, obtaining a new lock with a given file
96
# descriptor will release the previous lock associated with that descriptor.
97
#
98
# Arguments
99
# lockfile: pathname of the lock file; the lock will be stored in
100
# ZED_LOCKDIR unless the pathname contains a "/".
101
# fd: integer for the file descriptor used by flock (OPTIONAL unless holding
102
# concurrent locks)
103
#
104
# Globals
105
# ZED_FLOCK_FD
106
# ZED_LOCKDIR
107
#
108
# Return
109
# nothing
110
#
111
zed_lock()
112
{
113
local lockfile="$1"
114
local fd="${2:-${ZED_FLOCK_FD}}"
115
local umask_bak
116
local err
117
118
[ -n "${lockfile}" ] || return
119
if ! expr "${lockfile}" : '.*/' >/dev/null 2>&1; then
120
lockfile="${ZED_LOCKDIR}/${lockfile}"
121
fi
122
123
umask_bak="$(umask)"
124
umask 077
125
126
# Obtain a lock on the file bound to the given file descriptor.
127
#
128
eval "exec ${fd}>> '${lockfile}'"
129
if ! err="$(flock --exclusive "${fd}" 2>&1)"; then
130
zed_log_err "failed to lock \"${lockfile}\": ${err}"
131
fi
132
133
umask "${umask_bak}"
134
}
135
136
137
# zed_unlock (lockfile, [fd])
138
#
139
# Release the lock on [lockfile].
140
#
141
# Arguments
142
# lockfile: pathname of the lock file
143
# fd: integer for the file descriptor used by flock (must match the file
144
# descriptor passed to the zed_lock function call)
145
#
146
# Globals
147
# ZED_FLOCK_FD
148
# ZED_LOCKDIR
149
#
150
# Return
151
# nothing
152
#
153
zed_unlock()
154
{
155
local lockfile="$1"
156
local fd="${2:-${ZED_FLOCK_FD}}"
157
local err
158
159
[ -n "${lockfile}" ] || return
160
if ! expr "${lockfile}" : '.*/' >/dev/null 2>&1; then
161
lockfile="${ZED_LOCKDIR}/${lockfile}"
162
fi
163
164
# Release the lock and close the file descriptor.
165
if ! err="$(flock --unlock "${fd}" 2>&1)"; then
166
zed_log_err "failed to unlock \"${lockfile}\": ${err}"
167
fi
168
eval "exec ${fd}>&-"
169
}
170
171
172
# zed_notify (subject, pathname)
173
#
174
# Send a notification via all available methods.
175
#
176
# Arguments
177
# subject: notification subject
178
# pathname: pathname containing the notification message (OPTIONAL)
179
#
180
# Return
181
# 0: notification succeeded via at least one method
182
# 1: notification failed
183
# 2: no notification methods configured
184
#
185
zed_notify()
186
{
187
local subject="$1"
188
local pathname="$2"
189
local num_success=0
190
local num_failure=0
191
192
zed_notify_email "${subject}" "${pathname}"; rv=$?
193
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
194
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
195
196
zed_notify_pushbullet "${subject}" "${pathname}"; rv=$?
197
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
198
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
199
200
zed_notify_slack_webhook "${subject}" "${pathname}"; rv=$?
201
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
202
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
203
204
zed_notify_pushover "${subject}" "${pathname}"; rv=$?
205
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
206
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
207
208
zed_notify_ntfy "${subject}" "${pathname}"; rv=$?
209
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
210
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
211
212
zed_notify_gotify "${subject}" "${pathname}"; rv=$?
213
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
214
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
215
216
[ "${num_success}" -gt 0 ] && return 0
217
[ "${num_failure}" -gt 0 ] && return 1
218
return 2
219
}
220
221
222
# zed_notify_email (subject, pathname)
223
#
224
# Send a notification via email to the address specified by ZED_EMAIL_ADDR.
225
#
226
# Requires the mail executable to be installed in the standard PATH, or
227
# ZED_EMAIL_PROG to be defined with the pathname of an executable capable of
228
# reading a message body from stdin.
229
#
230
# Command-line options to the mail executable can be specified in
231
# ZED_EMAIL_OPTS. This undergoes the following keyword substitutions:
232
# - @ADDRESS@ is replaced with the space-delimited recipient email address(es)
233
# - @SUBJECT@ is replaced with the notification subject
234
# If @SUBJECT@ was omited here, a "Subject: ..." header will be added to notification
235
#
236
#
237
# Arguments
238
# subject: notification subject
239
# pathname: pathname containing the notification message (OPTIONAL)
240
#
241
# Globals
242
# ZED_EMAIL_PROG
243
# ZED_EMAIL_OPTS
244
# ZED_EMAIL_ADDR
245
#
246
# Return
247
# 0: notification sent
248
# 1: notification failed
249
# 2: not configured
250
#
251
zed_notify_email()
252
{
253
local subject="${1:-"ZED notification"}"
254
local pathname="${2:-"/dev/null"}"
255
256
: "${ZED_EMAIL_PROG:="mail"}"
257
: "${ZED_EMAIL_OPTS:="-s '@SUBJECT@' @ADDRESS@"}"
258
259
# For backward compatibility with ZED_EMAIL.
260
if [ -n "${ZED_EMAIL}" ] && [ -z "${ZED_EMAIL_ADDR}" ]; then
261
ZED_EMAIL_ADDR="${ZED_EMAIL}"
262
fi
263
[ -n "${ZED_EMAIL_ADDR}" ] || return 2
264
265
zed_check_cmd "${ZED_EMAIL_PROG}" || return 1
266
267
[ -n "${subject}" ] || return 1
268
if [ ! -r "${pathname}" ]; then
269
zed_log_err \
270
"${ZED_EMAIL_PROG##*/} cannot read \"${pathname}\""
271
return 1
272
fi
273
274
# construct cmdline options
275
ZED_EMAIL_OPTS_PARSED="$(echo "${ZED_EMAIL_OPTS}" \
276
| sed -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \
277
-e "s/@SUBJECT@/${subject}/g")"
278
279
# pipe message to email prog
280
# shellcheck disable=SC2086,SC2248
281
{
282
# no subject passed as option?
283
if [ "${ZED_EMAIL_OPTS%@SUBJECT@*}" = "${ZED_EMAIL_OPTS}" ] ; then
284
# inject subject header
285
printf "Subject: %s\n" "${subject}"
286
# The following empty line is needed to separate the header from the
287
# body of the message. Otherwise programs like sendmail will skip
288
# everything up to the first empty line (or wont send an email at
289
# all) and will still exit with exit code 0
290
printf "\n"
291
fi
292
# output message
293
cat "${pathname}"
294
} |
295
eval ${ZED_EMAIL_PROG} ${ZED_EMAIL_OPTS_PARSED} >/dev/null 2>&1
296
rv=$?
297
if [ "${rv}" -ne 0 ]; then
298
zed_log_err "${ZED_EMAIL_PROG##*/} exit=${rv}"
299
return 1
300
fi
301
return 0
302
}
303
304
305
# zed_notify_pushbullet (subject, pathname)
306
#
307
# Send a notification via Pushbullet <https://www.pushbullet.com/>.
308
# The access token (ZED_PUSHBULLET_ACCESS_TOKEN) identifies this client to the
309
# Pushbullet server. The optional channel tag (ZED_PUSHBULLET_CHANNEL_TAG) is
310
# for pushing to notification feeds that can be subscribed to; if a channel is
311
# not defined, push notifications will instead be sent to all devices
312
# associated with the account specified by the access token.
313
#
314
# Requires awk, curl, and sed executables to be installed in the standard PATH.
315
#
316
# References
317
# https://docs.pushbullet.com/
318
# https://www.pushbullet.com/security
319
#
320
# Arguments
321
# subject: notification subject
322
# pathname: pathname containing the notification message (OPTIONAL)
323
#
324
# Globals
325
# ZED_PUSHBULLET_ACCESS_TOKEN
326
# ZED_PUSHBULLET_CHANNEL_TAG
327
#
328
# Return
329
# 0: notification sent
330
# 1: notification failed
331
# 2: not configured
332
#
333
zed_notify_pushbullet()
334
{
335
local subject="$1"
336
local pathname="${2:-"/dev/null"}"
337
local msg_body
338
local msg_tag
339
local msg_json
340
local msg_out
341
local msg_err
342
local url="https://api.pushbullet.com/v2/pushes"
343
344
[ -n "${ZED_PUSHBULLET_ACCESS_TOKEN}" ] || return 2
345
346
[ -n "${subject}" ] || return 1
347
if [ ! -r "${pathname}" ]; then
348
zed_log_err "pushbullet cannot read \"${pathname}\""
349
return 1
350
fi
351
352
zed_check_cmd "awk" "curl" "sed" || return 1
353
354
# Escape the following characters in the message body for JSON:
355
# newline, backslash, double quote, horizontal tab, vertical tab,
356
# and carriage return.
357
#
358
msg_body="$(awk '{ ORS="\\n" } { gsub(/\\/, "\\\\"); gsub(/"/, "\\\"");
359
gsub(/\t/, "\\t"); gsub(/\f/, "\\f"); gsub(/\r/, "\\r"); print }' \
360
"${pathname}")"
361
362
# Push to a channel if one is configured.
363
#
364
[ -n "${ZED_PUSHBULLET_CHANNEL_TAG}" ] && msg_tag="$(printf \
365
'"channel_tag": "%s", ' "${ZED_PUSHBULLET_CHANNEL_TAG}")"
366
367
# Construct the JSON message for pushing a note.
368
#
369
msg_json="$(printf '{%s"type": "note", "title": "%s", "body": "%s"}' \
370
"${msg_tag}" "${subject}" "${msg_body}")"
371
372
# Send the POST request and check for errors.
373
#
374
msg_out="$(curl -u "${ZED_PUSHBULLET_ACCESS_TOKEN}:" -X POST "${url}" \
375
--header "Content-Type: application/json" --data-binary "${msg_json}" \
376
2>/dev/null)"; rv=$?
377
if [ "${rv}" -ne 0 ]; then
378
zed_log_err "curl exit=${rv}"
379
return 1
380
fi
381
msg_err="$(echo "${msg_out}" \
382
| sed -n -e 's/.*"error" *:.*"message" *: *"\([^"]*\)".*/\1/p')"
383
if [ -n "${msg_err}" ]; then
384
zed_log_err "pushbullet \"${msg_err}"\"
385
return 1
386
fi
387
return 0
388
}
389
390
391
# zed_notify_slack_webhook (subject, pathname)
392
#
393
# Notification via Slack Webhook <https://api.slack.com/incoming-webhooks>.
394
# The Webhook URL (ZED_SLACK_WEBHOOK_URL) identifies this client to the
395
# Slack channel.
396
#
397
# Requires awk, curl, and sed executables to be installed in the standard PATH.
398
#
399
# References
400
# https://api.slack.com/incoming-webhooks
401
#
402
# Arguments
403
# subject: notification subject
404
# pathname: pathname containing the notification message (OPTIONAL)
405
#
406
# Globals
407
# ZED_SLACK_WEBHOOK_URL
408
#
409
# Return
410
# 0: notification sent
411
# 1: notification failed
412
# 2: not configured
413
#
414
zed_notify_slack_webhook()
415
{
416
[ -n "${ZED_SLACK_WEBHOOK_URL}" ] || return 2
417
418
local subject="$1"
419
local pathname="${2:-"/dev/null"}"
420
local msg_body
421
local msg_tag
422
local msg_json
423
local msg_out
424
local msg_err
425
local url="${ZED_SLACK_WEBHOOK_URL}"
426
427
[ -n "${subject}" ] || return 1
428
if [ ! -r "${pathname}" ]; then
429
zed_log_err "slack webhook cannot read \"${pathname}\""
430
return 1
431
fi
432
433
zed_check_cmd "awk" "curl" "sed" || return 1
434
435
# Escape the following characters in the message body for JSON:
436
# newline, backslash, double quote, horizontal tab, vertical tab,
437
# and carriage return.
438
#
439
msg_body="$(awk '{ ORS="\\n" } { gsub(/\\/, "\\\\"); gsub(/"/, "\\\"");
440
gsub(/\t/, "\\t"); gsub(/\f/, "\\f"); gsub(/\r/, "\\r"); print }' \
441
"${pathname}")"
442
443
# Construct the JSON message for posting.
444
# shellcheck disable=SC2016
445
#
446
msg_json="$(printf '{"text": "*%s*\\n```%s```"}' "${subject}" "${msg_body}" )"
447
448
# Send the POST request and check for errors.
449
#
450
msg_out="$(curl -X POST "${url}" \
451
--header "Content-Type: application/json" --data-binary "${msg_json}" \
452
2>/dev/null)"; rv=$?
453
if [ "${rv}" -ne 0 ]; then
454
zed_log_err "curl exit=${rv}"
455
return 1
456
fi
457
msg_err="$(echo "${msg_out}" \
458
| sed -n -e 's/.*"error" *:.*"message" *: *"\([^"]*\)".*/\1/p')"
459
if [ -n "${msg_err}" ]; then
460
zed_log_err "slack webhook \"${msg_err}"\"
461
return 1
462
fi
463
return 0
464
}
465
466
# zed_notify_pushover (subject, pathname)
467
#
468
# Send a notification via Pushover <https://pushover.net/>.
469
# The access token (ZED_PUSHOVER_TOKEN) identifies this client to the
470
# Pushover server. The user token (ZED_PUSHOVER_USER) defines the user or
471
# group to which the notification will be sent.
472
#
473
# Requires curl and sed executables to be installed in the standard PATH.
474
#
475
# References
476
# https://pushover.net/api
477
#
478
# Arguments
479
# subject: notification subject
480
# pathname: pathname containing the notification message (OPTIONAL)
481
#
482
# Globals
483
# ZED_PUSHOVER_TOKEN
484
# ZED_PUSHOVER_USER
485
#
486
# Return
487
# 0: notification sent
488
# 1: notification failed
489
# 2: not configured
490
#
491
zed_notify_pushover()
492
{
493
local subject="$1"
494
local pathname="${2:-"/dev/null"}"
495
local msg_body
496
local msg_out
497
local msg_err
498
local url="https://api.pushover.net/1/messages.json"
499
500
[ -n "${ZED_PUSHOVER_TOKEN}" ] && [ -n "${ZED_PUSHOVER_USER}" ] || return 2
501
502
if [ ! -r "${pathname}" ]; then
503
zed_log_err "pushover cannot read \"${pathname}\""
504
return 1
505
fi
506
507
zed_check_cmd "curl" "sed" || return 1
508
509
# Read the message body in.
510
#
511
msg_body="$(cat "${pathname}")"
512
513
if [ -z "${msg_body}" ]
514
then
515
msg_body=$subject
516
subject=""
517
fi
518
519
# Send the POST request and check for errors.
520
#
521
msg_out="$( \
522
curl \
523
--form-string "token=${ZED_PUSHOVER_TOKEN}" \
524
--form-string "user=${ZED_PUSHOVER_USER}" \
525
--form-string "message=${msg_body}" \
526
--form-string "title=${subject}" \
527
"${url}" \
528
2>/dev/null \
529
)"; rv=$?
530
if [ "${rv}" -ne 0 ]; then
531
zed_log_err "curl exit=${rv}"
532
return 1
533
fi
534
msg_err="$(echo "${msg_out}" \
535
| sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
536
if [ -n "${msg_err}" ]; then
537
zed_log_err "pushover \"${msg_err}"\"
538
return 1
539
fi
540
return 0
541
}
542
543
544
# zed_notify_ntfy (subject, pathname)
545
#
546
# Send a notification via Ntfy.sh <https://ntfy.sh/>.
547
# The ntfy topic (ZED_NTFY_TOPIC) identifies the topic that the notification
548
# will be sent to Ntfy.sh server. The ntfy url (ZED_NTFY_URL) defines the
549
# self-hosted or provided hosted ntfy service location. The ntfy access token
550
# <https://docs.ntfy.sh/publish/#access-tokens> (ZED_NTFY_ACCESS_TOKEN) reprsents an
551
# access token that could be used if a topic is read/write protected. If a
552
# topic can be written to publicaly, a ZED_NTFY_ACCESS_TOKEN is not required.
553
#
554
# Requires curl and sed executables to be installed in the standard PATH.
555
#
556
# References
557
# https://docs.ntfy.sh
558
#
559
# Arguments
560
# subject: notification subject
561
# pathname: pathname containing the notification message (OPTIONAL)
562
#
563
# Globals
564
# ZED_NTFY_TOPIC
565
# ZED_NTFY_ACCESS_TOKEN (OPTIONAL)
566
# ZED_NTFY_URL
567
#
568
# Return
569
# 0: notification sent
570
# 1: notification failed
571
# 2: not configured
572
#
573
zed_notify_ntfy()
574
{
575
local subject="$1"
576
local pathname="${2:-"/dev/null"}"
577
local msg_body
578
local msg_out
579
local msg_err
580
581
[ -n "${ZED_NTFY_TOPIC}" ] || return 2
582
local url="${ZED_NTFY_URL:-"https://ntfy.sh"}/${ZED_NTFY_TOPIC}"
583
584
if [ ! -r "${pathname}" ]; then
585
zed_log_err "ntfy cannot read \"${pathname}\""
586
return 1
587
fi
588
589
zed_check_cmd "curl" "sed" || return 1
590
591
# Read the message body in.
592
#
593
msg_body="$(cat "${pathname}")"
594
595
if [ -z "${msg_body}" ]
596
then
597
msg_body=$subject
598
subject=""
599
fi
600
601
# Send the POST request and check for errors.
602
#
603
if [ -n "${ZED_NTFY_ACCESS_TOKEN}" ]; then
604
msg_out="$( \
605
curl \
606
-u ":${ZED_NTFY_ACCESS_TOKEN}" \
607
-H "Title: ${subject}" \
608
-d "${msg_body}" \
609
-H "Priority: high" \
610
"${url}" \
611
2>/dev/null \
612
)"; rv=$?
613
else
614
msg_out="$( \
615
curl \
616
-H "Title: ${subject}" \
617
-d "${msg_body}" \
618
-H "Priority: high" \
619
"${url}" \
620
2>/dev/null \
621
)"; rv=$?
622
fi
623
if [ "${rv}" -ne 0 ]; then
624
zed_log_err "curl exit=${rv}"
625
return 1
626
fi
627
msg_err="$(echo "${msg_out}" \
628
| sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
629
if [ -n "${msg_err}" ]; then
630
zed_log_err "ntfy \"${msg_err}"\"
631
return 1
632
fi
633
return 0
634
}
635
636
637
# zed_notify_gotify (subject, pathname)
638
#
639
# Send a notification via Gotify <https://gotify.net/>.
640
# The Gotify URL (ZED_GOTIFY_URL) defines a self-hosted Gotify location.
641
# The Gotify application token (ZED_GOTIFY_APPTOKEN) defines a
642
# Gotify application token which is associated with a message.
643
# The optional Gotify priority value (ZED_GOTIFY_PRIORITY) overrides the
644
# default or configured priority at the Gotify server for the application.
645
#
646
# Requires curl and sed executables to be installed in the standard PATH.
647
#
648
# References
649
# https://gotify.net/docs/index
650
#
651
# Arguments
652
# subject: notification subject
653
# pathname: pathname containing the notification message (OPTIONAL)
654
#
655
# Globals
656
# ZED_GOTIFY_URL
657
# ZED_GOTIFY_APPTOKEN
658
# ZED_GOTIFY_PRIORITY
659
#
660
# Return
661
# 0: notification sent
662
# 1: notification failed
663
# 2: not configured
664
#
665
zed_notify_gotify()
666
{
667
local subject="$1"
668
local pathname="${2:-"/dev/null"}"
669
local msg_body
670
local msg_out
671
local msg_err
672
673
[ -n "${ZED_GOTIFY_URL}" ] && [ -n "${ZED_GOTIFY_APPTOKEN}" ] || return 2
674
local url="${ZED_GOTIFY_URL}/message?token=${ZED_GOTIFY_APPTOKEN}"
675
676
if [ ! -r "${pathname}" ]; then
677
zed_log_err "gotify cannot read \"${pathname}\""
678
return 1
679
fi
680
681
zed_check_cmd "curl" "sed" || return 1
682
683
# Read the message body in.
684
#
685
msg_body="$(cat "${pathname}")"
686
687
if [ -z "${msg_body}" ]
688
then
689
msg_body=$subject
690
subject=""
691
fi
692
693
# Send the POST request and check for errors.
694
#
695
if [ -n "${ZED_GOTIFY_PRIORITY}" ]; then
696
msg_out="$( \
697
curl \
698
--form-string "title=${subject}" \
699
--form-string "message=${msg_body}" \
700
--form-string "priority=${ZED_GOTIFY_PRIORITY}" \
701
"${url}" \
702
2>/dev/null \
703
)"; rv=$?
704
else
705
msg_out="$( \
706
curl \
707
--form-string "title=${subject}" \
708
--form-string "message=${msg_body}" \
709
"${url}" \
710
2>/dev/null \
711
)"; rv=$?
712
fi
713
714
if [ "${rv}" -ne 0 ]; then
715
zed_log_err "curl exit=${rv}"
716
return 1
717
fi
718
msg_err="$(echo "${msg_out}" \
719
| sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
720
if [ -n "${msg_err}" ]; then
721
zed_log_err "gotify \"${msg_err}"\"
722
return 1
723
fi
724
return 0
725
}
726
727
728
729
# zed_rate_limit (tag, [interval])
730
#
731
# Check whether an event of a given type [tag] has already occurred within the
732
# last [interval] seconds.
733
#
734
# This function obtains a lock on the statefile using file descriptor 9.
735
#
736
# Arguments
737
# tag: arbitrary string for grouping related events to rate-limit
738
# interval: time interval in seconds (OPTIONAL)
739
#
740
# Globals
741
# ZED_NOTIFY_INTERVAL_SECS
742
# ZED_RUNDIR
743
#
744
# Return
745
# 0 if the event should be processed
746
# 1 if the event should be dropped
747
#
748
# State File Format
749
# time;tag
750
#
751
zed_rate_limit()
752
{
753
local tag="$1"
754
local interval="${2:-${ZED_NOTIFY_INTERVAL_SECS}}"
755
local lockfile="zed.zedlet.state.lock"
756
local lockfile_fd=9
757
local statefile="${ZED_RUNDIR}/zed.zedlet.state"
758
local time_now
759
local time_prev
760
local umask_bak
761
local rv=0
762
763
[ -n "${tag}" ] || return 0
764
765
zed_lock "${lockfile}" "${lockfile_fd}"
766
time_now="$(date +%s)"
767
time_prev="$(grep -E "^[0-9]+;${tag}\$" "${statefile}" 2>/dev/null \
768
| tail -1 | cut -d\; -f1)"
769
770
if [ -n "${time_prev}" ] \
771
&& [ "$((time_now - time_prev))" -lt "${interval}" ]; then
772
rv=1
773
else
774
umask_bak="$(umask)"
775
umask 077
776
grep -E -v "^[0-9]+;${tag}\$" "${statefile}" 2>/dev/null \
777
> "${statefile}.$$"
778
echo "${time_now};${tag}" >> "${statefile}.$$"
779
mv -f "${statefile}.$$" "${statefile}"
780
umask "${umask_bak}"
781
fi
782
783
zed_unlock "${lockfile}" "${lockfile_fd}"
784
return "${rv}"
785
}
786
787
788
# zed_guid_to_pool (guid)
789
#
790
# Convert a pool GUID into its pool name (like "tank")
791
# Arguments
792
# guid: pool GUID (decimal or hex)
793
#
794
# Return
795
# Pool name
796
#
797
zed_guid_to_pool()
798
{
799
if [ -z "$1" ] ; then
800
return
801
fi
802
803
guid="$(printf "%u" "$1")"
804
$ZPOOL get -H -ovalue,name guid | awk '$1 == '"$guid"' {print $2; exit}'
805
}
806
807
# zed_exit_if_ignoring_this_event
808
#
809
# Exit the script if we should ignore this event, as determined by
810
# $ZED_SYSLOG_SUBCLASS_INCLUDE and $ZED_SYSLOG_SUBCLASS_EXCLUDE in zed.rc.
811
# This function assumes you've imported the normal zed variables.
812
zed_exit_if_ignoring_this_event()
813
{
814
if [ -n "${ZED_SYSLOG_SUBCLASS_INCLUDE}" ]; then
815
eval "case ${ZEVENT_SUBCLASS} in
816
${ZED_SYSLOG_SUBCLASS_INCLUDE});;
817
*) exit 0;;
818
esac"
819
elif [ -n "${ZED_SYSLOG_SUBCLASS_EXCLUDE}" ]; then
820
eval "case ${ZEVENT_SUBCLASS} in
821
${ZED_SYSLOG_SUBCLASS_EXCLUDE}) exit 0;;
822
*);;
823
esac"
824
fi
825
}
826
827