1 # include	"../hdr/defines.h"
2 # include	"../hdr/had.h"
3 
4 SCCSID(@(#)delta.c	4.4);
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,LNLNAM);
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, root;
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 	root = getuid() == 0;
411 	while (fgets(line,sizeof(line),in) != NULL) {
412 		pf_ab(line,&pf,1);
413 		if (root || equal(pf.pf_user,user)) {
414 			if (sp->s_rel == 0) {
415 				if (++cnt) {
416 					fclose(out);
417 					fclose(in);
418 					fatal("missing -r argument (de1)");
419 				}
420 				move(&pf,&goodpf,sizeof(pf));
421 				continue;
422 			}
423 			else if (sp->s_rel == pf.pf_gsid.s_rel &&
424 				sp->s_lev == pf.pf_gsid.s_lev &&
425 				sp->s_br == pf.pf_gsid.s_br &&
426 				sp->s_seq == pf.pf_gsid.s_seq) {
427 					move(&pf,&goodpf,sizeof(pf));
428 					continue;
429 			}
430 		}
431 		fputs(line,out);
432 	}
433 	fflush(out);
434 	fstat(fileno(out),&Statbuf);
435 	Szqfile = Statbuf.st_size;
436 	copy(auxf(pkt->p_file,'p'),Pfilename);
437 	fclose(out);
438 	fclose(in);
439 	if (!goodpf.pf_user[0])
440 		fatal("not in p-file (de2)");
441 	return(&goodpf);
442 }
443 
444 
445 dodiff(newf,oldf,difflim)
446 char *newf, *oldf;
447 int difflim;
448 {
449 	register int i;
450 	int pfd[2];
451 	FILE *iop;
452 	extern char Diffpgm[];
453 	char num[10];
454 
455 	xpipe(pfd);
456 	if ((i = fork()) < 0) {
457 		close(pfd[0]);
458 		close(pfd[1]);
459 		fatal("cannot fork, try again (de11)");
460 	}
461 	else if (i == 0) {
462 		close(pfd[0]);
463 		close(1);
464 		dup(pfd[1]);
465 		close(pfd[1]);
466 		for (i = 5; i < 15; i++)
467 			close(i);
468 		sprintf(num,"%d",difflim);
469 		execl(Diffpgm,Diffpgm,oldf,newf,num,"-s",0);
470 		close(1);
471 		exit(32);	/* tell parent that 'execl' failed */
472 	}
473 	else {
474 		close(pfd[1]);
475 		iop = fdfopen(pfd[0],0);
476 		return(iop);
477 	}
478 }
479 
480 
481 getdiff(type,plinenum)
482 register char *type;
483 register int *plinenum;
484 {
485 	char line[512];
486 	register char *p;
487 	int num_lines;
488 	static int chg_num, chg_ln;
489 	int lowline, highline;
490 
491 	if ((p = rddiff(line,512)) == NULL)
492 		return(0);
493 
494 	if (*p == '-') {
495 		*type = INS;
496 		*plinenum = chg_ln;
497 		num_lines = chg_num;
498 	}
499 	else {
500 		p = linerange(p,&lowline,&highline);
501 		*plinenum = lowline;
502 
503 		switch(*p++) {
504 		case 'd':
505 			num_lines = highline - lowline + 1;
506 			*type = DEL;
507 			skiplines(line,num_lines);
508 			break;
509 
510 		case 'a':
511 			linerange(p,&lowline,&highline);
512 			num_lines = highline - lowline + 1;
513 			*type = INS;
514 			break;
515 
516 		case 'c':
517 			chg_ln = lowline;
518 			num_lines = highline - lowline + 1;
519 			linerange(p,&lowline,&highline);
520 			chg_num = highline - lowline + 1;
521 			*type = DEL;
522 			skiplines(line,num_lines);
523 			break;
524 		}
525 	}
526 
527 	return(num_lines);
528 }
529 
530 
531 insert(pkt,linenum,n,ser)
532 register struct packet *pkt;
533 register int linenum;
534 register int n;
535 int ser;
536 {
537 	char str[512];
538 
539 	after(pkt,linenum);
540 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,INS,ser));
541 	for (++n; --n; ) {
542 		rddiff(str,sizeof(str));
543 		putline(pkt,&str[2]);
544 	}
545 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,END,ser));
546 }
547 
548 
549 delete(pkt,linenum,n,ser)
550 register struct packet *pkt;
551 register int linenum;
552 int n;
553 register int ser;
554 {
555 	char str[512];
556 
557 	before(pkt,linenum);
558 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,DEL,ser));
559 	after(pkt,linenum + n - 1);
560 	putline(pkt,sprintf(str,"%c%c %u\n",CTLCHAR,END,ser));
561 }
562 
563 
564 after(pkt,n)
565 register struct packet *pkt;
566 register int n;
567 {
568 	before(pkt,n);
569 	if (pkt->p_glnno == n)
570 		putline(pkt,0);
571 }
572 
573 
574 before(pkt,n)
575 register struct packet *pkt;
576 register int n;
577 {
578 	while (pkt->p_glnno < n) {
579 		if (!readmod(pkt))
580 			break;
581 	}
582 }
583 
584 
585 linerange(cp,low,high)
586 register char *cp;
587 register int *low, *high;
588 {
589 	cp = satoi(cp,low);
590 	if (*cp == ',')
591 		cp = satoi(++cp,high);
592 	else
593 		*high = *low;
594 
595 	return(cp);
596 }
597 
598 
599 skiplines(lp,num)
600 register char *lp;
601 register int num;
602 {
603 	for (++num;--num;)
604 		rddiff(lp,512);
605 }
606 
607 
608 rddiff(s,n)
609 register char *s;
610 register int n;
611 {
612 	register int r;
613 
614 	if ((r = fgets(s,n,Diffin)) != NULL && HADP)
615 		fputs(s,gpkt.p_stdout);
616 	return(r);
617 }
618 
619 
620 enter(pkt,ch,n,sidp)
621 struct packet *pkt;
622 char ch;
623 int n;
624 struct sid *sidp;
625 {
626 	char str[32];
627 	register struct apply *ap;
628 
629 	sid_ba(sidp,str);
630 	ap = &pkt->p_apply[n];
631 	if (pkt->p_cutoff > pkt->p_idel[n].i_datetime)
632 		switch(ap->a_code) {
633 
634 		case EMPTY:
635 			switch (ch) {
636 			case INCLUDE:
637 				condset(ap,APPLY,INCLUSER);
638 				break;
639 			case EXCLUDE:
640 				condset(ap,NOAPPLY,EXCLUSER);
641 				break;
642 			case IGNORE:
643 				condset(ap,EMPTY,IGNRUSER);
644 				break;
645 			}
646 			break;
647 		case APPLY:
648 			fatal("internal error in delta/enter() (de5)");
649 			break;
650 		case NOAPPLY:
651 			fatal("internal error in delta/enter() (de6)");
652 			break;
653 		default:
654 			fatal("internal error in delta/enter() (de7)");
655 			break;
656 		}
657 }
658 
659 
660 escdodelt()	/* dummy routine for dodelt() */
661 {
662 }
663 
664 
665 clean_up(n)
666 {
667 	if (gpkt.p_file[0])
668 		unlockit(auxf(gpkt.p_file,'z'),getpid());
669 	xrm(&gpkt);
670 	xfreeall();
671 }
672