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