summaryrefslogtreecommitdiff
path: root/sys/src/cmd/replica/updatedb.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/replica/updatedb.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/replica/updatedb.c')
-rwxr-xr-xsys/src/cmd/replica/updatedb.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/sys/src/cmd/replica/updatedb.c b/sys/src/cmd/replica/updatedb.c
new file mode 100755
index 000000000..d63a53c0f
--- /dev/null
+++ b/sys/src/cmd/replica/updatedb.c
@@ -0,0 +1,214 @@
+/*
+ * generate a list of files and their metadata
+ * using a given proto file.
+ */
+#include "all.h"
+
+int changesonly;
+char *uid;
+Db *db;
+Biobuf blog;
+ulong now;
+int n;
+char **x;
+int nx;
+int justlog;
+char *root=".";
+char **match;
+int nmatch;
+
+int
+ismatch(char *s)
+{
+ int i, len;
+
+ if(nmatch == 0)
+ return 1;
+ for(i=0; i<nmatch; i++){
+ if(strcmp(s, match[i]) == 0)
+ return 1;
+ len = strlen(match[i]);
+ if(strncmp(s, match[i], len) == 0 && s[len]=='/')
+ return 1;
+ }
+ return 0;
+}
+
+void
+xlog(int c, char *name, Dir *d)
+{
+ char *dname;
+
+ dname = d->name;
+ if(strcmp(dname, name) == 0)
+ dname = "-";
+ if(!justlog)
+ Bprint(&blog, "%lud %d ", now, n++);
+ Bprint(&blog, "%c %q %q %luo %q %q %lud %lld\n",
+ c, name, dname, d->mode, uid ? uid : d->uid, d->gid, d->mtime, d->length);
+}
+
+void
+walk(char *new, char *old, Dir *xd, void*)
+{
+ int i, change, len;
+ Dir od, d;
+
+ new = unroot(new, "/");
+ old = unroot(old, root);
+
+ if(!ismatch(new))
+ return;
+ for(i=0; i<nx; i++){
+ if(strcmp(new, x[i]) == 0)
+ return;
+ len = strlen(x[i]);
+ if(strncmp(new, x[i], len)==0 && new[len]=='/')
+ return;
+ }
+
+ d = *xd;
+ d.name = old;
+ memset(&od, 0, sizeof od);
+ change = 0;
+ if(markdb(db, new, &od) < 0){
+ if(!changesonly){
+ xlog('a', new, &d);
+ change = 1;
+ }
+ }else{
+ if((d.mode&DMDIR)==0 && (od.mtime!=d.mtime || od.length!=d.length)){
+ xlog('c', new, &d);
+ change = 1;
+ }
+ if((!uid&&strcmp(od.uid,d.uid)!=0)
+ || strcmp(od.gid,d.gid)!=0
+ || od.mode!=d.mode){
+ xlog('m', new, &d);
+ change = 1;
+ }
+ }
+ if(!justlog && change){
+ if(uid)
+ d.uid = uid;
+ d.muid = "mark"; /* mark bit */
+ insertdb(db, new, &d);
+ }
+}
+
+void
+warn(char *msg, void*)
+{
+ char *p;
+
+ fprint(2, "warning: %s\n", msg);
+
+ /* find the %r in "can't open foo: %r" */
+ p = strstr(msg, ": ");
+ if(p)
+ p += 2;
+
+ /*
+ * if the error is about a remote server failing,
+ * then there's no point in continuing to look
+ * for changes -- we'll think everything got deleted!
+ *
+ * actual errors i see are:
+ * "i/o on hungup channel" for a local hangup
+ * "i/o on hungup channel" for a timeout (yank the network wire)
+ * "'/n/sources/plan9' Hangup" for a remote hangup
+ * the rest is paranoia.
+ */
+ if(p){
+ if(cistrstr(p, "hungup") || cistrstr(p, "Hangup")
+ || cistrstr(p, "rpc error")
+ || cistrstr(p, "shut down")
+ || cistrstr(p, "i/o")
+ || cistrstr(p, "connection"))
+ sysfatal("suspected network or i/o error - bailing out");
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: replica/updatedb [-c] [-p proto] [-r root] [-t now n] [-u uid] [-x path]... db [paths]\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ char *proto;
+ Avlwalk *w;
+ Dir d;
+ Entry *e;
+
+ quotefmtinstall();
+ proto = "/sys/lib/sysconfig/proto/allproto";
+ now = time(0);
+ Binit(&blog, 1, OWRITE);
+ ARGBEGIN{
+ case 'c':
+ changesonly = 1;
+ break;
+ case 'l':
+ justlog = 1;
+ break;
+ case 'p':
+ proto = EARGF(usage());
+ break;
+ case 'r':
+ root = EARGF(usage());
+ break;
+ case 't':
+ now = strtoul(EARGF(usage()), 0, 0);
+ n = atoi(EARGF(usage()));
+ break;
+ case 'u':
+ uid = EARGF(usage());
+ break;
+ case 'x':
+ if(nx%16 == 0)
+ x = erealloc(x, (nx+16)*sizeof(x[0]));
+ x[nx++] = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc <1)
+ usage();
+
+ match = argv+1;
+ nmatch = argc-1;
+
+ db = opendb(argv[0]);
+ if(rdproto(proto, root, walk, warn, nil) < 0)
+ sysfatal("rdproto: %r");
+
+ if(!changesonly){
+ w = avlwalk(db->avl);
+ while(e = (Entry*)avlprev(w)){
+ if(!ismatch(e->name))
+ continue;
+ if(!e->d.mark){ /* not visited during walk */
+ memset(&d, 0, sizeof d);
+ d.name = e->d.name;
+ d.uid = e->d.uid;
+ d.gid = e->d.gid;
+ d.mtime = e->d.mtime;
+ d.mode = e->d.mode;
+ xlog('d', e->name, &d);
+ if(!justlog)
+ removedb(db, e->name);
+ }
+ }
+ }
+
+ if(Bterm(&blog) < 0)
+ sysfatal("writing output: %r");
+
+ exits(nil);
+}
+