diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /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-x | sys/src/cmd/replica/updatedb.c | 214 |
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); +} + |