-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathnextcloud-sync-cron.sh
executable file
·692 lines (569 loc) · 18.7 KB
/
nextcloud-sync-cron.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
#!/usr/bin/env bash
#
# Nextcloud sync cron script.
#
# This script is a wrapper around nextcloudcmd, designed to be run
# periodically as a cron job, to keep a local directory synchronised
# with a Nextcloud repository.
#
# Usage: nextcloud-sync-cron.sh configfile
#
# The config file must contain "username", "password", "local"
# directory and "remote" URL to a Nextcloud service. Equal sign
# between name and value.
#
# See the README file at <https://github.com/qcif/nextcloud-sync-cron>
# for more details.
#
# Copyright 2017, 2019, 2020, 2021,QCIF Pty Ltd.
#----------------------------------------------------------------
#----------------------------------------------------------------
# Constants: these should not be changed
NAME="Nextcloud sync cron"
VERSION=1.5.0
#----------------------------------------------------------------
PROG=$(basename "$0")
PROGDIR=$(cd "$(dirname "$0")" && pwd)
#----------------------------------------------------------------
# Exit status
STATUS_OK=0
STATUS_ERROR=1
STATUS_USAGE_ERROR=2
STATUS_UNEXPECTED_ERROR=3
STATUS_ALREADY_RUNNING=4
STATUS_SKIPPING=5
STATUS_CONFIG_ERROR=6
STATUS_CONFIG_FILE_NOT_FIXED=7
#----------------------------------------------------------------
# Bash strict mode: http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -e # exit if any command has non-zero exit status (works in sh too)
set -u # fail on attempts to expand undefined enviroment variables
set -o pipefail # prevents errors in a pipeline from being masked
# Better error message than "set -e" produces (but only bash supports ERR)
trap "echo $PROG: aborted; exit $STATUS_UNEXPECTED_ERROR" ERR
# Can't figure out which command failed? Run using "bash -x" or uncomment:
# set -x # write each command to stderr before it is exceuted
IFS=$'\n\t'
#----------------------------------------------------------------
# Process command line arguments
LOG_DIR=
VERBOSE=
CONF_FILE=
## Define options: trailing colon means has an argument
SHORT_OPTS=l:Vvh
LONG_OPTS=logdir:,verbose,version,help
SHORT_HELP="Usage: $PROG [options] configFile
Options:
-l dir directory for log files
-v always print out error messages to stderr on error
-h show this help message"
LONG_HELP="Usage: $PROG [options] configFile
Options:
-l | --logdir dir directory for log files
-v | --verbose always print out error messages to stderr on error
-h | --help show this help message
--version show version information"
# Detect if GNU Enhanced getopt is available
HAS_GNU_ENHANCED_GETOPT=
if getopt -T >/dev/null; then :
else
if [ $? -eq 4 ]; then
HAS_GNU_ENHANCED_GETOPT=yes
fi
fi
# Run getopt (runs getopt first in `if` so `trap ERR` does not interfere)
if [ -n "$HAS_GNU_ENHANCED_GETOPT" ]; then
# Use GNU enhanced getopt
if ! getopt --name "$PROG" --long $LONG_OPTS --options $SHORT_OPTS -- "$@" \
>/dev/null; then
echo "$PROG: usage error (use -h or --help for help)" >&2
exit 2
fi
ARGS=`getopt --name "$PROG" --long $LONG_OPTS --options $SHORT_OPTS -- "$@"`
else
# Use original getopt (no long option names, no whitespace, no sorting)
if ! getopt $SHORT_OPTS "$@" >/dev/null; then
echo "$PROG: usage error (use -h for help)" >&2
exit 2
fi
ARGS=`getopt $SHORT_OPTS "$@"`
fi
eval set -- $ARGS
## Process parsed options
while [ $# -gt 0 ]; do
case "$1" in
-l | --logdir) LOG_DIR="$2"; shift;;
-v | --verbose) VERBOSE=yes;;
-h | --help) if [ -n "$HAS_GNU_ENHANCED_GETOPT" ]
then echo "$LONG_HELP";
else echo "$SHORT_HELP";
fi; exit 0;;
-V | --version) echo "$NAME $VERSION"; exit 0;;
--) shift; break;; # end of options
esac
shift
done
## Process remaining arguments
if [ $# -eq 0 ]; then
echo "$PROG: usage error: missing configuration file ('-h' for help)" >&2
exit $STATUS_USAGE_ERROR
elif [ $# -eq 1 ]; then
CONF_FILE="$1"
else
echo "$PROG: too many arguments ('-h' for help)" >&2
exit $STATUS_USAGE_ERROR
fi
#----------------------------------------------------------------
# Check nextcloud client program is available
NEXTCLOUDCMD=nextcloudcmd
if ! which "$NEXTCLOUDCMD" >/dev/null 2>&1; then
echo "$PROG: error: command not found: $NEXTCLOUDCMD" 2>&1
exit 1
fi
#----------------------------------------------------------------
# Load configuration
function getconfig () {
# Usage: getconfig [--optional] param_name config_file
if [ $# -eq 3 -a "$1" = '--optional' ]; then
OPTIONAL=yes
PARAM="$2"
FILE="$3"
elif [ $# -eq 2 ]; then
OPTIONAL=
PARAM="$1"
FILE="$2"
else
echo "$PROG: internal error: invoking getconfig" >&2
exit $STATUS_CONFIG_ERROR
fi
VALUE=
FOUND=
IFS=": "
while read -r K V; do
if [ "$K" = "$PARAM" ]; then
if [ -n "$FOUND" ]; then
echo "$PROG: config: multiple value for \"$PARAM\": $FILE" >&2
exit $STATUS_CONFIG_ERROR
fi
VALUE="$V"
FOUND=yes
fi
done < "$FILE"
if [ -z "$OPTIONAL" ]; then
# Parameter was mandatory
if [ -z "$FOUND" ]; then
echo "$PROG: config: missing value for \"$PARAM\": $FILE" >&2
exit $STATUS_CONFIG_ERROR
fi
if [ -z "$VALUE" ]; then
echo "$PROG: config: \"$PARAM\" cannot be blank: $FILE" >&2
exit $STATUS_CONFIG_ERROR
fi
fi
echo "$VALUE"
}
if [ ! -e "$CONF_FILE" ]; then
echo "$PROG: error: config file missing: $CONF_FILE" >&2
exit $STATUS_ERROR
fi
if [ ! -f "$CONF_FILE" ]; then
echo "$PROG: error: config file is not a file: $CONF_FILE" >&2
exit $STATUS_ERROR
fi
if [ ! -r "$CONF_FILE" ]; then
echo "$PROG: error: cannot read config file: $CONF_FILE" >&2
exit $STATUS_ERROR
fi
# Optional config options
USERNAME=`getconfig --optional username "$CONF_FILE"`
PASSWORD=`getconfig --optional password "$CONF_FILE"`
UNSYNCEDFOLDERS=`getconfig --optional unsyncedfolders "$CONF_FILE"`
DAVPATH=`getconfig --optional davpath "$CONF_FILE"`
UPLIMIT=`getconfig --optional uplimit "$CONF_FILE"`
DOWNLIMIT=`getconfig --optional downlimit "$CONF_FILE"`
EXCLUDE=`getconfig --optional exclude "$CONF_FILE"`
HTTPPROXY=`getconfig --optional httpproxy "$CONF_FILE"`
TRUST=`getconfig --optional trust "$CONF_FILE"`
USEDELAY=`getconfig --optional usedelay "$CONF_FILE"`
# Mandatory config options
LOCAL_DIR=`getconfig local "$CONF_FILE"`
REMOTE_URI=`getconfig remote "$CONF_FILE"`
#----------------------------------------------------------------
# Setup internal file names
if [ -z "$LOG_DIR" ]; then
# No log directory from command line: use default inside local directory
LOG_DIR="$LOCAL_DIR/._sync_nextcloud"
fi
LOG_FILE="$LOG_DIR/sync.log"
PID_FILE="$LOG_DIR/sync.pid"
OUT_FILE="$LOG_DIR/nextcloudcmd.txt"
BAD_FILE="$LOG_DIR/failures.txt"
#----------------------------------------------------------------
# Check configuration is correct
if [ ! -e "$LOCAL_DIR" ]; then
echo "$PROG: error: local directory missing: $LOCAL_DIR" >&2
exit $STATUS_ERROR
fi
if [ ! -d "$LOCAL_DIR" ]; then
echo "$PROG: error: local directory is not a directory: $LOCAL_DIR" >&2
exit $STATUS_ERROR
fi
if [ ! -r "$LOCAL_DIR" ]; then
echo "$PROG: error: cannot read local directory: $LOCAL_DIR" >&2
exit $STATUS_ERROR
fi
if [ ! -w "$LOCAL_DIR" ]; then
echo "$PROG: error: cannot write to local directory: $LOCAL_DIR" >&2
exit $STATUS_ERROR
fi
if [ ! -x "$LOCAL_DIR" ]; then
echo "$PROG: error: cannot access local directory: $LOCAL_DIR" >&2
exit $STATUS_ERROR
fi
if [ ! -d "$LOG_DIR" ]; then
if ! mkdir "$LOG_DIR" 2>&1; then
echo "$PROG: error: cannot create log directory: $LOG_DIR" >&2
exit $STATUS_ERROR
fi
fi
if [ ! -w "$LOG_DIR" ]; then
echo "$PROG: error: cannot write to log directory: $LOG_DIR" >&2
exit $STATUS_ERROR
fi
if [ ! -x "$LOG_DIR" ]; then
echo "$PROG: error: cannot access log directory: $LOG_DIR" >&2
exit $STATUS_ERROR
fi
#----------------------------------------------------------------
# Start log file
if [ ! -f "$LOG_FILE" ]; then
# Log does not exist: create it
if ! touch "$LOG_FILE"; then
echo "$PROG: error: could not create log file: $LOG_FILE" >&2
exit $STATUS_ERROR
fi
fi
# NOTE: After this point this script does not produce any output to
# stdout or stderr, unless in verbose mode. This is so cron won't
# email the user anything. See the log file for any error messages.
#----------------------------------------------------------------
# Check credentials (might) exist
# Might because it doesn't look inside any ~/.netrc file for correctness.
ERROR=
if [ -n "$USERNAME" -a -z "$PASSWORD" ]; then
ERROR="config file has username without password"
elif [ -z "$USERNAME" -a -n "$PASSWORD" ]; then
ERROR="config file has password without username"
elif [ -z "$USERNAME" -a -z "$PASSWORD" ]; then
if [ ! -r "$HOME/.netrc" ]; then
ERROR="cannot read file: $HOME/.netrc"
fi
if [ ! -e "$HOME/.netrc" ]; then
ERROR="file missing: $HOME/.netrc"
fi
fi
if [ -n "$UNSYNCEDFOLDERS" ]; then
if [ ! -r "$UNSYNCEDFOLDERS" ]; then
ERROR="cannot read unsyncedfolders file: $UNSYNCEDFOLDERS"
fi
fi
if [ -n "$EXCLUDE" ]; then
if [ ! -r "$EXCLUDE" ]; then
ERROR="cannot read excludelist file: $EXCLUDE"
fi
fi
if [ -n "$ERROR" ]; then
TS=`date '+%F %T'`
echo "$TS: fail: $ERROR" >> "$LOG_FILE"
if [ -n "$VERBOSE" ]; then
echo "$PROG: error: $ERROR" >&2
fi
exit $STATUS_CONFIG_ERROR
fi
#----------------------------------------------------------------
# Check for previous failures
PARAM_NAME_NUM_FAILURES=number_of_failures
PARAM_NAME_TIMESTAMP=last_runtime
PARAM_NAME_REASON=reason
REASON_CONFIG='configuration error'
if [ -e "$BAD_FILE" ]; then
# Previous run failed
NUM_FAILURES=`getconfig $PARAM_NAME_NUM_FAILURES "$BAD_FILE"`
PREV_FAIL_SECS=`getconfig $PARAM_NAME_TIMESTAMP "$BAD_FILE"`
PREV_REASON=`getconfig $PARAM_NAME_REASON "$BAD_FILE"`
if ! echo "$NUM_FAILURES" | grep -E '^[0-9]+$' >/dev/null; then
if [ -n "$VERBOSE" ]; then
echo "$PROG: error: corrupt file: $BAD_FILE" >&2
fi
exit $STATUS_ERROR
fi
if [ $NUM_FAILURES -le 0 ]; then
if [ -n "$VERBOSE" ]; then
echo "$PROG: error: corrupt file: $BAD_FILE" >&2
fi
exit $STATUS_ERROR
fi
if ! echo "$PREV_FAIL_SECS" | grep -E '^[0-9]+$' >/dev/null; then
if [ -n "$VERBOSE" ]; then
echo "$PROG: error: corrupt file: $BAD_FILE" >&2
fi
exit $STATUS_ERROR
fi
# Determine delay before retrying
# Current algorithm: 1, 2, 4 minute ... 4, 8, 16, 24, 24, 24 hours ...
if [ -n "$USEDELAY" -a "$USEDELAY" != 'true' ]; then
USEDELAY="false"
else
USEDELAY="true"
fi
if [ "$USEDELAY" == 'true' ]; then
MAX_DELAY=$((60 * 60 * 24)) # 1 day
DELAY=$(( 2 ** (($NUM_FAILURES - 1)) * 60 ))
if [ $DELAY -gt $MAX_DELAY ]; then
DELAY=$MAX_DELAY
fi
else
DELAY=1 # 1 second
fi
# Abort if reason was configuration error and it has not been fixed
if echo "$PREV_REASON" | grep "^$REASON_CONFIG" >/dev/null; then
# Configuration error
if [ "$CONF_FILE" -nt "$BAD_FILE" ]; then
# Config file has been modified since last run
:
elif [ \( -z "$USERNAME" \) -a \
\( "$HOME/.netrc" -nt "$BAD_FILE" \) ];then
# Using ~/.netrc and it has been modified since last run
:
else
# Problem probably has not been fixed
if [ -n "$USERNAME" ]; then
ERROR="fix \"$CONF_FILE\" or delete \"$BAD_FILE\""
else
ERROR="fix \"$CONF_FILE\" and/or \"$HOME/.netrc\", or delete \"$BAD_FILE\""
fi
TS=`date '+%F %T'`
echo "$TS: fail: $ERROR" >> "$LOG_FILE"
if [ -n "$VERBOSE" ]; then
echo "$PROG: $PREV_REASON" >&2
echo "$PROG: $ERROR before running again" >&2
fi
exit $STATUS_CONFIG_FILE_NOT_FIXED
fi
# Note: normal delay does not apply.
else
# Not a config file error: retry or wait?
NOW_SECS=`date +%s`
ELAPSED=$(($NOW_SECS - $PREV_FAIL_SECS))
if [ $ELAPSED -lt $DELAY ]; then
if [ -n "$VERBOSE" ]; then
echo "$PROG: skipping (can sync in $(($DELAY-$ELAPSED))s)" >&2
fi
exit $STATUS_SKIPPING
fi
fi
else
# Previous run was ok
NUM_FAILURES=0
fi
#----------------------------------------------------------------
# Prevent multiple instances of this script from running
# Check PID file exists and its process is still running
if [ -f "$PID_FILE" ]; then
OLD_PID=`cat "$PID_FILE"`
if echo "$OLD_PID" | grep -E '^[0-9]+$' >/dev/null; then
# PID file contained a number
if ps -p "$OLD_PID" >/dev/null; then
# Process still running
if [ -n "$VERBOSE" ]; then
echo "$PROG: another process is already running" >&2
fi
exit $STATUS_ALREADY_RUNNING
else
# Process not running: stale PID file
rm "$PID_FILE"
fi
else
# PID file contained unexpected data
TS=`date '+%F %T'`
echo "$TS: fail: bad PID file: $PID_FILE" >> "$LOG_FILE"
exit $STATUS_ERROR
fi
fi
# Create PID file
PID=$$
echo $PID > "$PID_FILE"
SAVED_PID=`cat "$PID_FILE"`
if [ "$SAVED_PID" != "$PID" ]; then
# Race condition: someone else created the PID file before us?
if [ -n "$VERBOSE" ]; then
echo "$PROG: another process is already running" >&2
fi
exit $STATUS_ALREADY_RUNNING
fi
#----------------------------------------------------------------
# Run sync command, saving any error messages if this is a last chance run
# Write the settings used into the start of the file to aid debugging
TS=`date '+%F %T'`
START_SECS=`date +%s`
UNSYNCEDFOLDERS_SETTING=
if [ -n "$UNSYNCEDFOLDERS" ]; then
UNSYNCEDFOLDERS_SETTING="unsyncedfolders: $UNSYNCEDFOLDERS"
fi
DAVPATH_SETTING=
if [ -n "$DAVPATH" ]; then
DAVPATH_SETTING="davpath: $DAVPATH"
fi
UPLIMIT_SETTING=
if [ -n "$UPLIMIT" ]; then
UPLIMIT_SETTING="uplimit: $UPLIMIT"
fi
DOWNLIMIT_SETTING=
if [ -n "$DOWNLIMIT" ]; then
DOWNLIMIT_SETTING="downlimit: $DOWNLIMIT"
fi
EXCLUDE_SETTING=
if [ -n "$EXCLUDE" ]; then
EXCLUDE_SETTING="exclude: $EXCLUDE"
fi
HTTPPROXY_SETTING=
if [ -n "$HTTPPROXY" ]; then
HTTPPROXY_SETTING="httpproxy: $HTTPPROXY"
fi
TRUST_SETTING=
if [ -n "$TRUST" -a "$TRUST" != 'false' ]; then
TRUST_SETTING="trust: true"
fi
cat >"$OUT_FILE" <<EOF
# $NAME: nextcloudcmd output
# script: $PROGDIR/$PROG
# config: $CONF_FILE
# runtime: $TS
remote: $REMOTE_URI
local: $LOCAL_DIR
$UNSYNCEDFOLDERS_SETTING
$DAVPATH_SETTING
$UPLIMIT_SETTING
$DOWNLIMIT_SETTING
$EXCLUDE_SETTING
$HTTPPROXY_SETTING
$TRUST_SETTING
EOF
# Warning: do not run nextcloudcmd with -h, since that will sync the
# hidden directory used for logging. If hidden files are needed,
# change where the log directory is.
# Stdin is taken from /dev/null so when it attempts to use ~/.netrc
# and suitable credentials aren't in it, it is not going to hang
# waiting for the user to enter the password. The --non-interactive
# option is not used because it causes nextcloudcmd v2.3.2 to return a
# misleading zero exit status if it fails to authenticate.
UNSYNCEDFOLDERS_OPTION=
if [ -n "$UNSYNCEDFOLDERS" ]; then
UNSYNCEDFOLDERS_OPTION="--unsyncedfolders \"$UNSYNCEDFOLDERS\""
fi
DAVPATH_OPTION=
if [ -n "$DAVPATH" ]; then
DAVPATH_OPTION="--path \"$DAVPATH\""
fi
UPLIMIT_OPTION=
if [ -n "$UPLIMIT" ]; then
UPLIMIT_OPTION="--uplimit $UPLIMIT"
fi
DOWNLIMIT_OPTION=
if [ -n "$DOWNLIMIT" ]; then
DOWNLIMIT_OPTION="--downlimit $DOWNLIMIT"
fi
EXCLUDE_OPTION=
if [ -n "$EXCLUDE" ]; then
EXCLUDE_OPTION="--exclude \"$EXCLUDE\""
fi
HTTPPROXY_OPTION=
if [ -n "$HTTPPROXY" ]; then
HTTPPROXY_OPTION="--httpproxy '$HTTPPROXY'"
fi
TRUST_OPTION=
if [ -n "$TRUST" -a "$TRUST" != 'false' ]; then
TRUST_OPTION="--trust"
fi
# Run command
NCC_SUCCEEDED=
if [ -n "$USERNAME" ]; then
# Credentials on command line
if eval "$NEXTCLOUDCMD" --user "$USERNAME" --password "$PASSWORD" \
$UNSYNCEDFOLDERS_OPTION \
$DAVPATH_OPTION \
$UPLIMIT_OPTION \
$DOWNLIMIT_OPTION \
$EXCLUDE_OPTION \
$HTTPPROXY_OPTION \
$TRUST_OPTION \
"$LOCAL_DIR" "$REMOTE_URI" </dev/null >>"$OUT_FILE" 2>&1; then
NCC_SUCCEEDED=yes
fi
else
# Credentials from ~/.netrc (the "-n" means to use netrc for login)
if eval "$NEXTCLOUDCMD" -n \
$UNSYNCEDFOLDERS_OPTION \
$DAVPATH_OPTION \
$UPLIMIT_OPTION \
$DOWNLIMIT_OPTION \
$EXCLUDE_OPTION \
$HTTPPROXY_OPTION \
$TRUST_OPTION \
"$LOCAL_DIR" "$REMOTE_URI" </dev/null >>"$OUT_FILE" 2>&1; then
NCC_SUCCEEDED=yes
fi
fi
TE=`date '+%F %T'`
FINISH_SECS=`date +%s`
DELAY=$(($FINISH_SECS - $START_SECS))
# Write statistics into the end of the file
cat >>"$OUT_FILE" <<EOF
# time taken: $DELAY seconds
# finished: $TE
EOF
if [ -n "$NCC_SUCCEEDED" ]; then
# Succeeded
# Reset failures
if [ $NUM_FAILURES -gt 0 ]; then
rm "$BAD_FILE"
fi
# Log
echo "$TS: OK (${DELAY} s)" >> "$LOG_FILE"
EXIT_STATUS=$STATUS_OK
else
# Failed
# Attempt to interpret output for obvious errors.
REASON=
if grep 'Network error: "ocs/v1.php/cloud/capabilities" "Host .* not found" QVariant(Invalid)' "$OUT_FILE" >/dev/null; then
REASON="$REASON_CONFIG: bad host in \"remote\" URL"
elif grep 'Network error: "ocs/v1.php/cloud/capabilities" "Error transferring .* - server replied: Not Found" QVariant(int, 404)' "$OUT_FILE" >/dev/null; then
REASON="$REASON_CONFIG: bad path in \"remote\" URL"
elif grep 'Network error: "ocs/v1.php/cloud/capabilities" "Host requires authentication" QVariant(int, 401)' "$OUT_FILE" >/dev/null; then
REASON="$REASON_CONFIG: incorrect username/password"
else
REASON="see nextcloudcmd output: $OUT_FILE"
fi
# Record failures
NUM_FAILURES=$((NUM_FAILURES + 1))
cat > "$BAD_FILE" <<EOF
# $NAME: recent failures
# script: $PROGDIR/$PROG
# config: $CONF_FILE
# last_runtime: $TS
$PARAM_NAME_NUM_FAILURES: $NUM_FAILURES
$PARAM_NAME_TIMESTAMP: $START_SECS
$PARAM_NAME_REASON: $REASON
EOF
# Log
echo "$TS: fail" >> "$LOG_FILE"
if [ -n "$VERBOSE" ]; then
echo "$PROG: error: $REASON" >&2
fi
EXIT_STATUS=$STATUS_ERROR
fi
#----------------------------------------------------------------
# Remove PID file
rm "$PID_FILE"
exit $EXIT_STATUS
#EOF