1 # Apply timing control to this host
2 # This is run as a cron job to either "close" or "open" the blocking of
3 # the host via a configured control implementation.
5 # File control.dat defines the limits, and control mechanism.
6 # File activity-$date.dat is the local activity.
9 (write-line 2 (join (map string args)))
12 (constant 'NOW (date-value))
14 # Set current time variables in local timezone
15 (map set '(YEAR MONTH DATE HOUR MINUTE SECOND DOY DOW)
16 (date-list (+ NOW (* 60 (now 0 -2)))))
17 ;(println (list YEAR MONTH DATE HOUR MINUTE SECOND DOY DOW))
20 DAY (list YEAR MONTH DATE)
23 CONTROL.DAT "control.dat"
24 EXTRA.DAT "control-extra.dat"
26 USAGE.TMP ".usage.dat"
30 # ( (control "file") (gap minutes) ( weekday start limit stop ) ... )
31 (setf CONTROL (read-expr (or (read-file CONTROL.DAT)
32 (die "** Missing " CONTROL.DAT " ** Exiting."))
34 (map set '(dow MODE START LIMIT END)
35 (or (assoc DOW CONTROL)
36 (assoc 'policy CONTROL)
37 (list DOW (6 30) 120 (20 0)))
41 GAP (or (lookup 'gap CONTROL) 15)
42 CLIP (or (lookup 'clip CONTROL) 1000)
43 NET (or (lookup 'net CONTROL) "10.0.0.0/8")
46 # Load the configured control mechanism
47 (if (lookup 'control CONTROL) (load $it)
48 (die "** Unknown control mechanism. Exiting!!"))
50 (die "** Control function (control cmd reason) not defined. Exiting!!"))
52 ;; Apply control command with reason, then exit
53 (define (do-control x r) (control x r) (exit 0))
55 ;; Utility: Combine an (hour minutes) pair into total minutes
56 (define (minutes x) (+ (* (x 0) 60) (x 1)))
58 ;; Utility: Combine hours and minutes into total seconds
59 (define (seconds H M) (+ (* 3600 H) (* 60 M)))
61 # Apply EXTRA.DAT. This is a pair of hours and minutes to force open,
62 # relative to the modification time of the file.
64 (when (regex "([0-9]+) ([0-9]+)" (or (read-file EXTRA.DAT) "") 0)
65 (<= NOW (+ (file-info EXTRA.DAT 6) (seconds (int $1) (int $2))))))
67 ;;==== Utilities for activity data
68 # Activity is lines of timestamps. Collect TOTAL as list of unique
69 # time values (H M) within the start-end time span.
70 (define (log-name-fmt t)
71 (format "%d%02d%02d-.*\\.dat" (0 3 (date-list t))))
74 (find-all "([0-9]+( \\S+)?).*" (read-file (string "activity/" f)) $1 0))
76 # Collect all timestamps of the UTC date of the given time stamp
78 (flat (map log-lines (directory "activity" (log-name-fmt t)))))
80 # Translate timestamp into its local time (hour minute), if it's
81 # within the applicable day, null otherwise.
82 (define (period-minute x)
84 (letn ((d (date-list (+ (int x 0 10) (* 60 (now 0 -2)))))
86 (on (if (regex "^[0-9]+ ([0-9]+)$" x 0) (> (int $1 0 10) CLIP) 1))
88 (and on (= (0 3 d) DAY) tm)))) ; (>= tm START) (< tm END) tm))))
91 # Collect all mentioned minutes from the activity logs
96 (sort (extend (logs (- NOW 86400)) (logs NOW)))))))
98 # Add all mentioned minutes, and fill in any time periods of less than
99 # the configured GAP minutes between them.
102 (setf LAST (minutes (pop TOTAL) SUM 1))
104 (letn ((M (minutes x)) (V (- M LAST)))
105 (inc SUM (if (< V GAP) V 1))
109 # Rework SUM into (h m) format
110 (setf SUM (letn ((h (/ SUM 60)) (m (- SUM (* 60 h)))) (list h m)))
112 # Write out current usage with atomic update (jic)
113 (write-file USAGE.TMP (string SUM))
114 (rename-file USAGE.TMP USAGE.DAT)
116 # Apply current policy setting
117 ; ** Note that do-control exits
118 (when OVERRIDE (do-control "open" "override"))
120 (closed (do-control "close" "closed"))
121 (opened (do-control "open" "open"))
122 (timed ;; Close host outside start-end times
123 (when (< HM START) (do-control "close" "early"))
124 (when (>= HM END) (do-control "close" "late"))
125 (when (> SUM LIMIT) (do-control "close" "usage"))
126 (do-control "open" "usage")
128 (true (die "Unknown control mode " MODE))