applylog.c 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. #include "all.h"
  2. #define Nwork 16
  3. int localdirstat(char*, Dir*);
  4. int ismatch(char*);
  5. void conflict(char*, char*, ...);
  6. void error(char*, ...);
  7. int isdir(char*);
  8. void worker(int fdf, int fdt, char *from, char *to);
  9. vlong nextoff(void);
  10. void failure(void *, char *note);
  11. QLock lk;
  12. vlong off;
  13. int errors;
  14. int nconf;
  15. int donothing;
  16. char **conf;
  17. int verbose;
  18. char **match;
  19. int nmatch;
  20. int tempspool = 1;
  21. int safeinstall = 1;
  22. char *lroot;
  23. char *rroot;
  24. Db *clientdb;
  25. int skip;
  26. int douid;
  27. char *mkname(char*, int, char*, char*);
  28. char localbuf[10240];
  29. char remotebuf[10240];
  30. int copyfile(char*, char*, char*, Dir*, int, int*);
  31. ulong maxnow;
  32. int maxn;
  33. char *timefile;
  34. int timefd;
  35. Db *copyerr;
  36. typedef struct Res Res;
  37. struct Res
  38. {
  39. char c;
  40. char *name;
  41. };
  42. Res *res;
  43. int nres;
  44. void
  45. addresolve(int c, char *name)
  46. {
  47. if(name[0] == '/')
  48. name++;
  49. res = erealloc(res, (nres+1)*sizeof res[0]);
  50. res[nres].c = c;
  51. res[nres].name = name;
  52. nres++;
  53. }
  54. int
  55. resolve(char *name)
  56. {
  57. int i, len;
  58. for(i=0; i<nres; i++){
  59. len = strlen(res[i].name);
  60. if(len == 0)
  61. return res[i].c;
  62. if(strncmp(name, res[i].name, len) == 0 && (name[len]=='/' || name[len] == 0))
  63. return res[i].c;
  64. }
  65. return '?';
  66. }
  67. void
  68. readtimefile(void)
  69. {
  70. int n;
  71. char buf[24];
  72. if((timefd = open(timefile, ORDWR)) < 0
  73. && (timefd = create(timefile, ORDWR|OEXCL, 0666)) < 0)
  74. return;
  75. n = readn(timefd, buf, sizeof buf);
  76. if(n < sizeof buf)
  77. return;
  78. maxnow = atoi(buf);
  79. maxn = atoi(buf+12);
  80. }
  81. void
  82. writetimefile(void)
  83. {
  84. char buf[24+1];
  85. snprint(buf, sizeof buf, "%11lud %11d ", maxnow, maxn);
  86. pwrite(timefd, buf, 24, 0);
  87. }
  88. static void membogus(char**);
  89. void
  90. addce(char *local)
  91. {
  92. char e[ERRMAX];
  93. Dir d;
  94. memset(&d, 0, sizeof d);
  95. rerrstr(e, sizeof e);
  96. d.name = atom(e);
  97. d.uid = "";
  98. d.gid = "";
  99. insertdb(copyerr, atom(local), &d);
  100. }
  101. void
  102. delce(char *local)
  103. {
  104. removedb(copyerr, local);
  105. }
  106. void
  107. chat(char *f, ...)
  108. {
  109. Fmt fmt;
  110. char buf[256];
  111. va_list arg;
  112. if(!verbose)
  113. return;
  114. fmtfdinit(&fmt, 1, buf, sizeof buf);
  115. va_start(arg, f);
  116. fmtvprint(&fmt, f, arg);
  117. va_end(arg);
  118. fmtfdflush(&fmt);
  119. }
  120. void
  121. usage(void)
  122. {
  123. fprint(2, "usage: replica/applylog [-cnSstuv] [-T timefile] clientdb clientroot serverroot [path ...]\n");
  124. exits("usage");
  125. }
  126. int
  127. notexists(char *path)
  128. {
  129. char buf[ERRMAX];
  130. if(access(path, AEXIST) >= 0)
  131. return 0;
  132. rerrstr(buf, sizeof buf);
  133. if(strstr(buf, "entry not found") || strstr(buf, "not exist"))
  134. return 1;
  135. /* some other error, like network hangup */
  136. return 0;
  137. }
  138. void
  139. main(int argc, char **argv)
  140. {
  141. char *f[10], *local, *name, *remote, *s, *t, verb;
  142. int fd, havedb, havelocal, i, k, n, nf, resolve1, skip;
  143. int checkedmatch1, checkedmatch2,
  144. checkedmatch3, checkedmatch4;
  145. ulong now;
  146. Biobuf bin;
  147. Dir dbd, ld, nd, rd;
  148. Avlwalk *w;
  149. Entry *e;
  150. membogus(argv);
  151. quotefmtinstall();
  152. ARGBEGIN{
  153. case 's':
  154. case 'c':
  155. i = ARGC();
  156. addresolve(i, EARGF(usage()));
  157. break;
  158. case 'n':
  159. donothing = 1;
  160. verbose = 1;
  161. break;
  162. case 'S':
  163. safeinstall = 0;
  164. break;
  165. case 'T':
  166. timefile = EARGF(usage());
  167. break;
  168. case 't':
  169. tempspool = 0;
  170. break;
  171. case 'u':
  172. douid = 1;
  173. break;
  174. case 'v':
  175. verbose++;
  176. break;
  177. default:
  178. usage();
  179. }ARGEND
  180. if(argc < 3)
  181. usage();
  182. if(timefile)
  183. readtimefile();
  184. lroot = argv[1];
  185. if(!isdir(lroot))
  186. sysfatal("bad local root directory");
  187. rroot = argv[2];
  188. if(!isdir(rroot))
  189. sysfatal("bad remote root directory");
  190. match = argv+3;
  191. nmatch = argc-3;
  192. for(i=0; i<nmatch; i++)
  193. if(match[i][0] == '/')
  194. match[i]++;
  195. if((clientdb = opendb(argv[0])) == nil)
  196. sysfatal("opendb %q: %r", argv[2]);
  197. copyerr = opendb(nil);
  198. skip = 0;
  199. Binit(&bin, 0, OREAD);
  200. for(; s=Brdstr(&bin, '\n', 1); free(s)){
  201. t = estrdup(s);
  202. nf = tokenize(s, f, nelem(f));
  203. if(nf != 10 || strlen(f[2]) != 1){
  204. skip = 1;
  205. fprint(2, "warning: skipping bad log entry <%s>\n", t);
  206. free(t);
  207. continue;
  208. }
  209. free(t);
  210. now = strtoul(f[0], 0, 0);
  211. n = atoi(f[1]);
  212. verb = f[2][0];
  213. name = f[3];
  214. if(now < maxnow || (now==maxnow && n <= maxn))
  215. continue;
  216. local = mkname(localbuf, sizeof localbuf, lroot, name);
  217. if(strcmp(f[4], "-") == 0)
  218. f[4] = f[3];
  219. remote = mkname(remotebuf, sizeof remotebuf, rroot, f[4]);
  220. rd.name = f[4];
  221. rd.mode = strtoul(f[5], 0, 8);
  222. rd.uid = f[6];
  223. rd.gid = f[7];
  224. rd.mtime = strtoul(f[8], 0, 10);
  225. rd.length = strtoll(f[9], 0, 10);
  226. havedb = finddb(clientdb, name, &dbd)>=0;
  227. havelocal = localdirstat(local, &ld)>=0;
  228. resolve1 = resolve(name);
  229. /*
  230. * if(!ismatch(name)){
  231. * skip = 1;
  232. * continue;
  233. * }
  234. *
  235. * This check used to be right here, but we want
  236. * the time to be able to move forward past entries
  237. * that don't match and have already been applied.
  238. * So now every path below must checked !ismatch(name)
  239. * before making any changes to the local file
  240. * system. The fake variable checkedmatch
  241. * tracks whether !ismatch(name) has been checked.
  242. * If the compiler doesn't produce any used/set
  243. * warnings, then all the paths should be okay.
  244. * Even so, we have the asserts to fall back on.
  245. */
  246. switch(verb){
  247. case 'd': /* delete file */
  248. delce(local);
  249. if(!havelocal) /* doesn't exist; who cares? */
  250. break;
  251. if(!ismatch(name)){
  252. if(!skip)
  253. fprint(2, "stopped updating log apply time because of %s\n", name);
  254. skip = 1;
  255. continue;
  256. }
  257. SET(checkedmatch1);
  258. if(!havedb){
  259. if(resolve1 == 's')
  260. goto DoRemove;
  261. else if(resolve1 == 'c')
  262. goto DoRemoveDb;
  263. conflict(name, "locally created; will not remove");
  264. skip = 1;
  265. continue;
  266. }
  267. assert(havelocal && havedb);
  268. if(dbd.mtime > rd.mtime) /* we have a newer file than what was deleted */
  269. break;
  270. if(!(dbd.mode&DMDIR) && (dbd.mtime != ld.mtime || dbd.length != ld.length)){ /* locally modified since we downloaded it */
  271. if(resolve1 == 's')
  272. goto DoRemove;
  273. else if(resolve1 == 'c')
  274. break;
  275. conflict(name, "locally modified; will not remove");
  276. skip = 1;
  277. continue;
  278. }
  279. DoRemove:
  280. USED(checkedmatch1);
  281. assert(ismatch(name));
  282. chat("d %q\n", name);
  283. if(donothing)
  284. break;
  285. if(remove(local) < 0){
  286. error("removing %q", name);
  287. skip = 1;
  288. continue;
  289. }
  290. DoRemoveDb:
  291. USED(checkedmatch1);
  292. assert(ismatch(name));
  293. removedb(clientdb, name);
  294. break;
  295. case 'a': /* add file */
  296. if(!havedb){
  297. if(!ismatch(name)){
  298. if(!skip)
  299. fprint(2, "stopped updating log apply time because of %s\n", name);
  300. skip = 1;
  301. continue;
  302. }
  303. SET(checkedmatch2);
  304. if(!havelocal)
  305. goto DoCreate;
  306. if((ld.mode&DMDIR) && (rd.mode&DMDIR))
  307. break;
  308. if(resolve1 == 's')
  309. goto DoCreate;
  310. else if(resolve1 == 'c')
  311. goto DoCreateDb;
  312. conflict(name, "locally created; will not overwrite");
  313. skip = 1;
  314. continue;
  315. }
  316. assert(havedb);
  317. if(dbd.mtime >= rd.mtime) /* already created this file; ignore */
  318. break;
  319. if(havelocal){
  320. if((ld.mode&DMDIR) && (rd.mode&DMDIR))
  321. break;
  322. if(!ismatch(name)){
  323. if(!skip)
  324. fprint(2, "stopped updating log apply time because of %s\n", name);
  325. skip = 1;
  326. continue;
  327. }
  328. SET(checkedmatch2);
  329. if(dbd.mtime==ld.mtime && dbd.length==ld.length)
  330. goto DoCreate;
  331. if(resolve1=='s')
  332. goto DoCreate;
  333. else if(resolve1 == 'c')
  334. break;
  335. conflict(name, "locally modified; will not overwrite");
  336. skip = 1;
  337. continue;
  338. }
  339. if(!ismatch(name)){
  340. if(!skip)
  341. fprint(2, "stopped updating log apply time because of %s\n", name);
  342. skip = 1;
  343. continue;
  344. }
  345. SET(checkedmatch2);
  346. DoCreate:
  347. USED(checkedmatch2);
  348. assert(ismatch(name));
  349. if(notexists(remote)){
  350. addce(local);
  351. /* no skip=1 */
  352. break;;
  353. }
  354. chat("a %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime);
  355. if(donothing)
  356. break;
  357. if(rd.mode&DMDIR){
  358. if((fd = create(local, OREAD, DMDIR)) < 0){
  359. error("mkdir %q: %r", name);
  360. skip = 1;
  361. continue;
  362. }
  363. nulldir(&nd);
  364. nd.mode = rd.mode;
  365. if(dirfwstat(fd, &nd) < 0)
  366. fprint(2, "warning: cannot set mode on %q\n", local);
  367. nulldir(&nd);
  368. nd.gid = rd.gid;
  369. if(dirfwstat(fd, &nd) < 0)
  370. fprint(2, "warning: cannot set gid on %q\n", local);
  371. if(douid){
  372. nulldir(&nd);
  373. nd.uid = rd.uid;
  374. if(dirfwstat(fd, &nd) < 0)
  375. fprint(2, "warning: cannot set uid on %q\n", local);
  376. }
  377. close(fd);
  378. rd.mtime = now;
  379. }else{
  380. if(copyfile(local, remote, name, &rd, 1, &k) < 0){
  381. if(k)
  382. addce(local);
  383. skip = 1;
  384. continue;
  385. }
  386. }
  387. DoCreateDb:
  388. USED(checkedmatch2);
  389. assert(ismatch(name));
  390. insertdb(clientdb, name, &rd);
  391. break;
  392. case 'c': /* change contents */
  393. if(!havedb){
  394. if(notexists(remote)){
  395. addce(local);
  396. /* no skip=1 */
  397. break;
  398. }
  399. if(!ismatch(name)){
  400. if(!skip)
  401. fprint(2, "stopped updating log apply time because of %s\n", name);
  402. skip = 1;
  403. continue;
  404. }
  405. SET(checkedmatch3);
  406. if(resolve1 == 's')
  407. goto DoCopy;
  408. else if(resolve1=='c')
  409. goto DoCopyDb;
  410. if(havelocal)
  411. conflict(name, "locally created; will not update");
  412. else
  413. conflict(name, "not replicated; will not update");
  414. skip = 1;
  415. continue;
  416. }
  417. if(dbd.mtime >= rd.mtime) /* already have/had this version; ignore */
  418. break;
  419. if(!ismatch(name)){
  420. if(!skip)
  421. fprint(2, "stopped updating log apply time because of %s\n", name);
  422. skip = 1;
  423. continue;
  424. }
  425. SET(checkedmatch3);
  426. if(!havelocal){
  427. if(notexists(remote)){
  428. addce(local);
  429. /* no skip=1 */
  430. break;
  431. }
  432. if(resolve1 == 's')
  433. goto DoCopy;
  434. else if(resolve1 == 'c')
  435. break;
  436. conflict(name, "locally removed; will not update");
  437. skip = 1;
  438. continue;
  439. }
  440. assert(havedb && havelocal);
  441. if(dbd.mtime != ld.mtime || dbd.length != ld.length){
  442. if(notexists(remote)){
  443. addce(local);
  444. /* no skip=1 */
  445. break;
  446. }
  447. if(resolve1 == 's')
  448. goto DoCopy;
  449. else if(resolve1 == 'c')
  450. break;
  451. conflict(name, "locally modified; will not update");
  452. skip = 1;
  453. continue;
  454. }
  455. DoCopy:
  456. USED(checkedmatch3);
  457. assert(ismatch(name));
  458. if(notexists(remote)){
  459. addce(local);
  460. /* no skip=1 */
  461. break;
  462. }
  463. chat("c %q\n", name);
  464. if(donothing)
  465. break;
  466. if(copyfile(local, remote, name, &rd, 0, &k) < 0){
  467. if(k)
  468. addce(local);
  469. skip = 1;
  470. continue;
  471. }
  472. DoCopyDb:
  473. USED(checkedmatch3);
  474. assert(ismatch(name));
  475. if(!havedb){
  476. if(havelocal)
  477. dbd = ld;
  478. else
  479. dbd = rd;
  480. }
  481. dbd.mtime = rd.mtime;
  482. dbd.length = rd.length;
  483. insertdb(clientdb, name, &dbd);
  484. break;
  485. case 'm': /* change metadata */
  486. if(!havedb){
  487. if(notexists(remote)){
  488. addce(local);
  489. /* no skip=1 */
  490. break;
  491. }
  492. if(!ismatch(name)){
  493. if(!skip)
  494. fprint(2, "stopped updating log apply time because of %s\n", name);
  495. skip = 1;
  496. continue;
  497. }
  498. SET(checkedmatch4);
  499. if(resolve1 == 's'){
  500. USED(checkedmatch4);
  501. SET(checkedmatch2);
  502. goto DoCreate;
  503. }
  504. else if(resolve1 == 'c')
  505. goto DoMetaDb;
  506. if(havelocal)
  507. conflict(name, "locally created; will not update metadata");
  508. else
  509. conflict(name, "not replicated; will not update metadata");
  510. skip = 1;
  511. continue;
  512. }
  513. if(!(dbd.mode&DMDIR) && dbd.mtime > rd.mtime) /* have newer version; ignore */
  514. break;
  515. if((dbd.mode&DMDIR) && dbd.mtime > now)
  516. break;
  517. if(havelocal && (!douid || strcmp(ld.uid, rd.uid)==0) && strcmp(ld.gid, rd.gid)==0 && ld.mode==rd.mode)
  518. break;
  519. if(!havelocal){
  520. if(notexists(remote)){
  521. addce(local);
  522. /* no skip=1 */
  523. break;
  524. }
  525. if(!ismatch(name)){
  526. if(!skip)
  527. fprint(2, "stopped updating log apply time because of %s\n", name);
  528. skip = 1;
  529. continue;
  530. }
  531. SET(checkedmatch4);
  532. if(resolve1 == 's'){
  533. USED(checkedmatch4);
  534. SET(checkedmatch2);
  535. goto DoCreate;
  536. }
  537. else if(resolve1 == 'c')
  538. break;
  539. conflict(name, "locally removed; will not update metadata");
  540. skip = 1;
  541. continue;
  542. }
  543. if(!(dbd.mode&DMDIR) && (dbd.mtime != ld.mtime || dbd.length != ld.length)){ /* this check might be overkill */
  544. if(notexists(remote)){
  545. addce(local);
  546. /* no skip=1 */
  547. break;
  548. }
  549. if(!ismatch(name)){
  550. if(!skip)
  551. fprint(2, "stopped updating log apply time because of %s\n", name);
  552. skip = 1;
  553. continue;
  554. }
  555. SET(checkedmatch4);
  556. if(resolve1 == 's')
  557. goto DoMeta;
  558. else if(resolve1 == 'c')
  559. break;
  560. conflict(name, "contents locally modified (%s); will not update metadata to %s %s %luo",
  561. dbd.mtime != ld.mtime ? "mtime" :
  562. dbd.length != ld.length ? "length" :
  563. "unknown",
  564. rd.uid, rd.gid, rd.mode);
  565. skip = 1;
  566. continue;
  567. }
  568. if((douid && strcmp(ld.uid, dbd.uid)!=0) || strcmp(ld.gid, dbd.gid)!=0 || ld.mode!=dbd.mode){
  569. if(notexists(remote)){
  570. addce(local);
  571. /* no skip=1 */
  572. break;
  573. }
  574. if(!ismatch(name)){
  575. if(!skip)
  576. fprint(2, "stopped updating log apply time because of %s\n", name);
  577. skip = 1;
  578. continue;
  579. }
  580. SET(checkedmatch4);
  581. if(resolve1 == 's')
  582. goto DoMeta;
  583. else if(resolve1 == 'c')
  584. break;
  585. conflict(name, "metadata locally changed; will not update metadata to %s %s %luo", rd.uid, rd.gid, rd.mode);
  586. skip = 1;
  587. continue;
  588. }
  589. if(!ismatch(name)){
  590. if(!skip)
  591. fprint(2, "stopped updating log apply time because of %s\n", name);
  592. skip = 1;
  593. continue;
  594. }
  595. SET(checkedmatch4);
  596. DoMeta:
  597. USED(checkedmatch4);
  598. assert(ismatch(name));
  599. if(notexists(remote)){
  600. addce(local);
  601. /* no skip=1 */
  602. break;
  603. }
  604. chat("m %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime);
  605. if(donothing)
  606. break;
  607. nulldir(&nd);
  608. nd.gid = rd.gid;
  609. nd.mode = rd.mode;
  610. if(douid)
  611. nd.uid = rd.uid;
  612. if(dirwstat(local, &nd) < 0){
  613. error("dirwstat %q: %r", name);
  614. skip = 1;
  615. continue;
  616. }
  617. DoMetaDb:
  618. USED(checkedmatch4);
  619. assert(ismatch(name));
  620. if(!havedb){
  621. if(havelocal)
  622. dbd = ld;
  623. else
  624. dbd = rd;
  625. }
  626. if(dbd.mode&DMDIR)
  627. dbd.mtime = now;
  628. dbd.gid = rd.gid;
  629. dbd.mode = rd.mode;
  630. if(douid)
  631. dbd.uid = rd.uid;
  632. insertdb(clientdb, name, &dbd);
  633. break;
  634. }
  635. if(!skip && !donothing){
  636. maxnow = now;
  637. maxn = n;
  638. }
  639. }
  640. w = avlwalk(copyerr->avl);
  641. while(e = (Entry*)avlnext(w))
  642. error("copying %q: %s\n", e->name, e->d.name);
  643. if(timefile)
  644. writetimefile();
  645. if(nconf)
  646. exits("conflicts");
  647. if(errors)
  648. exits("errors");
  649. exits(nil);
  650. }
  651. char*
  652. mkname(char *buf, int nbuf, char *a, char *b)
  653. {
  654. if(strlen(a)+strlen(b)+2 > nbuf)
  655. sysfatal("name too long");
  656. strcpy(buf, a);
  657. if(a[strlen(a)-1] != '/')
  658. strcat(buf, "/");
  659. strcat(buf, b);
  660. return buf;
  661. }
  662. int
  663. isdir(char *s)
  664. {
  665. ulong m;
  666. Dir *d;
  667. if((d = dirstat(s)) == nil)
  668. return 0;
  669. m = d->mode;
  670. free(d);
  671. return (m&DMDIR) != 0;
  672. }
  673. void
  674. conflict(char *name, char *f, ...)
  675. {
  676. char *s;
  677. va_list arg;
  678. va_start(arg, f);
  679. s = vsmprint(f, arg);
  680. va_end(arg);
  681. fprint(2, "%s: %s\n", name, s);
  682. free(s);
  683. nconf++;
  684. // if(nconf%16 == 0)
  685. // conf = erealloc(conf, (nconf+16)*sizeof(conf[0]));
  686. // conf[nconf++] = estrdup(name);
  687. }
  688. void
  689. error(char *f, ...)
  690. {
  691. char *s;
  692. va_list arg;
  693. va_start(arg, f);
  694. s = vsmprint(f, arg);
  695. va_end(arg);
  696. fprint(2, "error: %s\n", s);
  697. free(s);
  698. errors = 1;
  699. }
  700. int
  701. ismatch(char *s)
  702. {
  703. int i, len;
  704. if(nmatch == 0)
  705. return 1;
  706. for(i=0; i<nmatch; i++){
  707. len = strlen(match[i]);
  708. if(len == 0)
  709. return 1;
  710. if(strncmp(s, match[i], len) == 0 && (s[len]=='/' || s[len] == 0))
  711. return 1;
  712. }
  713. return 0;
  714. }
  715. int
  716. localdirstat(char *name, Dir *d)
  717. {
  718. static Dir *d2;
  719. free(d2);
  720. if((d2 = dirstat(name)) == nil)
  721. return -1;
  722. *d = *d2;
  723. return 0;
  724. }
  725. enum { DEFB = 8192 };
  726. static int
  727. copy1(int fdf, int fdt, char *from, char *to)
  728. {
  729. int i, n, rv, pid[Nwork];
  730. Waitmsg *w;
  731. n = 0;
  732. off = 0;
  733. for(i=0; i<Nwork; i++){
  734. switch(pid[n] = rfork(RFPROC|RFMEM)){
  735. case 0:
  736. notify(failure);
  737. worker(fdf, fdt, from, to);
  738. case -1:
  739. break;
  740. default:
  741. n++;
  742. break;
  743. }
  744. }
  745. if(n == 0){
  746. fprint(2, "cp: rfork: %r\n");
  747. return -1;
  748. }
  749. rv = 0;
  750. while((w = wait()) != nil){
  751. if(w->msg[0]){
  752. rv = -1;
  753. for(i=0; i<n; i++)
  754. if(pid[i] > 0)
  755. postnote(PNPROC, pid[i], "failure");
  756. }
  757. free(w);
  758. }
  759. return rv;
  760. }
  761. void
  762. worker(int fdf, int fdt, char *from, char *to)
  763. {
  764. char buf[DEFB], *bp;
  765. long len, n;
  766. vlong o;
  767. len = sizeof(buf);
  768. bp = buf;
  769. o = nextoff();
  770. while(n = pread(fdf, bp, len, o)){
  771. if(n < 0){
  772. fprint(2, "reading %s: %r\n", from);
  773. _exits("bad");
  774. }
  775. if(pwrite(fdt, buf, n, o) != n){
  776. fprint(2, "writing %s: %r\n", to);
  777. _exits("bad");
  778. }
  779. bp += n;
  780. o += n;
  781. len -= n;
  782. if(len == 0){
  783. len = sizeof buf;
  784. bp = buf;
  785. o = nextoff();
  786. }
  787. }
  788. _exits(nil);
  789. }
  790. vlong
  791. nextoff(void)
  792. {
  793. vlong o;
  794. qlock(&lk);
  795. o = off;
  796. off += DEFB;
  797. qunlock(&lk);
  798. return o;
  799. }
  800. void
  801. failure(void*, char *note)
  802. {
  803. if(strcmp(note, "failure") == 0)
  804. _exits(nil);
  805. noted(NDFLT);
  806. }
  807. static int
  808. opentemp(char *template)
  809. {
  810. int fd, i;
  811. char *p;
  812. p = estrdup(template);
  813. fd = -1;
  814. for(i=0; i<10; i++){
  815. mktemp(p);
  816. if((fd=create(p, ORDWR|OEXCL|ORCLOSE, 0000)) >= 0)
  817. break;
  818. strcpy(p, template);
  819. }
  820. if(fd < 0)
  821. return -1;
  822. strcpy(template, p);
  823. free(p);
  824. return fd;
  825. }
  826. int
  827. copyfile(char *local, char *remote, char *name, Dir *d, int dowstat, int *printerror)
  828. {
  829. Dir *d0, *d1, *dl;
  830. Dir nd;
  831. int rfd, tfd, wfd, didcreate;
  832. char tmp[32], *p, *safe;
  833. char err[ERRMAX];
  834. Again:
  835. *printerror = 0;
  836. if((rfd = open(remote, OREAD)) < 0)
  837. return -1;
  838. d0 = dirfstat(rfd);
  839. if(d0 == nil){
  840. close(rfd);
  841. return -1;
  842. }
  843. *printerror = 1;
  844. if(!tempspool){
  845. tfd = rfd;
  846. goto DoCopy;
  847. }
  848. strcpy(tmp, "/tmp/replicaXXXXXXXX");
  849. tfd = opentemp(tmp);
  850. if(tfd < 0){
  851. close(rfd);
  852. free(d0);
  853. return -1;
  854. }
  855. if(copy1(rfd, tfd, remote, tmp) < 0 || (d1 = dirfstat(rfd)) == nil){
  856. close(rfd);
  857. close(tfd);
  858. free(d0);
  859. return -1;
  860. }
  861. close(rfd);
  862. if(d0->qid.path != d1->qid.path
  863. || d0->qid.vers != d1->qid.vers
  864. || d0->mtime != d1->mtime
  865. || d0->length != d1->length){
  866. /* file changed underfoot; go around again */
  867. close(tfd);
  868. free(d0);
  869. free(d1);
  870. goto Again;
  871. }
  872. free(d1);
  873. if(seek(tfd, 0, 0) != 0){
  874. close(tfd);
  875. free(d0);
  876. return -1;
  877. }
  878. DoCopy:
  879. /*
  880. * clumsy but important hack to do safeinstall-like installs.
  881. */
  882. p = strchr(name, '/');
  883. if(safeinstall && p && strncmp(p, "/bin/", 5) == 0 && access(local, AEXIST) >= 0){
  884. /*
  885. * remove bin/_targ
  886. */
  887. safe = emalloc(strlen(local)+2);
  888. strcpy(safe, local);
  889. p = strrchr(safe, '/')+1;
  890. memmove(p+1, p, strlen(p)+1);
  891. p[0] = '_';
  892. remove(safe); /* ignore failure */
  893. /*
  894. * rename bin/targ to bin/_targ
  895. */
  896. nulldir(&nd);
  897. nd.name = p;
  898. if(dirwstat(local, &nd) < 0)
  899. fprint(2, "warning: rename %s to %s: %r\n", local, p);
  900. }
  901. didcreate = 0;
  902. if((dl = dirstat(local)) == nil){
  903. if((wfd = create(local, OWRITE, 0)) >= 0){
  904. didcreate = 1;
  905. goto okay;
  906. }
  907. goto err;
  908. }else{
  909. if((wfd = open(local, OTRUNC|OWRITE)) >= 0)
  910. goto okay;
  911. rerrstr(err, sizeof err);
  912. if(strstr(err, "permission") == nil)
  913. goto err;
  914. nulldir(&nd);
  915. /*
  916. * Assume the person running pull is in the appropriate
  917. * groups. We could set 0666 instead, but I'm worried
  918. * about leaving the file world-readable or world-writable
  919. * when it shouldn't be.
  920. */
  921. nd.mode = dl->mode | 0660;
  922. if(nd.mode == dl->mode)
  923. goto err;
  924. if(dirwstat(local, &nd) < 0)
  925. goto err;
  926. if((wfd = open(local, OTRUNC|OWRITE)) >= 0){
  927. nd.mode = dl->mode;
  928. if(dirfwstat(wfd, &nd) < 0)
  929. fprint(2, "warning: set mode on %s to 0660 to open; cannot set back to %luo: %r\n", local, nd.mode);
  930. goto okay;
  931. }
  932. nd.mode = dl->mode;
  933. if(dirwstat(local, &nd) < 0)
  934. fprint(2, "warning: set mode on %s to %luo to open; open failed; cannot set mode back to %luo: %r\n", local, nd.mode|0660, nd.mode);
  935. goto err;
  936. }
  937. err:
  938. close(tfd);
  939. free(d0);
  940. free(dl);
  941. return -1;
  942. okay:
  943. free(dl);
  944. if(copy1(tfd, wfd, tmp, local) < 0){
  945. close(tfd);
  946. close(wfd);
  947. free(d0);
  948. return -1;
  949. }
  950. close(tfd);
  951. if(didcreate || dowstat){
  952. nulldir(&nd);
  953. nd.mode = d->mode;
  954. if(dirfwstat(wfd, &nd) < 0)
  955. fprint(2, "warning: cannot set mode on %s\n", local);
  956. nulldir(&nd);
  957. nd.gid = d->gid;
  958. if(dirfwstat(wfd, &nd) < 0)
  959. fprint(2, "warning: cannot set gid on %s\n", local);
  960. if(douid){
  961. nulldir(&nd);
  962. nd.uid = d->uid;
  963. if(dirfwstat(wfd, &nd) < 0)
  964. fprint(2, "warning: cannot set uid on %s\n", local);
  965. }
  966. }
  967. d->mtime = d0->mtime;
  968. d->length = d0->length;
  969. nulldir(&nd);
  970. nd.mtime = d->mtime;
  971. if(dirfwstat(wfd, &nd) < 0)
  972. fprint(2, "warning: cannot set mtime on %s\n", local);
  973. free(d0);
  974. close(wfd);
  975. return 0;
  976. }
  977. /*
  978. * Applylog might try to overwrite itself.
  979. * To avoid problems with this, we copy ourselves
  980. * into /tmp and then re-exec.
  981. */
  982. char *rmargv0;
  983. static void
  984. rmself(void)
  985. {
  986. remove(rmargv0);
  987. }
  988. static int
  989. genopentemp(char *template, int mode, int perm)
  990. {
  991. int fd, i;
  992. char *p;
  993. p = estrdup(template);
  994. fd = -1;
  995. for(i=0; i<10; i++){
  996. mktemp(p);
  997. if(access(p, 0) < 0 && (fd=create(p, mode, perm)) >= 0)
  998. break;
  999. strcpy(p, template);
  1000. }
  1001. if(fd < 0)
  1002. sysfatal("could not create temporary file");
  1003. strcpy(template, p);
  1004. free(p);
  1005. return fd;
  1006. }
  1007. static void
  1008. membogus(char **argv)
  1009. {
  1010. int n, fd, wfd;
  1011. char template[50], buf[1024];
  1012. if(strncmp(argv[0], "/tmp/_applylog_", 1+3+1+1+8+1)==0) {
  1013. rmargv0 = argv[0];
  1014. atexit(rmself);
  1015. return;
  1016. }
  1017. if((fd = open(argv[0], OREAD)) < 0)
  1018. return;
  1019. strcpy(template, "/tmp/_applylog_XXXXXX");
  1020. if((wfd = genopentemp(template, OWRITE, 0700)) < 0)
  1021. return;
  1022. while((n = read(fd, buf, sizeof buf)) > 0)
  1023. if(write(wfd, buf, n) != n)
  1024. goto Error;
  1025. if(n != 0)
  1026. goto Error;
  1027. close(fd);
  1028. close(wfd);
  1029. argv[0] = template;
  1030. exec(template, argv);
  1031. fprint(2, "exec error %r\n");
  1032. Error:
  1033. close(fd);
  1034. close(wfd);
  1035. remove(template);
  1036. return;
  1037. }