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