ref: fe1eb39db7ae6904924f3ab1f6f9b34416f2eb1b
dir: /sys/src/cmd/replica/updatedb.c/
/* * 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; 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){ for(e = (Entry*)avlmax(db->avl); e != nil; e = (Entry*)avlprev(e)){ 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); }