]> pd.if.org Git - zpackage/commitdiff
add support for notes
authorNathan Wagner <nw@hydaspes.if.org>
Fri, 19 Oct 2018 08:15:46 +0000 (08:15 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Sat, 3 Nov 2018 12:39:52 +0000 (12:39 +0000)
coalesce devminor and devmajor into device

.gitignore
Makefile
db.sql
lib/dbquery.c
lib/integ.c
lib/notes.c [new file with mode: 0644]
lib/seterror.c [new file with mode: 0644]
zpm-note [deleted file]
zpm-syncfs.c
zpm.h

index 70122a687e1d2dbcc949582ed212f5c697589b2c..0290ec3498cd0b20eede639a5e9281591368b04e 100644 (file)
@@ -4,6 +4,7 @@
 uncompress
 zpm-addfile
 zpm-foreach-path
 uncompress
 zpm-addfile
 zpm-foreach-path
+zpm-note
 zpm-vercmp
 zpm-verify
 zpm-extract
 zpm-vercmp
 zpm-verify
 zpm-extract
index fb88665abf683baf99571d03a6bb3fe31168119d..1fb6e6ce1e90316493d80d7cea8d16392ac4e469 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ lib/jsw/jsw_rbtree.c
 JSWOBJ=$(JSWSRC:%.c=%.o)
 LIBZPMSRC=sha256.c db.c compress.c uncompress.c zpm.c zpm_hash.c \
          foreach_path.c vercmp.c findpkg.c quote.c dbquery.c script_hash.c \
 JSWOBJ=$(JSWSRC:%.c=%.o)
 LIBZPMSRC=sha256.c db.c compress.c uncompress.c zpm.c zpm_hash.c \
          foreach_path.c vercmp.c findpkg.c quote.c dbquery.c script_hash.c \
-         parse.c integ.c
+         parse.c integ.c seterror.c notes.c
 
 LIBZPMOBJ=$(addprefix lib/, $(LIBZPMSRC:%.c=%.o))
 
 
 LIBZPMOBJ=$(addprefix lib/, $(LIBZPMSRC:%.c=%.o))
 
@@ -29,7 +29,7 @@ curdir=$(shell pwd)
 ZPKGBIN=zpm-addfile zpm-extract zpm-init zpm-vercmp zpm-stat zpm-hash \
        zpm-findpkg zpm-shell zpm-soneed zpm-foreach-path zpm-parse \
        zpm-runscript zpm-soname zpm-syncfs zpm-packagehash zpm-verify \
 ZPKGBIN=zpm-addfile zpm-extract zpm-init zpm-vercmp zpm-stat zpm-hash \
        zpm-findpkg zpm-shell zpm-soneed zpm-foreach-path zpm-parse \
        zpm-runscript zpm-soname zpm-syncfs zpm-packagehash zpm-verify \
-       zpm-elftype zpm-quote
+       zpm-elftype zpm-quote zpm-note
 
 SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-preserve zpm-test zpm-log \
        zpm-contents zpm-uninstall zpm-pathmod zpm-rmpackage zpm-newpackage \
 
 SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-preserve zpm-test zpm-log \
        zpm-contents zpm-uninstall zpm-pathmod zpm-rmpackage zpm-newpackage \
@@ -142,6 +142,9 @@ zpm-foreach-path: zpm-foreach-path.o libzpm.a sqlite/sqlite3.h
 zpm-findpkg: zpm-findpkg.o libzpm.a
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf
 
 zpm-findpkg: zpm-findpkg.o libzpm.a
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf
 
+zpm-note: zpm-note.o libzpm.a
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf
+
 zpm-syncfs: zpm-syncfs.o libzpm.a libelf.a
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf -lm
 
 zpm-syncfs: zpm-syncfs.o libzpm.a libelf.a
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf -lm
 
diff --git a/db.sql b/db.sql
index be71bde3428047a6368f6e6ed611ab0f7d12b867..020f228d658dcb0f464e92afef8e2de0ab04e910 100644 (file)
--- a/db.sql
+++ b/db.sql
@@ -123,6 +123,7 @@ create table packagefiles (
        uid     integer, -- numeric uid, generally ignored
        gid     integer, -- numeric gid, generally ignored
        configuration integer not null default 0, -- boolean if config file
        uid     integer, -- numeric uid, generally ignored
        gid     integer, -- numeric gid, generally ignored
        configuration integer not null default 0, -- boolean if config file
+       confhash text, -- last hash on disk
        filetype varchar not null default 'r',
        -- r regular file
        -- d directory
        filetype varchar not null default 'r',
        -- r regular file
        -- d directory
@@ -132,10 +133,9 @@ create table packagefiles (
        -- b block special -- not supported
        -- c and b device special files add dev number column
        -- p fifos (i.e. pipe) -- not supported
        -- b block special -- not supported
        -- c and b device special files add dev number column
        -- p fifos (i.e. pipe) -- not supported
+       -- s unix domain socket -- not supported
        target  text, -- link target for links
        target  text, -- link target for links
-       -- device file dev numbers
-       devmajor        integer,
-       devminor        integer,
+       device  integer, -- device file dev_t
        hash    text, -- null if not a regular file
        mtime   integer, -- seconds since epoch, finer resolution not needed
        primary key (package,version,release,path),
        hash    text, -- null if not a regular file
        mtime   integer, -- seconds since epoch, finer resolution not needed
        primary key (package,version,release,path),
@@ -147,8 +147,8 @@ create table packagefiles (
        check (target is null or length(target) between 1 and 4095),
        check (hash is null or length(hash) between 1 and 1024),
        check (not (filetype = 'r' and hash is null)),
        check (target is null or length(target) between 1 and 4095),
        check (hash is null or length(hash) between 1 and 1024),
        check (not (filetype = 'r' and hash is null)),
-       check (not (filetype = 'c' and (devmajor is null or devminor is null))),
-       check (not (filetype = 'b' and (devmajor is null or devminor is null))),
+       check (not (filetype = 'c' and device is null)),
+       check (not (filetype = 'b' and device is null)),
        check (filetype in ('r','d','l','h','c','b','p')),
        check(length(username) between 1 and 256),
        check(length(groupname) between 1 and 256),
        check (filetype in ('r','d','l','h','c','b','p')),
        check(length(username) between 1 and 256),
        check(length(groupname) between 1 and 256),
@@ -183,8 +183,7 @@ begin
        configuration = NEW.configuration,
        filetype = NEW.filetype,
        target = NEW.target,
        configuration = NEW.configuration,
        filetype = NEW.filetype,
        target = NEW.target,
-       devmajor = NEW.devmajor,
-       devminor = NEW.devminor,
+       device = NEW.device,
        hash = NEW.hash,
        mtime = NEW.mtime
        where package = OLD.package
        hash = NEW.hash,
        mtime = NEW.mtime
        where package = OLD.package
@@ -368,6 +367,16 @@ create table zpmlog (
        info    text -- human readable
 );
 
        info    text -- human readable
 );
 
+create table notes (
+       id      integer primary key, -- rowid alias
+       ts      text default (strftime('%Y-%m-%d %H:%M:%f', 'now')),
+       note    text not null,
+       pkgid   text, -- package
+       path    text, -- file path involved
+       file    text, -- hash of file
+       ack     integer default 0
+);
+
 create table history (
        ts      integer, -- again, probably needs timestamp sub second
        cmd     text,
 create table history (
        ts      integer, -- again, probably needs timestamp sub second
        cmd     text,
@@ -473,7 +482,7 @@ syncstatus as (
 newfiles as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
 newfiles as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
-       target,devminor,devmajor
+       configuration,target,device, null as ohash
        from syncstatus SS
        where path not in (select path from syncstatus where
                rstatus in ('installed', 'updating', 'removing')
        from syncstatus SS
        where path not in (select path from syncstatus where
                rstatus in ('installed', 'updating', 'removing')
@@ -486,7 +495,8 @@ modified as (
        SS.path, 
        SS.username,
                SS.uid, SS.groupname, SS.gid, SS.mode,
        SS.path, 
        SS.username,
                SS.uid, SS.groupname, SS.gid, SS.mode,
-       SS.filetype, SS.mtime, SS.hash, SS.target, SS.devminor, SS.devmajor
+       SS.filetype, SS.mtime, SS.hash,SS.configuration, SS.target, SS.device,
+       null as ohash
        from syncstatus SS
        join syncstatus OS
        on SS.path = OS.path and SS.pkgid is not OS.pkgid
        from syncstatus SS
        join syncstatus OS
        on SS.path = OS.path and SS.pkgid is not OS.pkgid
@@ -507,7 +517,7 @@ needed as (
 preserve as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
 preserve as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
-       target,devminor,devmajor
+       configuration,target,device, null as ohash
        from syncstatus SS
        where path in (select library from needed)
        and SS.rstatus in ('removing', 'removed')
        from syncstatus SS
        where path in (select library from needed)
        and SS.rstatus in ('removing', 'removed')
@@ -516,7 +526,7 @@ preserve as (
 remove as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
 remove as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
-       target,devminor,devmajor
+       configuration,target,device, null as ohash
        from syncstatus SS
        where path not in (
                select path from syncstatus where
        from syncstatus SS
        where path not in (
                select path from syncstatus where
@@ -529,7 +539,7 @@ remove as (
 expired as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
 expired as (
        select distinct
                path,username,uid,groupname,gid,mode,filetype,mtime,hash,
-       target,devminor,devmajor
+       configuration,target,device, null as ohash
        from syncstatus BASE
        where hash in (select file from elflibraries where file is not null)
        and path not in (select path from preserve)
        from syncstatus BASE
        where hash in (select file from elflibraries where file is not null)
        and path not in (select path from preserve)
index ab03984697b2f255fc88aaa9ebc9d0c0a8d78ba5..cba95378ae2a258c8351b9f3ac07191bc46ce337 100644 (file)
@@ -62,6 +62,26 @@ sqlite3_stmt *zpm_dbquery(struct zpm *zpm, char *query, ...) {
        return st;
 }
 
        return st;
 }
 
+void zpm_db_run(struct zpm *zpm, char *query, ...) {
+       sqlite3_stmt *st;
+       va_list args;
+       int rv;
+
+       va_start(args, query);
+       st = zpm_dbqueryv(zpm, query, args);
+       va_end(args);
+
+       rv = sqlite3_step(st);
+
+       if (rv != SQLITE_DONE) {
+               zpm->error = 1;
+               zpm_seterror(zpm, "db error: %s", sqlite3_errstr(rv));
+       }
+
+       sqlite3_finalize(st);
+       return ;
+}
+
 char *zpm_db_string(struct zpm *zpm, char *query, ...) {
        sqlite3_stmt *st;
        va_list args;
 char *zpm_db_string(struct zpm *zpm, char *query, ...) {
        sqlite3_stmt *st;
        va_list args;
@@ -84,3 +104,24 @@ char *zpm_db_string(struct zpm *zpm, char *query, ...) {
        sqlite3_finalize(st);
        return result;
 }
        sqlite3_finalize(st);
        return result;
 }
+
+int zpm_db_int(struct zpm *zpm, char *query, ...) {
+       sqlite3_stmt *st;
+       va_list args;
+       int rv;
+       int result = 0;
+
+       va_start(args, query);
+       st = zpm_dbqueryv(zpm, query, args);
+       va_end(args);
+
+       rv = sqlite3_step(st);
+
+       if (rv == SQLITE_ROW) {
+               result = sqlite3_column_int(st, 0);
+       }
+       /* TODO set error if it's not SQLITE_ROW */
+
+       sqlite3_finalize(st);
+       return result;
+}
index 6abfcf340cff7087ea82a75c9e83cffd215fa130..81667eae77cee6ebd721fabd5d93b1d555a6217a 100644 (file)
@@ -155,7 +155,7 @@ int zpm_package_hash(struct zpm *zpm, char *pkgid, char *hash) {
        /* hash package files */
 
        sql = sqlite3_mprintf("select path, mode, username, groupname, configuration, "
        /* hash package files */
 
        sql = sqlite3_mprintf("select path, mode, username, groupname, configuration, "
-               "filetype, target, devmajor, devminor, mtime, hash "
+               "filetype, target, device, mtime, hash "
                "from packagefiles_pkgid where pkgid = %Q order by path",
                pkgid);
        hash_query(zpm, sql, &d);
                "from packagefiles_pkgid where pkgid = %Q order by path",
                pkgid);
        hash_query(zpm, sql, &d);
diff --git a/lib/notes.c b/lib/notes.c
new file mode 100644 (file)
index 0000000..9622bae
--- /dev/null
@@ -0,0 +1,180 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sqlite3.h"
+#include "zpm.h"
+
+void zpm_note_ack(struct zpm *zpm, int64_t note) {
+       char *in = "update notes set ack = 1 where id = %" PRId64;
+       zpm_db_run(zpm, in, note);
+}
+
+void zpm_note_unack(struct zpm *zpm, int64_t note) {
+       char *in = "update notes set ack = 0 where id = %" PRId64;
+       zpm_db_run(zpm, in, note);
+}
+
+void zpm_note_del(struct zpm *zpm, int64_t note) {
+       char *in = "delete from notes where id = %" PRId64;
+       zpm_db_run(zpm, in, note);
+}
+
+static char *colstring(sqlite3_stmt *s, int col) {
+       const char *val;
+       char *dup = 0;
+
+       val = (const char *)sqlite3_column_text(s, col);
+       if (val) {
+               dup = strdup(val);
+       }
+       return dup;
+}
+
+/* normally unacked only */
+/* 0x1 = next note,
+ * 0x2 = include acked
+ * 0x4 = suppress unack, implies 0x2
+ */
+/* TODO filter on pkgid/path/hash if not null */
+int64_t zpm_note(struct zpm *zpm, struct zpm_note *n, unsigned int flags) {
+       char *op = "=", *ack = " and ack = 0";
+
+       sqlite3_stmt *st;
+       int64_t id = 0;
+
+       if (flags & 0x1) {
+               op = ">";
+       }
+
+       if (flags & 0x4) {
+               ack = " and ack = 1";
+       } else if (flags & 0x2) {
+               ack = "";
+       }
+
+       st = zpm_dbquery(zpm, "select id,ts,note,pkgid,path,file,ack "
+                       "from notes where id %s %" PRId64 "%s %s",
+                       op, n->id, ack);
+
+       switch (sqlite3_step(st)) {
+               case SQLITE_DONE: /* not found */
+                       break;
+               case SQLITE_ROW:
+                       n->note = colstring(st, 2);
+                       n->pkgid = colstring(st, 3);
+                       n->path = colstring(st, 4);
+                       n->file = colstring(st, 5);
+                       n->ack = sqlite3_column_int(st, 6);
+                       n->ts = sqlite3_column_int(st, 1);
+                       n->id = sqlite3_column_int64(st, 0);
+                       id = n->id;
+                       break;
+               default: zpm->error = 1;
+                        zpm->errmsg = strdup(sqlite3_errmsg(zpm->db));
+                        break;
+       }
+
+       return id;
+}
+
+/* free any memory */
+void zpm_note_free(struct zpm_note *n) {
+       free(n->note);
+       free(n->pkgid);
+       free(n->path);
+       free(n->file);
+}
+
+int zpm_notes_available(struct zpm *zpm, int flags) {
+       int total;
+       char *sql;
+
+       if (!flags) {
+               sql = "select count(*) from notes where ack = 0";
+       } else {
+               sql = "select count(*) from notes";
+       }
+
+       total = zpm_db_int(zpm, sql);
+       return total;
+}
+
+/* get up to n notes following.  return total number of notes found */
+/* set the first note id to the id before the first one you want
+ * or to 0 to start at the beginning.  This can then
+ * be iterated up to n notes at a time by setting the id of the
+ * first one to the id found in the last one.
+ */
+int zpm_notes(struct zpm *zpm, int n, struct zpm_note *note) {
+       int64_t id;
+       int i;
+
+       for (i = 0; i < n; i++) {
+               id = zpm_note(zpm, note, 1);
+               if (!id) {
+                       break;
+               }
+               note++;
+               if (i < 0) {
+                       note->id = id;
+               }
+       }
+
+       return i;
+}
+
+int64_t zpm_note_next(struct zpm *zpm, struct zpm_note *n) {
+       return zpm_note(zpm, n, 1);
+}
+
+int64_t zpm_note_add(struct zpm *zpm, char *pkgid, char *path, char *filehash,
+               char *notefmt, ...) {
+       sqlite3_stmt *st;
+       char *note;
+       va_list ap;
+       int64_t id = 0;
+       char *in = "insert into notes (note,pkgid,path,file) values (?,?,?,?);";
+
+       if (!notefmt) {
+               return 0;
+       }
+
+       st = zpm_dbquery(zpm, in);
+
+       if (!st) {
+               zpm->error = 1;
+               zpm->errmsg = strdup(sqlite3_errmsg(zpm->db));
+               return 0;
+       }
+
+       va_start(ap, notefmt);
+       note = sqlite3_vmprintf(notefmt, ap);
+       va_end(ap);
+
+       if (!note) {
+               zpm->error = 1;
+               zpm_seterror(zpm, "can't alloc");
+       }
+
+       sqlite3_bind_text(st, 1, note, -1, SQLITE_STATIC);
+       sqlite3_bind_text(st, 2, pkgid, -1, SQLITE_STATIC);
+       sqlite3_bind_text(st, 3, path, -1, SQLITE_STATIC);
+       sqlite3_bind_text(st, 4, filehash, -1, SQLITE_STATIC);
+
+       switch (sqlite3_step(st)) {
+               case SQLITE_DONE:
+                       id = sqlite3_last_insert_rowid(zpm->db);
+                       break;
+               default: zpm->error = 1;
+                        zpm->errmsg = strdup(sqlite3_errmsg(zpm->db));
+                        break;
+       }
+
+       sqlite3_finalize(st);
+       sqlite3_free(note);
+       return id;
+}
diff --git a/lib/seterror.c b/lib/seterror.c
new file mode 100644 (file)
index 0000000..337c722
--- /dev/null
@@ -0,0 +1,31 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "zpm.h"
+
+void zpm_seterror(struct zpm *zpm, char *msgfmt, ...) {
+       char msg[1024];
+       va_list ap;
+
+       if (zpm->errmsg) {
+               free(zpm->errmsg);
+               zpm->errmsg = 0;
+       }
+
+       if (msgfmt != NULL) {
+               va_start(ap, msgfmt);
+               vsnprintf(msg, sizeof msg, msgfmt, ap);
+               va_end(ap);
+
+               msg[1023] = 0;
+               if (zpm->errmsg) {
+                       free(zpm->errmsg);
+               }
+
+               zpm->errmsg = strdup(msg);
+       }
+}
diff --git a/zpm-note b/zpm-note
deleted file mode 100755 (executable)
index f78bdd8..0000000
--- a/zpm-note
+++ /dev/null
@@ -1,147 +0,0 @@
-#!/bin/sh
-
-# Admin notes:
-# 
-# Each note is just a file.  Stored under /var/spool/admin/notes/[open|ack]/<package>/<note>
-# 
-# note: list notes
-# note ack <note> - moves note to "acknowledged" spool
-# note list [package] show notes for a given package, or all notes
-# note delete <note> - delete a note from the system
-# note edit <package> [file] - edit or create a note
-
-# TODO
-# discard unchanged new note file
-# quiet options to suppress new note name echo
-# semi-quiet to just output the number
-# renumber? to renumber all notes/reset sequence
-# lock the temp files
-# clean up unlocked temp files
-
-: ${ZPMSPOOL:=/var/lib/admin/notes}
-
-OPEN=$ZPMSPOOL/open
-
-set -e
-
-umask 007
-
-#cd $SPOOL || { echo "can't chdir to $SPOOL" ; exit 1; }
-
-[ -z "$1" ] && set list
-
-quiet=
-
-cmd=$1
-shift
-
-findnote() {
-       file=$(find $ZPMSPOOL -type f -name "$1")
-       if [ -z "$file" ] ; then
-               [ -z "$quiet" ] || printf "no such note $1\n" 1>&2
-               exit 1
-       fi
-       echo $file
-}
-
-findopen() {
-       file=$(find $ZPMSPOOL/open -type f -name "$1")
-       if [ -z "$file" ] ; then
-               [ -z "$quiet" ] || printf "no such open note $1\n" 1>&2
-               exit 1
-       fi
-       echo $file
-}
-
-case $cmd in
-       category)
-               notefile=$(findnote $1)
-               printf "%s\n" $(basename $(dirname $notefile))
-               ;;
-       list)
-               case $1 in
-                       -a) find $ZPMSPOOL/ack -type f -printf '%P\n' | sort -n
-                               ;;
-                       ?*) if [ -d $ZPMSPOOL/open/$1 ] ; then
-                               find $ZPMSPOOL/open/$1 -type f -printf '%P\n' | sort -n
-                       else
-                               exit 1
-                       fi
-                               ;;
-                       *) find $ZPMSPOOL/open -type f -printf '%P\n' | sort -n
-                               ;;
-               esac
-               ;;
-       detail)
-               len=$(find $ZPMSPOOL/open -type f -printf "%P\n" | awk ' { if ( length > x ) { x = length } }END{ print x }')
-               find $ZPMSPOOL/open -type f -printf "%P\n" | sort -n | while read note ; do
-                       subject=$(head -1 $ZPMSPOOL/open/$note) 
-                       date=$(stat -c '%y' $ZPMSPOOL/open/$note | cut -f1 -d' ')
-                       owner=$(stat -c '%U' $ZPMSPOOL/open/$note)
-                       printf '%*s %8s %s %s\n' $len $note $owner "$date" "$subject"
-               done
-               ;;
-       ack)
-               file=$(findopen $1)
-               subfile=$(echo $file | sed -e "s|$ZPMSPOOL/open/||")
-               filedir=$(dirname $subfile)
-               mkdir -p $ZPMSPOOL/ack/$filedir
-               mv $file $ZPMSPOOL/ack/$filedir
-               ;;
-       new)
-               # new -- edit a new file for package general (or ZPMNOTEPACKAGE)
-               # new package -- edit a new note for package
-               # new package file -- use file for new package note
-               if [ $# -eq 0 ]; then set ${ZPMNOTEPACKAGE:-general}; fi
-
-               # edit a new file for the note
-               if [ $# -eq 1 ]; then
-                       tmp=$(mktemp -p $ZPMSPOOL/open)
-                       pkg=$1
-                       [ -f $ZPMSPOOL/.template ] && cp $ZPMSPOOL/.template $tmp
-                       #flock -n -E3 $tmp vim $tmp
-                       #if [ $? -eq 3 ]; then echo already editing $1; exit 1; fi
-                       ${EDITOR:-vi} $tmp
-               else
-                       # take note from file or stdin
-                       pkg=$1 ; shift
-                       mkdir -p $ZPMSPOOL/open/$pkg
-                       case $1 in
-                               '-')
-                                       tmp=$(mktemp -p $ZPMSPOOL/open)
-                                       cat - > $tmp
-                                       ;;
-                               *)
-                                       tmp=$(mktemp -p $ZPMSPOOL/open)
-                                       cp $1 $tmp
-                                       ;;
-                       esac
-               fi
-               file=$(zpm sequence notes)
-               mkdir -p $ZPMSPOOL/open/$pkg
-               mv $tmp $ZPMSPOOL/open/$pkg/$file || { rm -f $tmp; exit 1; }
-               # TODO run newhooks in $ZPMSPOOL/.hook/newnote
-               echo "$pkg/$file"
-               exit 0
-               ;;
-       edit)
-               file=$(findnote $1)
-               flock -n -E3 $file vim $file
-               if [ $? -eq 3 ]; then echo already editing $1; exit 1; fi
-               ;;
-       resolve)
-               file=$(findnote $1)
-               echo $file
-               ;;
-       remove)
-               file=$(findnote $1)
-               rm $file
-               ;;
-       show)
-               file=$(findnote $1)
-               ${PAGER:-less} $file
-               ;;
-       *)
-               echo '$0: unknown command ' $cmd 1>&2
-               exit 1
-esac
index 935e71509f2591ae20cc3a9801c22548c0a53ae1..d2847cf2387f295b9e2d393e94dcd8e29189cbca 100644 (file)
@@ -40,11 +40,12 @@ struct nitem {
        gid_t gid;
        char *dest;
        char *path;
        gid_t gid;
        char *dest;
        char *path;
-       char *hash;
+       char *hash, *ohash;
        char *target;
        time_t mtime;
        mode_t mode;
        int ftype;
        char *target;
        time_t mtime;
        mode_t mode;
        int ftype;
+       int configuration;
        struct timespec times[2];
 };
 
        struct timespec times[2];
 };
 
@@ -285,6 +286,7 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) {
        struct config *conf = f;
        char *dest;
        struct stat st;
        struct config *conf = f;
        char *dest;
        struct stat st;
+       int flags = 0;
 
        dest = COL("dest");
        if (!dest) return seterror(conf,"no file dest");
 
        dest = COL("dest");
        if (!dest) return seterror(conf,"no file dest");
@@ -306,21 +308,22 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) {
        }
 
        if (S_ISDIR(st.st_mode)) {
        }
 
        if (S_ISDIR(st.st_mode)) {
-               if (conf->verbose) {
-                       fprintf(stderr, "rmdir(%s)\n", dest);
-               }
-               rmdir(dest);
-       } else if (S_ISREG(st.st_mode)) {
-               /* TODO conf to import before removal */
-               if (conf->verbose) {
-                       fprintf(stderr, "unlink(%s)\n", dest);
-               }
-               if (unlink(dest) == -1) {
-                       return seterror(conf, "can't unlink");
-               }
-       } else {
-               if (unlink(dest) == -1) {
-                       return seterror(conf, "can't unlink");
+               flags = AT_REMOVEDIR;
+       }
+       /* TODO check that expected filetype matches actual filetype */
+
+       if (conf->verbose) {
+               fprintf(stderr, "%s(%s)\n", flags ? "rmdir" : "unlink", dest);
+       }
+
+       errno = 0;
+
+       if (unlinkat(AT_FDCWD, dest, flags) == -1) {
+               switch (errno) {
+                       case ENOENT:
+                               break;
+                       default:
+                               return seterror(conf, "can't unlink");
                }
        }
        
                }
        }
        
