1 # include "../hdr/defines.h"
2 # include "../hdr/had.h"
3 # include "pathnames.h"
4
5 static char Sccsid[] = "@(#)delta.c 4.12 11/11/90";
6 USXALLOC();
7
8 # ifdef LOGDELTA
9 char *LogFile = _PATH_SCCSLOG;
10 FILE *Logf;
11 # endif
12
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
main(argc,argv)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
delta(file)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)",
222 _PATH_BDIFF);
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 _PATH_BDIFF,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
rdpfile(pkt,sp)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
dodiff(newf,oldf,difflim)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 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(_PATH_BDIFF,"bdiff",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
getdiff(type,plinenum)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
insert(pkt,linenum,n,ser)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
delete(pkt,linenum,n,ser)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
after(pkt,n)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
before(pkt,n)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
linerange(cp,low,high)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
skiplines(lp,num)637 skiplines(lp,num)
638 register char *lp;
639 register int num;
640 {
641 for (++num;--num;)
642 rddiff(lp,512);
643 }
644
645
rddiff(s,n)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
escdodelt()698 escdodelt() /* dummy routine for dodelt() */
699 {
700 }
701
702
clean_up(n)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