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