datefmt: Define 1 year as 365.2425 days instead of 365.25
[sunny256-utils.git] / log_df
blob6bb5c02dd93afad71df5cd4fbbedee10b4f88890
1 #!/bin/sh
3 #==============================================================================
4 # log_df
5 # File ID: 99575e5c-5d3e-11df-9eee-90e6ba3022ac
7 # Log disk space.
9 # Author: Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 2 or later.
11 #==============================================================================
13 progname=log_df
14 VERSION=0.7.0
16 opt_dbname=''
17 opt_help=0
18 opt_host=''
19 opt_quiet=0
20 opt_upgrade_db=0
21 opt_verbose=0
22 while test -n "$1"; do
23 case "$1" in
24 -d|--dbname) opt_dbname="$2"; shift 2 ;;
25 -h|--help) opt_help=1; shift ;;
26 --host) opt_host="$2"; shift 2 ;;
27 -q|--quiet) opt_quiet=$(($opt_quiet + 1)); shift ;;
28 --upgrade-db) opt_upgrade_db=1; shift ;;
29 -v|--verbose) opt_verbose=$(($opt_verbose + 1)); shift ;;
30 --version) echo $progname $VERSION; exit 0 ;;
31 --) shift; break ;;
33 if printf '%s\n' "$1" | grep -q ^-; then
34 echo "$progname: $1: Unknown option" >&2
35 exit 1
36 else
37 break
39 break ;;
40 esac
41 done
42 opt_verbose=$(($opt_verbose - $opt_quiet))
44 if test "$opt_help" = "1"; then
45 test $opt_verbose -gt 0 && { echo; echo $progname $VERSION; }
46 cat <<END
48 Log disk space.
50 Usage: $progname [options]
52 Options:
54 -d DBFILE, --dbname DBFILE
55 Use DBFILE as database file for SQLite.
56 -h, --help
57 Show this help.
58 --host HOSTNAME
59 Use HOSTNAME as value in the host column.
60 -q, --quiet
61 Be more quiet. Can be repeated to increase silence.
62 --upgrade-db
63 Upgrade database to the current schema without adding new entries.
64 Can be used when converting old databases.
65 -v, --verbose
66 Increase level of verbosity. Can be repeated.
67 --version
68 Print version information.
70 END
71 exit 0
74 msg() {
75 echo "$progname: $*" >&2
78 SQLITE=sqlite3
79 dbversion=2
80 logdir="$HOME/log"
81 db="$logdir/df.sqlite"
82 if test -n "$opt_host"; then
83 host="$opt_host"
84 else
85 host=$(hostname)
87 if test -n "$opt_dbname"; then
88 db="$opt_dbname"
89 logdir="$(dirname "$db")"
92 [ -d "$logdir" ] || mkdir -p "$logdir" || {
93 msg $logdir: Could not create directory
94 exit 1
97 sql_create_table_meta=$(cat <<SQL_END
98 CREATE TABLE meta (
99 key TEXT
100 UNIQUE
101 NOT NULL
103 value TEXT
105 INSERT INTO meta VALUES ('dbversion', '$dbversion');
106 SQL_END
109 sql_create_table_df=$(cat <<SQL_END
110 CREATE TABLE df (
111 date TEXT
112 CONSTRAINT df_date_length
113 CHECK (length(date) = 19)
114 CONSTRAINT df_date_valid
115 CHECK (datetime(date) IS NOT NULL)
116 NOT NULL
118 host TEXT
119 CONSTRAINT df_host_length
120 CHECK (length(host) > 0)
121 NOT NULL
123 mountp TEXT
124 CONSTRAINT df_mountp_length
125 CHECK (length(mountp) > 0)
126 NOT NULL
128 device TEXT
129 CONSTRAINT df_device_length
130 CHECK (length(device) > 0)
131 NOT NULL
133 size INTEGER
134 CONSTRAINT df_size_length
135 CHECK (length(size) > 0)
136 CONSTRAINT df_size_positive
137 CHECK (size >= 0)
138 NOT NULL
140 used INTEGER
141 CONSTRAINT df_used_length
142 CHECK (length(used) > 0)
143 CONSTRAINT df_used_positive
144 CHECK (used >= 0)
145 NOT NULL
147 free INTEGER
148 CONSTRAINT df_free_length
149 CHECK (length(free) > 0)
150 CONSTRAINT df_free_positive
151 CHECK (free >= 0)
152 NOT NULL
154 UNIQUE (date, host, mountp)
155 ON CONFLICT IGNORE
157 SQL_END
160 sql_create_trigger_nodups=$(cat <<SQL_END
161 CREATE TRIGGER nodups
162 BEFORE INSERT ON df
163 BEGIN
164 SELECT RAISE (IGNORE)
165 WHERE
166 (SELECT used FROM df
167 WHERE mountp = NEW.mountp
168 ORDER BY date DESC
169 LIMIT 1) = NEW.used;
170 END;
171 SQL_END
174 if test ! -f "$db"; then
175 msg Creating database $db
176 cat <<SQL_END | $SQLITE "$db"
177 BEGIN EXCLUSIVE TRANSACTION;
178 $sql_create_table_meta
179 $sql_create_table_df
180 $sql_create_trigger_nodups
181 COMMIT;
182 SQL_END
185 curr_db_version=$(
186 $SQLITE "$db" "SELECT value FROM meta WHERE key = 'dbversion';"
189 upgrade_db() {
190 if test "$curr_db_version" = "$dbversion"; then
191 msg Database $db is already version $dbversion
192 return 0
194 backup="$db.$(date -u +"%Y%m%dT%H%M%SZ").db-upgrade.bck"
195 if test -e "$backup"; then
196 # Shouldn't happen, but keep it safe
197 msg Database backup $backup already exists, aborting
198 return 1
200 cp -p "$db" "$backup" || {
201 msg Could not backup database $db to $backup
202 return 1
204 msg Database backup stored as $backup
206 sql="BEGIN EXCLUSIVE TRANSACTION;
208 if test -z "$curr_db_version"; then
209 # First version without meta table
210 msg Upgrading database to version 1
211 sql="$sql$(cat <<SQL_END
212 $sql_create_table_meta
213 SQL_END
215 curr_db_version=1
217 if test $curr_db_version -lt 2; then
218 # Version 2
219 # - add host column and set all earlier entries to the current
220 # host name
221 # - delete percent column
222 msg Upgrading database to version 2
223 sql="$sql$(cat <<SQL_END
224 CREATE TABLE tmp_df AS
225 SELECT date, '$host' AS host, mountp, device, size, used, free FROM df;
226 DROP TABLE df;
227 $sql_create_table_df
228 $sql_create_trigger_nodups
229 INSERT INTO df
230 SELECT *
231 FROM tmp_df;
232 DROP TABLE tmp_df;
233 UPDATE meta SET value = 2
234 WHERE key = 'dbversion';
235 SQL_END
237 curr_db_version=2
240 sql="$sql
241 COMMIT;
242 VACUUM;
245 echo "$sql" | $SQLITE "$db" || return 1
246 msg Database $db successfully upgraded to version $dbversion
247 return 0
250 if test "$opt_upgrade_db" = "1"; then
251 upgrade_db
252 exit
255 if test -z "$curr_db_version"; then
256 msg dbversion not found, upgrading database $db
257 upgrade_db || {
258 msg Database upgrade failed
259 exit 1
263 if test $curr_db_version -lt $dbversion; then
264 msg Database $db is version $curr_db_version, needs upgrade
265 upgrade_db || {
266 msg Database upgrade failed
267 exit 1
271 df -B 1 -P |
272 grep ^/ |
273 sort -u |
274 perl -e "
275 while (<>) {
276 chomp();
277 if (/^(\\S+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\S+)%\\s+(\\S+)\$/) {
278 my (\$device, \$size, \$used, \$free, \$mountp) =
279 ( \$1, \$2, \$3, \$4, \$6);
280 print(
281 \"INSERT INTO df \" .
282 \"(date, host, mountp, \" .
283 \" device, size, used, free) \" .
284 \"VALUES (\" .
285 \"datetime('now'), '$host', '\$mountp', \" .
286 \"'\$device', \$size, \$used, \$free\" .
287 \");\\n\" .
288 \"\" .
289 \"\"
291 } else {
292 warn(\"$progname: Invalid line: \\"\$_\\"\\n\");
295 " | $SQLITE "$db"
297 # vim: set ts=8 sw=8 sts=8 noet fo+=w tw=79 fenc=UTF-8 :