--- /dev/null
+#!/bin/sh
+
+#-T timestamp
+#-a action
+#-t target
+#-i insert, otherwise search
+
+op=search
+action=
+json=0
+verbose=0
+
+pkgfile=${ZPMDB:-/var/lib/zpm/local.db}
+
+order=asc
+
+while getopts f:t:a:T:ijvr opt; do
+ case $opt in
+ f) pkgfile="$OPTARG" ;;
+ t) target="$OPTARG" ;;
+ a) action="$OPTARG" ;;
+ T) timestamp="$OPTARG" ;;
+ i) op=insert ;;
+ j) json=1 ;;
+ v) verbose=1 ;;
+ r) order=desc ;;
+ *) printf '%s unknown option %s\n' "$0" "$opt" ; exit 1 ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+if [ $op = 'insert' ]; then
+{
+ cols='action,target,info';
+ if [ -n "$timestamp" ]; then
+ cols='ts,action,target,info'
+ fi
+
+ printf "insert into zpmlog (%s)\n" $cols
+ printf 'values(';
+ if [ -n "$timestamp" ]; then
+ printf "'%s', " "$timestamp"
+ fi
+ if [ -n "$action" ]; then
+ printf "'%s', " "$action"
+ else
+ printf 'NULL,'
+ fi
+ if [ -n "$target" ]; then
+ printf "'%s', " "$target"
+ else
+ printf 'NULL,'
+ fi
+ printf "'%s')" "$*"
+ printf ';\n'
+} | zpm shell $pkgfile
+
+if [ $verbose -ne 0 ]; then
+ printf "%s %s %s\n" "$action" "$target" "$*" 1>&2
+fi
+
+fi
+
+cols='ts,target,action,info'
+
+if [ $op = 'search' ]; then
+
+if [ $json -eq 1 ]; then
+ cols="json_group_array(json_object('ts',ts,'target',target,'action',action,'info',info))"
+fi
+
+{
+ printf ".separator ' '\n"
+ printf 'select %s from zpmlog where\n' "$cols";
+ if [ -n "$timestamp" ]; then
+ printf "ts >= '%s' and " "$timestamp"
+ fi
+
+ if [ -n "$action" ]; then
+ printf "action like '%s' and " "$action"
+ fi
+ if [ -n "$target" ]; then
+ printf "target like '%s' and " "$target"
+ fi
+ printf "true order by ts $order;\n"
+} | zpm shell $pkgfile
+
+fi