updatedb.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * generate a list of files and their metadata
  3. * using a given proto file.
  4. */
  5. #include "all.h"
  6. int changesonly;
  7. char *uid;
  8. Db *db;
  9. Biobuf blog;
  10. ulong now;
  11. int n;
  12. char **x;
  13. int nx;
  14. int justlog;
  15. char *root=".";
  16. char **match;
  17. int nmatch;
  18. int
  19. ismatch(char *s)
  20. {
  21. int i, len;
  22. if(nmatch == 0)
  23. return 1;
  24. for(i=0; i<nmatch; i++){
  25. if(strcmp(s, match[i]) == 0)
  26. return 1;
  27. len = strlen(match[i]);
  28. if(strncmp(s, match[i], len) == 0 && s[len]=='/')
  29. return 1;
  30. }
  31. return 0;
  32. }
  33. void
  34. xlog(int c, char *name, Dir *d)
  35. {
  36. char *dname;
  37. dname = d->name;
  38. if(strcmp(dname, name) == 0)
  39. dname = "-";
  40. if(!justlog)
  41. Bprint(&blog, "%lud %d ", now, n++);
  42. Bprint(&blog, "%c %q %q %luo %q %q %lud %lld\n",
  43. c, name, dname, d->mode, uid ? uid : d->uid, d->gid, d->mtime, d->length);
  44. }
  45. void
  46. walk(char *new, char *old, Dir *xd, void*)
  47. {
  48. int i, change, len;
  49. Dir od, d;
  50. new = unroot(new, "/");
  51. old = unroot(old, root);
  52. if(!ismatch(new))
  53. return;
  54. for(i=0; i<nx; i++){
  55. if(strcmp(new, x[i]) == 0)
  56. return;
  57. len = strlen(x[i]);
  58. if(strncmp(new, x[i], len)==0 && new[len]=='/')
  59. return;
  60. }
  61. d = *xd;
  62. d.name = old;
  63. memset(&od, 0, sizeof od);
  64. change = 0;
  65. if(markdb(db, new, &od) < 0){
  66. if(!changesonly){
  67. xlog('a', new, &d);
  68. change = 1;
  69. }
  70. }else{
  71. if((d.mode&DMDIR)==0 && (od.mtime!=d.mtime || od.length!=d.length)){
  72. xlog('c', new, &d);
  73. change = 1;
  74. }
  75. if((!uid&&strcmp(od.uid,d.uid)!=0)
  76. || strcmp(od.gid,d.gid)!=0
  77. || od.mode!=d.mode){
  78. xlog('m', new, &d);
  79. change = 1;
  80. }
  81. }
  82. if(!justlog && change){
  83. if(uid)
  84. d.uid = uid;
  85. d.muid = "mark"; /* mark bit */
  86. insertdb(db, new, &d);
  87. }
  88. }
  89. void
  90. warn(char *msg, void*)
  91. {
  92. char *p;
  93. fprint(2, "warning: %s\n", msg);
  94. /* find the %r in "can't open foo: %r" */
  95. p = strstr(msg, ": ");
  96. if(p)
  97. p += 2;
  98. /*
  99. * if the error is about a remote server failing,
  100. * then there's no point in continuing to look
  101. * for changes -- we'll think everything got deleted!
  102. *
  103. * actual errors i see are:
  104. * "i/o on hungup channel" for a local hangup
  105. * "i/o on hungup channel" for a timeout (yank the network wire)
  106. * "'/n/sources/plan9' Hangup" for a remote hangup
  107. * the rest is paranoia.
  108. */
  109. if(p){
  110. if(cistrstr(p, "hungup") || cistrstr(p, "Hangup")
  111. || cistrstr(p, "rpc error")
  112. || cistrstr(p, "shut down")
  113. || cistrstr(p, "i/o")
  114. || cistrstr(p, "connection"))
  115. sysfatal("suspected network or i/o error - bailing out");
  116. }
  117. }
  118. void
  119. usage(void)
  120. {
  121. fprint(2, "usage: replica/updatedb [-c] [-p proto] [-r root] [-t now n] [-u uid] [-x path]... db [paths]\n");
  122. exits("usage");
  123. }
  124. void
  125. main(int argc, char **argv)
  126. {
  127. char *proto;
  128. Avlwalk *w;
  129. Dir d;
  130. Entry *e;
  131. quotefmtinstall();
  132. proto = "/sys/lib/sysconfig/proto/allproto";
  133. now = time(0);
  134. Binit(&blog, 1, OWRITE);
  135. ARGBEGIN{
  136. case 'c':
  137. changesonly = 1;
  138. break;
  139. case 'l':
  140. justlog = 1;
  141. break;
  142. case 'p':
  143. proto = EARGF(usage());
  144. break;
  145. case 'r':
  146. root = EARGF(usage());
  147. break;
  148. case 't':
  149. now = strtoul(EARGF(usage()), 0, 0);
  150. n = atoi(EARGF(usage()));
  151. break;
  152. case 'u':
  153. uid = EARGF(usage());
  154. break;
  155. case 'x':
  156. if(nx%16 == 0)
  157. x = erealloc(x, (nx+16)*sizeof(x[0]));
  158. x[nx++] = EARGF(usage());
  159. break;
  160. default:
  161. usage();
  162. }ARGEND
  163. if(argc <1)
  164. usage();
  165. match = argv+1;
  166. nmatch = argc-1;
  167. db = opendb(argv[0]);
  168. if(rdproto(proto, root, walk, warn, nil) < 0)
  169. sysfatal("rdproto: %r");
  170. if(!changesonly){
  171. w = avlwalk(db->avl);
  172. while(e = (Entry*)avlprev(w)){
  173. if(!ismatch(e->name))
  174. continue;
  175. if(!e->d.mark){ /* not visited during walk */
  176. memset(&d, 0, sizeof d);
  177. d.name = e->d.name;
  178. d.uid = e->d.uid;
  179. d.gid = e->d.gid;
  180. d.mtime = e->d.mtime;
  181. d.mode = e->d.mode;
  182. xlog('d', e->name, &d);
  183. if(!justlog)
  184. removedb(db, e->name);
  185. }
  186. }
  187. }
  188. if(Bterm(&blog) < 0)
  189. sysfatal("writing output: %r");
  190. exits(nil);
  191. }