@@ -339,6 +342,7 @@ static int remove_files(void *f, int ncols, char **vals, char **cols) {
 #define D_GID 0x80
 #define D_MODE 0x100
 #define D_MTIME 0x200
 #define D_GID 0x80
 #define D_MODE 0x100
 #define D_MTIME 0x200
+#define D_OHASH 0x400
 #define D_ERROR 0x1000
 #define D_STATERROR 0x2000
 #define D_RLERROR 0x4000
 #define D_ERROR 0x1000
 #define D_STATERROR 0x2000
 #define D_RLERROR 0x4000
@@ -376,6 +380,9 @@ static unsigned int file_compare(struct nitem *n, struct stat *st) {
                        if (strcmp(n->hash, ehash) != 0) {
                                diff |= D_HASH;
                        }
                        if (strcmp(n->hash, ehash) != 0) {
                                diff |= D_HASH;
                        }
+                       if (n->ohash && strcmp(n->ohash, ehash) != 0) {
+                               diff |= D_OHASH;
+                       }
                }
                if (n->hash && etype == S_IFLNK && stat_type == S_IFLNK) {
                        lsize = readlink(n->dest, link, sizeof link);
                }
                if (n->hash && etype == S_IFLNK && stat_type == S_IFLNK) {
                        lsize = readlink(n->dest, link, sizeof link);
@@ -460,6 +467,13 @@ static int read_item(struct config *conf, int ncols, char **vals, char **cols,
 
        n->mode = strtoul(val, NULL, 8);
 
 
        n->mode = strtoul(val, NULL, 8);
 
+       val = COL("configuration");
+       if (!val) {
+               seterror(conf, "can't determine config status");
+               return 0;
+       }
+       n->configuration = strtoul(val, NULL, 10);
+
        val = COL("filetype");
        if (!val || strlen(val) == 0) {
                seterror(conf, "can't determine file type");
        val = COL("filetype");
        if (!val || strlen(val) == 0) {
                seterror(conf, "can't determine file type");
@@ -467,6 +481,8 @@ static int read_item(struct config *conf, int ncols, char **vals, char **cols,
        }
        n->ftype = *val;
 
        }
        n->ftype = *val;
 
+       n->ohash = COL("hash");
+
        if (n->ftype == 'r') {
                n->hash = COL("hash");
                if (!n->hash) {
        if (n->ftype == 'r') {
                n->hash = COL("hash");
                if (!n->hash) {
@@ -601,6 +617,12 @@ static int set_md(struct config *conf, struct nitem *item) {
 /* flags: 1 = set md, 2 = create leading dirs, 4 = unlink existing file,
  * 8 = rmdir existing dir, 16 = return true/false
  */
 /* flags: 1 = set md, 2 = create leading dirs, 4 = unlink existing file,
  * 8 = rmdir existing dir, 16 = return true/false
  */
+#define INS_MD 0x1
+#define INS_CLD 0x2
+#define INS_UNLINK 0x4
+#define INS_RMDIR 0x8
+#define INS_RTF 0x10
+#define INS_ZPMNEW 0x20
 static int install(struct config *conf, struct nitem *item, unsigned int flags) {
        int rv = 1;
        struct zpm *source;
 static int install(struct config *conf, struct nitem *item, unsigned int flags) {
        int rv = 1;
        struct zpm *source;
@@ -686,6 +708,7 @@ static int install_files(void *f, int ncols, char **vals, char **cols) {
        struct nitem nitem;
        struct stat existing;
        int update = 0;
        struct nitem nitem;
        struct stat existing;
        int update = 0;
+       char dest[4096];
 
        /* TODO put the result row in a hash table.  May not actually
         * be faster
 
        /* TODO put the result row in a hash table.  May not actually
         * be faster
@@ -747,6 +770,22 @@ static int install_files(void *f, int ncols, char **vals, char **cols) {
                        return install(conf, &nitem, 3);
                }
 
                        return install(conf, &nitem, 3);
                }
 
+               if (nitem.configuration) {
+                       /* ohash == nhash, not an update */
+                       /* fhash == ohash, just update */
+                       /* fhash != ohash, install as dest.zpmnew, warn */
+                       /* TODO handle replacing config file
+                        * with config directory */
+                       if (diffs & D_OHASH) {
+                               if (strlen(nitem.dest) > sizeof dest - 8) {
+                                       return seterror(conf,"config file path too long for install as %s.zpmnew", nitem.dest);
+                               }
+                               fprintf(stderr, "installing as .zpmnew\n");
+                               sprintf(dest, "%s.zpmnew", nitem.dest);
+                               nitem.dest = dest;
+                       }
+               }
+
                /* file exists in filesystem */
                if (sametype) {
                        if (mdsame && hashsame) {
                /* file exists in filesystem */
                if (sametype) {
                        if (mdsame && hashsame) {
diff --git a/zpm.h b/zpm.h
index 64e5ac63ec9c49437cc2b4da2310111aa724d85c..c7144649940bfd6bbf8008732a480d4f646a85ef 100644 (file)
--- a/zpm.h
+++ b/zpm.h
@@ -176,6 +176,7 @@ int zpm_foreach_path(struct zpm *zpm, char *pkgid, char *where,
 int (*callback)(void *f, int ncols, char **vals, char **cols),
 void *data, char **errmsg);
 
 int (*callback)(void *f, int ncols, char **vals, char **cols),
 void *data, char **errmsg);
 
+
 int zpm_script_hash(struct zpm *zpm, char *pkgstr, char *phase, char *hash);
 int zpm_package_hash(struct zpm *zpm, char *pkgid, char *hash);
 int zpm_package_sethash(struct zpm *zpm, char *pkgid, char *hash);
 int zpm_script_hash(struct zpm *zpm, char *pkgstr, char *phase, char *hash);
 int zpm_package_hash(struct zpm *zpm, char *pkgid, char *hash);
 int zpm_package_sethash(struct zpm *zpm, char *pkgid, char *hash);
@@ -183,7 +184,32 @@ int zpm_package_sethash(struct zpm *zpm, char *pkgid, char *hash);
 sqlite3_stmt *zpm_dbqueryv(struct zpm *zpm, char *query, va_list args);
 sqlite3_stmt *zpm_dbquery(struct zpm *zpm, char *query, ...);
 char *zpm_db_string(struct zpm *zpm, char *query, ...);
 sqlite3_stmt *zpm_dbqueryv(struct zpm *zpm, char *query, va_list args);
 sqlite3_stmt *zpm_dbquery(struct zpm *zpm, char *query, ...);
 char *zpm_db_string(struct zpm *zpm, char *query, ...);
+int zpm_db_int(struct zpm *zpm, char *query, ...);
+void zpm_db_run(struct zpm *zpm, char *query, ...);
+void zpm_seterror(struct zpm *zpm, char *msgfmt, ...);
 
 struct zpm *zpm_clearmem(struct zpm *zpm);
 
 
 struct zpm *zpm_clearmem(struct zpm *zpm);
 
+struct zpm_note {
+       int64_t id;
+       time_t ts; /* or timespec */
+       char *note;
+       char *pkgid;
+       char *path;
+       char *file;
+       char *hash;
+       int ack;
+};
+
+void zpm_note_ack(struct zpm *zpm, int64_t note);
+void zpm_note_unack(struct zpm *zpm, int64_t note);
+void zpm_note_del(struct zpm *zpm, int64_t note);
+int64_t zpm_note(struct zpm *zpm, struct zpm_note *n, unsigned int flags);
+void zpm_note_free(struct zpm_note *n);
+int zpm_notes(struct zpm *zpm, int n, struct zpm_note *note);
+int64_t zpm_note_next(struct zpm *zpm, struct zpm_note *n);
+int64_t zpm_note_add(struct zpm *zpm, char *pkgid, char *path, char *filehash,
+               char *notefmt, ...);
+int zpm_notes_available(struct zpm *zpm, int flags);
+
 #endif
 #endif