-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path48-verifycron
More file actions
163 lines (130 loc) · 4.63 KB
/
48-verifycron
File metadata and controls
163 lines (130 loc) · 4.63 KB
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
#!/bin/bash
# verifycron--Checks a crontab file to ensure that it's
# formatted properly. Expects standard cron notation of
# min hr dom mon dow CMD,
# where min is 0-59, hr is 0-23, dom is 1-31, mon is 1-12 (or names)
# and dow is 0-7 (or names). Fields can be ranges (a-e) or lists
# separated by commas (a,c,z) or an asterisk. Note that the step
# value notation of Vixie cron (e.g., 2-6/2) is not supported by
# this script in its current version.
validNum()
{
# Return 0 if the number given is a valid integer and 1 if not.
# Specify both number and maxvalue as args to the function.
num=$1 max=$2
# Asterisk values in fields are rewritten as "X" for simplicity,
# so any number in the form "X" is de facto valid.
if [ "$num" = "X" ] ; then
return 0
elif [ ! -z $(echo $num | sed 's/[[:digit:]]//g') ] ; then
# Stripped out all the digits, and the remainder isn't empty? No good.
return 1
elif [ $num -gt $max ] ; then
# Number is bigger than the maximum value allowed.
return 1
else
return 0
fi
}
validDay()
{
# Return 0 if the value passed to this function is a valid day name,
# 1 otherwise.
case $(echo $1 | tr '[:upper:]' '[:lower:]') in
sun*|mon*|tue*|wed*|thu*|fri*|sat*) return 0 ;;
X) return 0 ;; # Special case--it's a rewritten "*"
*) return 1
esac
}
validMon()
{
# This function returns 0 if given a valid month name, 1 otherwise.
case $(echo $1 | tr '[:upper:]' '[:lower:]') in
jan*|feb*|mar*|apr*|may|jun*|jul*|aug*) return 0 ;;
sep*|oct*|nov*|dec*) return 0 ;;
X) return 0 ;; # special case, it's an "*"
*) return 1 ;;
esac
}
fixvars()
{
# Translate all '*' into 'X' to bypass shell expansion hassles.
# Save original input as "sourceline" for error messages.
sourceline="$min $hour $dom $mon $dow $command"
min=$(echo "$min" | tr '*' 'X') # minute
hour=$(echo "$hour" | tr '*' 'X') # hour
dom=$(echo "$dom" | tr '*' 'X') # day of month
mon=$(echo "$mon" | tr '*' 'X') # month
dow=$(echo "$dow" | tr '*' 'X') # day of week
}
if [ $# -ne 1 ] || [ ! -r $1 ] ; then
# If no crontab filename is given or it's not readable by the script, fail.
echo "Usage: $0 usercrontabfile" >&2; exit 1
fi
lines=0 entries=0 totalerrors=0
# Go through the crontab file line by line, checking each one.
while read min hour dom mon dow command
do
lines="$(( $lines + 1 ))"
errors=0
if [ -z "$min" -o "${min%${min#?}}" = "#" ] ; then
# If it's a blank line or the first character of the line is "#", skip it.
continue # Nothing to check
fi
((entries++))
fixvars
# At this point, all the fields in the current line are split out into
# separate variables, with all asterisks replaced by "X" for convenience,
# so let's check the validity of input fields...
# Minute check
for minslice in $(echo "$min" | sed 's/[,-]/ /g') ; do
if ! validNum $minslice 60 ; then
echo "Line ${lines}: Invalid minute value \"$minslice\""
errors=1
fi
done
# Hour check
for hrslice in $(echo "$hour" | sed 's/[,-]/ /g') ; do
if ! validNum $hrslice 24 ; then
echo "Line ${lines}: Invalid hour value \"$hrslice\""
errors=1
fi
done
# Day of month check
for domslice in $(echo $dom | sed 's/[,-]/ /g') ; do
if ! validNum $domslice 31 ; then
echo "Line ${lines}: Invalid day of month value \"$domslice\""
errors=1
fi
done
# Month check: Has to check for numeric values and names both.
# Remember that a conditional like "if ! cond" means that it's
# testing whether the specified condition is FALSE, not true.
for monslice in $(echo "$mon" | sed 's/[,-]/ /g') ; do
if ! validNum $monslice 12 ; then
if ! validMon "$monslice" ; then
echo "Line ${lines}: Invalid month value \"$monslice\""
errors=1
fi
fi
done
# Day of week check: Again, name or number is possible.
for dowslice in $(echo "$dow" | sed 's/[,-]/ /g') ; do
if ! validNum $dowslice 7 ; then
if ! validDay $dowslice ; then
echo "Line ${lines}: Invalid day of week value \"$dowslice\""
errors=1
fi
fi
done
if [ $errors -gt 0 ] ; then
echo ">>>> ${lines}: $sourceline"
echo ""
totalerrors="$(( $totalerrors + 1 ))"
fi
done < $1 # read the crontab passed as an argument to the script
# Notice that it's here, at the very end of the "while" loop, that we
# redirect the input so that the user-specified filename can be
# examined by the script!
echo "Done. Found $totalerrors errors in $entries crontab entries."
exit 0