1 # include "../hdr/defines.h" 2 # include "../hdr/had.h" 3 4 SCCSID(@(#)delta 2.1); 5 USXALLOC(); 6 7 char Diffpgm[] "/usr/local/bdiff"; 8 FILE *Diffin; 9 int Debug 0; 10 struct packet gpkt; 11 struct sid sid; 12 int num_files; 13 char had[26]; 14 char *ilist, *elist, *glist; 15 char *Comments, *Mrs; 16 int Domrs; 17 int verbosity; 18 int Did_id; 19 long Szqfile; 20 char Pfilename[FILESIZE]; 21 FILE *Xiop; 22 int Xcreate; 23 24 main(argc,argv) 25 int argc; 26 register char *argv[]; 27 { 28 register int i; 29 register char *p; 30 char c; 31 int testmore; 32 extern delta(); 33 extern int Fcnt; 34 35 Fflags = FTLEXIT | FTLMSG | FTLCLN; 36 for(i=1; i<argc; i++) 37 if(argv[i][0] == '-' && (c=argv[i][1])) { 38 p = &argv[i][2]; 39 testmore = 0; 40 switch (c) { 41 42 case 'r': 43 if (!p[0]) { 44 argv[i] = 0; 45 continue; 46 } 47 chksid(sid_ab(p,&sid),&sid); 48 break; 49 case 'g': 50 glist = p; 51 break; 52 case 'y': 53 Comments = p; 54 break; 55 case 'm': 56 Mrs = p; 57 break; 58 case 'p': 59 case 'n': 60 case 's': 61 testmore++; 62 break; 63 default: 64 fatal("unknown key letter (cm1)"); 65 } 66 67 if (testmore) { 68 testmore = 0; 69 if (*p) 70 fatal(sprintf(Error, 71 "value after %c arg (cm7)",c)); 72 } 73 if (had[c - 'a']++) 74 fatal("key letter twice (cm2)"); 75 argv[i] = 0; 76 } 77 else num_files++; 78 79 if(num_files == 0) 80 fatal("missing file arg (cm3)"); 81 if (!HADS) 82 verbosity = -1; 83 setsig(); 84 Fflags =& ~FTLEXIT; 85 Fflags =| FTLJMP; 86 for (i=1; i<argc; i++) 87 if (p=argv[i]) 88 do_file(p,delta); 89 exit(Fcnt ? 1 : 0); 90 } 91 92 93 delta(file) 94 { 95 static int first 1; 96 register char *p; 97 int n, linenum; 98 char type; 99 register int ser; 100 extern char had_dir, had_standinp; 101 extern char *Sflags[]; 102 char dfilename[FILESIZE]; 103 char gfilename[FILESIZE]; 104 char line[512]; 105 FILE *gin; 106 struct stats stats; 107 struct pfile *pp; 108 int inserted, deleted, orig; 109 int newser; 110 int status; 111 int diffloop; 112 int difflim; 113 114 if (setjmp(Fjmp)) 115 return; 116 if (first) { 117 first = 0; 118 dohist(file); 119 } 120 sinit(&gpkt,file,1); 121 if (lockit(auxf(gpkt.p_file,'z'),2,getpid())) 122 fatal("cannot create lock file (cm4)"); 123 gpkt.p_reopen = 1; 124 gpkt.p_stdout = stdout; 125 copy(auxf(gpkt.p_file,'g'),gfilename); 126 gin = xfopen(gfilename,0); 127 pp = rdpfile(&gpkt,&sid); 128 gpkt.p_cutoff = pp->pf_date; 129 ilist = pp->pf_ilist; 130 elist = pp->pf_elist; 131 132 if (dodelt(&gpkt,&stats,0,0) == 0) 133 fmterr(&gpkt); 134 if ((ser = sidtoser(&pp->pf_gsid,&gpkt)) == 0 || 135 sidtoser(&pp->pf_nsid,&gpkt)) 136 fatal("invalid sid in p-file (de3)"); 137 doie(&gpkt,ilist,elist,glist); 138 setup(&gpkt,ser); 139 finduser(&gpkt); 140 doflags(&gpkt); 141 move(&pp->pf_nsid,&gpkt.p_reqsid,sizeof(gpkt.p_reqsid)); 142 permiss(&gpkt); 143 flushto(&gpkt,EUSERTXT,1); 144 gpkt.p_chkeof = 1; 145 copy(auxf(gpkt.p_file,'d'),dfilename); 146 gpkt.p_gout = xfcreat(dfilename,0444); 147 while(readmod(&gpkt)) { 148 chkid(gpkt.p_line); 149 fputs(gpkt.p_line,gpkt.p_gout); 150 } 151 fclose(gpkt.p_gout); 152 orig = gpkt.p_glnno; 153 gpkt.p_glnno = 0; 154 gpkt.p_verbose = verbosity; 155 Did_id = 0; 156 while (fgets(line,sizeof(line),gin) != NULL && !chkid(line)) 157 ; 158 fclose(gin); 159 if (gpkt.p_verbose && (num_files > 1 || had_dir || had_standinp)) 160 fprintf(gpkt.p_stdout,"\n%s:\n",gpkt.p_file); 161 if (!Did_id) 162 if (Sflags[IDFLAG - 'a']) 163 fatal("no id keywords (cm6)"); 164 else if (gpkt.p_verbose) 165 fprintf(stderr,"No id keywords (cm7)\n"); 166 167 /* 168 The following while loop executes 'bdiff' on g-file and 169 d-file. If 'bdiff' fails (usually because segmentation 170 limit it is using is too large for 'diff'), it is 171 invoked again, with a lower segmentation limit. 172 */ 173 difflim = 3500; 174 diffloop = 0; 175 while (1) { 176 inserted = deleted = 0; 177 gpkt.p_glnno = 0; 178 gpkt.p_upd = 1; 179 gpkt.p_wrttn = 1; 180 getline(&gpkt); 181 gpkt.p_wrttn = 1; 182 newser = mkdelt(&gpkt,&pp->pf_nsid,&pp->pf_gsid, 183 diffloop,orig); 184 diffloop = 1; 185 flushto(&gpkt,EUSERTXT,0); 186 Diffin = dodiff(auxf(gpkt.p_file,'g'),dfilename,difflim); 187 while (n = getdiff(&type,&linenum)) { 188 if (type == INS) { 189 inserted =+ n; 190 insert(&gpkt,linenum,n,newser); 191 } 192 else { 193 deleted =+ n; 194 delete(&gpkt,linenum,n,newser); 195 } 196 } 197 fclose(Diffin); 198 if (gpkt.p_iop) 199 while (readmod(&gpkt)) 200 ; 201 wait(&status); 202 if (status) { /* diff failed */ 203 /* 204 Check top byte (exit code of child). 205 */ 206 if (((status >> 8) & 0377) == 32) /* 'execl' failed */ 207 fatal(sprintf(Error, 208 "cannot execute '%s' (de12)", 209 Diffpgm)); 210 /* 211 Re-try. 212 */ 213 if (difflim =- 500) { /* reduce segmentation */ 214 fprintf(stderr, 215 "'%s' failed, re-trying, segmentation = %d (de13)\n", 216 Diffpgm,difflim); 217 fclose(Xiop); /* set up */ 218 Xiop = 0; /* for new x-file */ 219 Xcreate = 0; 220 /* 221 Re-open s-file. 222 */ 223 gpkt.p_iop = xfopen(gpkt.p_file,0); 224 setbuf(gpkt.p_iop,gpkt.p_buf); 225 /* 226 Reset counters. 227 */ 228 gpkt.p_slnno = 0; 229 gpkt.p_ihash = 0; 230 gpkt.p_chash = 0; 231 gpkt.p_nhash = 0; 232 gpkt.p_keep = 0; 233 } 234 else 235 /* tried up to 500 lines, can't go on */ 236 fatal("diff failed (de4)"); 237 } 238 else { /* no need to try again, worked */ 239 break; /* exit while loop */ 240 } 241 } 242 unlink(dfilename); 243 stats.s_ins = inserted; 244 stats.s_del = deleted; 245 stats.s_unc = orig - deleted; 246 if (gpkt.p_verbose) { 247 fprintf(gpkt.p_stdout,"%u inserted\n",stats.s_ins); 248 fprintf(gpkt.p_stdout,"%u deleted\n",stats.s_del); 249 fprintf(gpkt.p_stdout,"%u unchanged\n",stats.s_unc); 250 } 251 flushline(&gpkt,&stats); 252 rename(auxf(gpkt.p_file,'x'),gpkt.p_file); 253 if (Szqfile) 254 rename(auxf(&gpkt.p_file,'q'),Pfilename); 255 else { 256 xunlink(Pfilename); 257 xunlink(auxf(&gpkt.p_file,'q')); 258 } 259 clean_up(0); 260 if (!HADN) { 261 setuid(getuid()); 262 unlink(gfilename); 263 } 264 } 265 266 267 mkdelt(pkt,sp,osp,diffloop,orig_nlines) 268 struct packet *pkt; 269 struct sid *sp, *osp; 270 int diffloop; 271 int orig_nlines; 272 { 273 extern long Timenow; 274 struct deltab dt; 275 char str[128]; 276 int newser; 277 extern char *Sflags[]; 278 register char *p; 279 int ser_inc, opred, nulldel; 280 281 if (!diffloop && pkt->p_verbose) { 282 sid_ba(sp,str); 283 fprintf(pkt->p_stdout,"%s\n",str); 284 } 285 putline(pkt,sprintf(str,"%c%c00000\n",CTLCHAR,HEAD)); 286 newstats(pkt,str,"0"); 287 move(sp,&dt.d_sid,sizeof(dt.d_sid)); 288 289 /* 290 Check if 'null' deltas should be inserted 291 (only if 'null' flag is in file and 292 releases are being skipped) and set 293 'nulldel' indicator appropriately. 294 */ 295 if (Sflags[NULLFLAG - 'a'] && (sp->s_rel > osp->s_rel + 1) && 296 !sp->s_br && !sp->s_seq && 297 !osp->s_br && !osp->s_seq) 298 nulldel = 1; 299 else 300 nulldel = 0; 301 /* 302 Calculate how many serial numbers are needed. 303 */ 304 if (nulldel) 305 ser_inc = sp->s_rel - osp->s_rel; 306 else 307 ser_inc = 1; 308 /* 309 Find serial number of the new delta. 310 */ 311 newser = dt.d_serial = maxser(pkt) + ser_inc; 312 /* 313 Find old predecessor's serial number. 314 */ 315 opred = sidtoser(osp,pkt); 316 if (nulldel) 317 dt.d_pred = newser - 1; /* set predecessor to 'null' delta */ 318 else 319 dt.d_pred = opred; 320 dt.d_datetime = Timenow; 321 substr(logname(),dt.d_pgmr,0,7); 322 dt.d_type = 'D'; 323 del_ba(&dt,str); 324 putline(pkt,str); 325 if (ilist) 326 mkixg(pkt,INCLUSER,INCLUDE); 327 if (elist) 328 mkixg(pkt,EXCLUSER,EXCLUDE); 329 if (glist) 330 mkixg(pkt,IGNRUSER,IGNORE); 331 if (Mrs) { 332 if (!(p = Sflags[VALFLAG - 'a'])) 333 fatal("MRs not allowed (de8)"); 334 if (*p && !diffloop && valmrs(pkt,p)) 335 fatal("invalid MRs (de9)"); 336 putmrs(pkt); 337 } 338 else if (Sflags[VALFLAG - 'a']) 339 fatal("MRs required (de10)"); 340 putline(pkt,sprintf(str,"%c%c ",CTLCHAR,COMMENTS)); 341 putline(pkt,Comments); 342 putline(pkt,"\n"); 343 putline(pkt,sprintf(str,CTLSTR,CTLCHAR,EDELTAB)); 344 if (nulldel) /* insert 'null' deltas */ 345 while (--ser_inc) { 346 putline(pkt,sprintf(str,"%c%c %s/%s/%05u\n", 347 CTLCHAR, STATS, 348 "00000", "00000", orig_nlines)); 349 dt.d_sid.s_rel =- 1; 350 dt.d_serial =- 1; 351 if (ser_inc != 1) 352 dt.d_pred =- 1; 353 else 354 dt.d_pred = opred; /* point to old pred */ 355 del_ba(&dt,str); 356 putline(pkt,str); 357 putline(pkt,sprintf(str,"%c%c ",CTLCHAR,COMMENTS)); 358 putline(pkt,"AUTO NULL DELTA\n"); 359 putline(pkt,sprintf(str,CTLSTR,CTLCHAR,EDELTAB)); 360 } 361 return(newser); 362 } 363 364 365 mkixg(pkt,reason,ch) 366 struct packet *pkt; 367 int reason; 368 char ch; 369 { 370 int n; 371 char str[512]; 372 373 putline(pkt,sprintf(str,"%c%c",CTLCHAR,ch)); 374 for (n = maxser(pkt); n; n--) { 375 if (pkt->p_apply[n].a_reason == reason) 376 putline(pkt,sprintf(str," %u",n)); 377 } 378 putline(pkt,"\n"); 379 } 380 381 382 putmrs(pkt) 383 struct packet *pkt; 384 { 385 register char **argv; 386 char str[64]; 387 extern char *Varg[]; 388 389 for (argv = &Varg[VSTART]; *argv; argv++) 390 putline(pkt,sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv)); 391 } 392 393 394 rdpfile(pkt,sp) 395 register struct packet *pkt; 396 struct sid *sp; 397 { 398 char *user; 399 struct pfile pf; 400 static struct pfile goodpf; 401 char line[512]; 402 int cnt; 403 FILE *in, *out; 404 405 cnt = -1; 406 user = logname(); 407 zero(&goodpf,sizeof(goodpf)); 408 in = xfopen(auxf(pkt->p_file,'p'),0); 409 out = xfcreat(auxf(pkt->p_file,'q'),0644); 410 while (fgets(line,sizeof(line),in) != NULL) { 411 pf_ab(line,&pf,1); 412 if (equal(pf.pf_user,user)) { 413 if (sp->s_rel == 0) { 414 if (++cnt) { 415 fclose(out); 416 fclose(in); 417 fatal("missing -r argument (de1)"); 418 } 419 move(&pf,&goodpf,sizeof(pf)); 420 continue; 421 } 422 else if (sp->s_rel == pf.pf_gsid.s_rel && 423 sp->s_lev == pf.pf_gsid.s_lev && 424 sp->s_br == pf.pf_gsid.s_br && 425 sp->s_seq == pf.pf_gsid.s_seq) { 426 move(&pf,&goodpf,sizeof(pf)); 427 continue; 428 } 429 } 430 fputs(line,out); 431 } 432 fflush(out); 433 fstat(fileno(out),&Statbuf); 434 Szqfile = Statbuf.st_size; 435 copy(auxf(pkt->p_file,'p'),Pfilename); 436 fclose(out); 437 fclose(in); 438 if (!goodpf.pf_user[0]) 439 fatal("not in p-file (de2)"); 440 return(&goodpf); 441 } 442 443 444 dodiff(newf,oldf,difflim) 445 char *newf, *oldf; 446 int difflim; 447 { 448 register int i; 449 int pfd[2]; 450 FILE *iop; 451 extern char Diffpgm[]; 452 char num[10]; 453 454 xpipe(pfd); 455 if ((i = fork()) < 0) { 456 close(pfd[0]); 457 close(pfd[1]); 458 fatal("cannot fork, try again (de11)"); 459 } 460 else if (i == 0) { 461 close(pfd[0]); 462 close(1); 463 dup(pfd[1]); 464 close(pfd[1]); 465 for (i = 5; i < 15; i++) 466 close(i); 467 sprintf(num,"%d",difflim); 468 execl(Diffpgm,Diffpgm,oldf,newf,num,"-s",0); 469 close(1); 470 exit(32); /* tell parent that 'execl' failed */ 471 } 472 else { 473 close(pfd[1]); 474 iop = fdfopen(pfd[0],0); 475 return(iop); 476 } 477 } 478 479 480 getdiff(type,plinenum) 481 register char *type; 482 register int *plinenum; 483 { 484 char line[512]; 485 register char *p; 486 int num_lines; 487 static int chg_num, chg_ln; 488 int lowline, highline; 489 490 if ((p = rddiff(line,512)) == NULL) 491 return(0); 492 493 if (*p == '-') { 494 *type = INS; 495 *plinenum = chg_ln; 496 num_lines = chg_num; 497 } 498 else { 499 p = linerange(p,&lowline,&highline); 500 *plinenum = lowline; 501 502 switch(*p++) { 503 case 'd': 504 num_lines = highline - lowline + 1; 505 *type = DEL; 506 skipline(line,num_lines); 507 break; 508 509 case 'a': 510 linerange(p,&lowline,&highline); 511 num_lines = highline - lowline + 1; 512 *type = INS; 513 break; 514 515 case 'c': 516 chg_ln = lowline; 517 num_lines = highline - lowline + 1; 518 linerange(p,&lowline,&highline); 519 chg_num = highline - lowline + 1; 520 *type = DEL; 521 skipline(line,num_lines); 522 break; 523 } 524 } 525 526 return(num_lines); 527 } 528 529 530 insert(pkt,linenum,n,ser) 531 register struct packet *pkt; 532 register int linenum; 533 register int n; 534 int ser; 535 { 536 char str[512]; 537 538 after(pkt,linenum); 539 putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,INS,ser)); 540 for (++n; --n; ) { 541 rddiff(str,sizeof(str)); 542 putline(pkt,&str[2]); 543 } 544 putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,END,ser)); 545 } 546 547 548 delete(pkt,linenum,n,ser) 549 register struct packet *pkt; 550 register int linenum; 551 int n; 552 register int ser; 553 { 554 char str[512]; 555 556 before(pkt,linenum); 557 putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,DEL,ser)); 558 after(pkt,linenum + n - 1); 559 putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,END,ser)); 560 } 561 562 563 after(pkt,n) 564 register struct packet *pkt; 565 register int n; 566 { 567 before(pkt,n); 568 if (pkt->p_glnno == n) 569 putline(pkt,0); 570 } 571 572 573 before(pkt,n) 574 register struct packet *pkt; 575 register int n; 576 { 577 while (pkt->p_glnno < n) { 578 if (!readmod(pkt)) 579 break; 580 } 581 } 582 583 584 linerange(cp,low,high) 585 register char *cp; 586 register int *low, *high; 587 { 588 cp = satoi(cp,low); 589 if (*cp == ',') 590 cp = satoi(++cp,high); 591 else 592 *high = *low; 593 594 return(cp); 595 } 596 597 598 skiplines(lp,num) 599 register char *lp; 600 register int num; 601 { 602 for (++num;--num;) 603 rddiff(lp,512); 604 } 605 606 607 rddiff(s,n) 608 register char *s; 609 register int n; 610 { 611 register int r; 612 613 if ((r = fgets(s,n,Diffin)) != NULL && HADP) 614 fputs(s,gpkt.p_stdout); 615 return(r); 616 } 617 618 619 enter(pkt,ch,n,sidp) 620 struct packet *pkt; 621 char ch; 622 int n; 623 struct sid *sidp; 624 { 625 char str[32]; 626 register struct apply *ap; 627 628 sid_ba(sidp,str); 629 ap = &pkt->p_apply[n]; 630 if (pkt->p_cutoff > pkt->p_idel[n].i_datetime) 631 switch(ap->a_code) { 632 633 case EMPTY: 634 switch (ch) { 635 case INCLUDE: 636 condset(ap,APPLY,INCLUSER); 637 break; 638 case EXCLUDE: 639 condset(ap,NOAPPLY,EXCLUSER); 640 break; 641 case IGNORE: 642 condset(ap,EMPTY,IGNRUSER); 643 break; 644 } 645 break; 646 case APPLY: 647 fatal("internal error in delta/enter() (de5)"); 648 break; 649 case NOAPPLY: 650 fatal("internal error in delta/enter() (de6)"); 651 break; 652 default: 653 fatal("internal error in delta/enter() (de7)"); 654 break; 655 } 656 } 657 658 659 escdodelt() /* dummy routine for dodelt() */ 660 { 661 } 662 663 664 clean_up(n) 665 { 666 if (gpkt.p_file[0]) 667 unlockit(auxf(gpkt.p_file,'z'),getpid()); 668 xrm(&gpkt); 669 xfreeall(); 670 } 671