1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License ("CDDL"), version 1.0.
6  * You may use this file only in accordance with the terms of version
7  * 1.0 of the CDDL.
8  *
9  * A full copy of the text of the CDDL should have accompanied this
10  * source.  A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 /* Copyright (c) 1988 AT&T */
24 /* All Rights Reserved */
25 /*
26  * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
27  * Use is subject to license terms.
28  */
29 /*
30  * Copyright 2006-2020 J. Schilling
31  *
32  * @(#)delta.c	1.115 20/09/17 J. Schilling
33  */
34 #if defined(sun)
35 #pragma ident "@(#)delta.c 1.115 20/09/17 J. Schilling"
36 #endif
37 /*
38  * @(#)delta.c 1.40 06/12/12
39  */
40 
41 #if defined(sun)
42 #pragma ident	"@(#)delta.c"
43 #pragma ident	"@(#)sccs:cmd/delta.c"
44 #endif
45 
46 # define	NEED_PRINTF_J		/* Need defines for js_snprintf()? */
47 # include	<schily/resource.h>
48 # define	SCCS_MAIN
49 # include	<defines.h>
50 # include	<version.h>
51 # include	<had.h>
52 # include	<i18n.h>
53 # include	<schily/utsname.h>
54 # include	<schily/fcntl.h>
55 # include	<schily/wait.h>
56 # define	VMS_VFORK_OK
57 # include	<schily/vfork.h>
58 # include	<ccstypes.h>
59 # include	<schily/sysexits.h>
60 
61 #ifdef		NO_FSDIFF
62 #undef		USE_FSDIFF
63 #endif
64 
65 # define	LENMR	60		/* Maximum length of an MR record */
66 
67 static FILE	*Diffin, *Gin;
68 static FILE	*Cs;			/* The changeset file		*/
69 static Nparms	N;			/* Keep -N parameters		*/
70 static Xparms	X;			/* Keep -X parameters		*/
71 static struct packet	gpkt;
72 static struct utsname	un;
73 static int	num_files;
74 static int	number_of_lines;	/* # of lines in the g-file	*/
75 static off_t	size_of_file;		/* The size of the g-file	*/
76 static off_t	Szqfile;
77 static off_t	Checksum_offset;
78 static char	Zhold[MAXPATHLEN];	/* temporary z-file name */
79 #if	defined(PROTOTYPES) && defined(INS_BASE)
80 static char	BDiffpgmp[]  =   NOGETTEXT(INS_BASE "/" SCCS_BIN_PRE "bin/" "bdiff");
81 #else
82 /*
83  * XXX If you are using a K&R compiler and like to install to a path
84  * XXX different from "/usr/ccs/bin/", you need to edit this string.
85  */
86 static char	BDiffpgmp[]  =   NOGETTEXT("/usr/ccs/bin/bdiff");
87 #endif
88 static char	BDiffpgm[]  =   NOGETTEXT("/usr/bin/bdiff");
89 static char	BDiffpgm2[]  =   NOGETTEXT("/bin/bdiff");
90 #ifdef	USE_FSDIFF
91 #if	defined(PROTOTYPES) && defined(INS_BASE)
92 static char	FDiffpgmp[]  =   NOGETTEXT(INS_BASE  "/" SCCS_BIN_PRE "bin/" "fsdiff");
93 #else
94 static char	FDiffpgmp[]  =   NOGETTEXT("/usr/ccs/bin/fsdiff");
95 #endif
96 #endif
97 #if	defined(PROTOTYPES) && defined(INS_BASE)
98 static char	Diffpgmp[]  =   NOGETTEXT(INS_BASE  "/" SCCS_BIN_PRE "bin/" "diff");
99 #else
100 static char	Diffpgmp[]  =   NOGETTEXT("/usr/ccs/bin/diff");
101 #endif
102 static char	Diffpgm[]   =   NOGETTEXT("/usr/bin/diff");
103 static char	Diffpgm2[]   =   NOGETTEXT("/bin/diff");
104 static char	*diffpgm = "";
105 static char	*ilist, *elist, *glist, Cmrs[300], *Nsid;
106 static char	Pfilename[FILESIZE];
107 static char	*uuname;
108 static char	*Cwd = "";
109 static char	*Dfilename;
110 static int	processed_files;
111 static int	did_intr;
112 
113 static struct timespec	gfile_mtime;	/* Timestamp for -o		*/
114 static	time_t	cutoff = MAX_TIME;
115 
116 static struct sid sid;
117 
118 static	void    clean_up __PR((void));
119 static	void	enter	__PR((struct packet *pkt, int ch, int n, struct sid *sidp));
120 
121 	int	main __PR((int argc, char **argv));
122 static void	delta __PR((char *file));
123 static int	mkdelt __PR((struct packet *pkt, struct sid *sp, struct sid *osp,
124 				int diffloop, int orig_nlines));
125 static void	mkixg __PR((struct packet *pkt, int reason, int ch));
126 static void	putmrs __PR((struct packet *pkt));
127 static void	putcmrs __PR((struct packet *pkt));
128 static struct pfile *rdpfile __PR((struct packet *pkt, struct sid *sp));
129 static FILE *	dodiff __PR((char *newf, char *oldf, int difflim));
130 static int	getdiff __PR((char *type, int *plinenum));
131 static void	insert __PR((struct packet *pkt, int linenum, int n, int ser, int off));
132 static void	delete __PR((struct packet *pkt, int linenum, int n, int ser));
133 static void	after __PR((struct packet *pkt, int n));
134 static void	before __PR((struct packet *pkt, int n));
135 static char *	linerange __PR((char *cp, int *low, int *high));
136 static void	skipline __PR((char *lp, int num));
137 static char *	rddiff __PR((char *s, int n, int *ll));
138 static void	fgetchk __PR((char *file, struct packet *pkt));
139 static void	warnctl __PR((char *file, off_t nline));
140 static void	warnnull __PR((char *file, off_t nline));
141 static int	fixghash __PR((struct packet *pkt, int ser));
142 static RETSIGTYPE intr	__PR((int));
143 static void	setintr	__PR((void));
144 
145 int
main(argc,argv)146 main(argc,argv)
147 int argc;
148 register char *argv[];
149 {
150 	register int i;
151 	register char *p;
152 	int no_arg, c;
153 	extern int Fcnt;
154 	int current_optind;
155 
156 	/*
157 	 * Set locale for all categories.
158 	 */
159 	setlocale(LC_ALL, "");
160 
161 	sccs_setinsbase(INS_BASE);
162 
163 	/*
164 	 * Set directory to search for general l10n SCCS messages.
165 	 */
166 #ifdef	PROTOTYPES
167 	(void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
168 	   NOGETTEXT(INS_BASE "/" SCCS_BIN_PRE "lib/locale/"));
169 #else
170 	(void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
171 	   NOGETTEXT("/usr/ccs/lib/locale/"));
172 #endif
173 
174 	(void) textdomain(NOGETTEXT("SUNW_SPRO_SCCS"));
175 
176 	tzset();	/* Set up timezome related vars */
177 
178 #ifdef	SCHILY_BUILD
179 	save_args(argc, argv);
180 #endif
181 	set_clean_up(clean_up);
182 	Fflags = FTLEXIT | FTLMSG | FTLCLN;
183 #ifdef	SCCS_FATALHELP
184 	Fflags |= FTLFUNC;
185 	Ffunc = sccsfatalhelp;
186 #endif
187 
188 	current_optind = 1;
189 	optind = 1;
190 	opterr = 0;
191 	no_arg = 0;
192 	i = 1;
193 	/*CONSTCOND*/
194 	while (1) {
195 		        if(current_optind < optind) {
196 			   current_optind = optind;
197 			   argv[i] = 0;
198 			   if (optind > i+1 ) {
199 			      if( (argv[i+1][0]!='-')&&(no_arg==0) ) {
200 				 argv[i+1] = NULL;
201 			      } else {
202 			         optind = i+1;
203 			         current_optind = optind;
204 			      }
205 			   }
206 			}
207 			no_arg = 0;
208 			i = current_optind;
209 		        c = getopt(argc, argv, "()-r:bdpsnm:g:y:fhoqkzC:D:N:X:V(version)");
210 
211 				/* this takes care of options given after
212 				** file names.
213 				*/
214 			if(c == EOF) {
215 			   if (optind < argc) {
216 				/* if it's due to -- then break; */
217 			       if(argv[i][0] == '-' &&
218 				      argv[i][1] == '-') {
219 			          argv[i] = 0;
220 			          break;
221 			       }
222 			       optind++;
223 			       current_optind = optind;
224 			       continue;
225 			   } else {
226 			       break;
227 			   }
228 			}
229 			p = optarg;
230 			switch (c) {
231 
232 			case 'r':
233 				if (*p == 0) continue;
234 				chksid(sid_ab(p,&sid),&sid);
235 				break;
236 			case 'g':
237 				glist = p;
238 				break;
239 			case 'y':
240 				if (optarg == argv[i+1]) {
241 				   Comments = "";
242 				   no_arg = 1;
243 				} else {
244 				   Comments = p;
245 				}
246 				break;
247 			case 'm':
248 				Mrs = p;
249 				repl(Mrs,'\n',' ');
250 				break;
251  			case 'b':
252  			case 'd':
253 			case 'p':
254 			case 'n':
255 			case 's':
256                         case 'f': /* force delta without p. file (NSE only) */
257 				if (p) {
258 				   if (*p) {
259 				      sprintf(SccsError,
260 					gettext("value after %c arg (cm7)"),
261 					c);
262 				      fatal(SccsError);
263 				   }
264 				}
265 				break;
266 			case 'h': /* allow diffh for large files (NSE only) */
267 			case 'k': /* get(1) without keyword expand */
268 			case 'o': /* use original file date */
269                                 break;
270                         case 'q': /* enable NSE mode */
271 				if(p) {
272                                   if (*p) {
273                                         nsedelim = p;
274 				  }
275                                 } else {
276                                         nsedelim = (char *) 0;
277                                 }
278                                 break;
279 			case 'z':
280 				break;
281 			case 'C':
282 				Cwd = p;
283 				break;
284 			case 'D':
285 				Dfilename = p;
286 				break;
287 
288 			case 'N':	/* Bulk names */
289 				initN(&N);
290 				if (optarg == argv[i+1]) {
291 				   no_arg = 1;
292 				   break;
293 				}
294 				N.n_parm = p;
295 				break;
296 
297 			case 'X':
298 				X.x_parm = optarg;
299 				X.x_flags = XO_PREPEND_FILE|XO_MAIL|\
300 					XO_USER|XO_DATE|XO_NULLPATH|\
301 					XO_NOBULK|XO_G_PATH;
302 				if (!parseX(&X))
303 					goto err;
304 				break;
305 
306 			case 'V':		/* version */
307 				printf(gettext(
308 				    "delta %s-SCCS version %s %s (%s-%s-%s)\n"),
309 					PROVIDER,
310 					VERSION,
311 					VDATE,
312 					HOST_CPU, HOST_VENDOR, HOST_OS);
313 				exit(EX_OK);
314 
315 			default:
316 			err:
317 				fatal(gettext("Usage: delta [ -bdknops ][ -g sid-list ][ -m mr-list ][ -r SID ]\n\t[ -y[comment] ][ -D diff-file ][ -N[bulk-spec]][ -Xxopts ] s.filename..."));
318 			}
319 
320 			/*
321 			 * Make sure that we only collect option letters from
322 			 * the range 'a'..'z' and 'A'..'Z'.
323 			 */
324 			if (ALPHA(c) &&
325 			    (had[LOWER(c)? c-'a' : NLOWER+c-'A']++)) {
326 				if (c != 'X')
327 					fatal(gettext("key letter twice (cm2)"));
328 			}
329 	}
330 #ifdef	NO_BDIFF
331 #if	!(defined(SVR4) && defined(sun))
332 	had['d' - 'a'] = 1;			/* Do not use "bdiff" */
333 #endif
334 #endif
335 
336 	for(i=1; i<argc; i++){
337 		if(argv[i]) {
338 		       num_files++;
339 		}
340 	}
341         if ((HADF || HADH) && !HADQ) {
342                 fatal(gettext("unknown key letter (cm1)"));
343         }
344  	if (num_files == 0) {
345  	   if (HADD != 0) Fflags &= ~FTLEXIT;
346  	   fatal(gettext("missing file arg (cm3)"));
347  	   exit(2);
348  	}
349 
350 	setsig();
351 	xsethome(NULL);
352 	if (HADUCN) {					/* Parse -N args  */
353 		parseN(&N);
354 
355 		if (N.n_sdot && (sethomestat & SETHOME_OFFTREE))
356 			fatal(gettext("-Ns. not supported in off-tree project mode"));
357 	}
358 
359 	/*
360 	 * Get the name of our machine to be used for the lockfile.
361 	 */
362 	uname(&un);
363 	uuname = un.nodename;
364 	setintr();					/* Catch ^C	*/
365 
366 	/*
367 	 * Set up a project global lock on the changeset file.
368 	 * Since we set FTLJMP, we do not need to unlockchset() from clean_up().
369 	 */
370 	if (SETHOME_CHSET()) {
371 		lockchset(getppid(), getpid(), uuname);
372 		if (HADUCN && exists(changesetgfile)) {
373 			/*
374 			 * Should we open/create the file even if it does not
375 			 * yet exist? This may change with the final concept.
376 			 */
377 			Cs = xfopen(changesetgfile, O_WRONLY|O_APPEND|O_BINARY);
378 		}
379 	}
380 	timerchsetlock();
381 
382 	Fflags &= ~FTLEXIT;
383 	Fflags |= FTLJMP;
384 	for (i=1; i<argc; i++)
385 		if ((p=argv[i]) != NULL)
386 			do_file(p, delta, 1, N.n_sdot, &X);
387 
388 	/*
389 	 * Only remove the global lock it it was created by us and not by
390 	 * our parent.
391 	 */
392 	if (SETHOME_CHSET()) {
393 		if (HADUCN) {
394 			bulkchdir(&N);
395 			if (Cs)
396 				fclose(Cs);
397 		}
398 		unlockchset(getpid(), uuname);
399 	}
400 
401 	return (Fcnt ? 1 : 0);
402 }
403 
404 /*
405  * Create the delta for one file
406  */
407 static void
delta(file)408 delta(file)
409 char *file;
410 {
411 	static int first = 1;
412 	int n, linenum;
413 	int	ghash;
414 	char type;
415 	register int ser;
416 	extern char had_dir, had_standinp;
417 	char nsid[SID_STRSIZE];
418 	char dfilename[FILESIZE];
419 	char gfilename[FILESIZE];
420 	char *ifile;
421 	char line[BUFSIZ];		/* Buffer for uuencoded IO, see below */
422 	struct stats stats;
423 	struct pfile *pp = NULL;
424 	struct stat sbuf;
425 	int inserted, deleted, orig;
426 	int newser;
427 	uid_t holduid;
428 	gid_t holdgid;
429 	FILE *efp;
430 	int status;
431 	int diffloop;
432 	int difflim;
433 
434 	Gin = NULL;
435 	if (setjmp(Fjmp))
436 		return;
437 
438 	/*
439 	 * In order to make the global lock with a potentially long duration
440 	 * not look as if it was expired, we refresh it for every file in our
441 	 * task list. This is needed since another SCCS instance on a different
442 	 * NFS machine cannot use kill() to check for a still active process.
443 	 */
444 	if (SETHOME_CHSET()) {
445 		if (HADUCN)
446 			bulkchdir(&N);	/* Done by bulkprepare() anyway */
447 		refreshchsetlock();
448 	}
449 
450 	if (HADUCN && !(X.x_opts & XO_NOBULK)) {
451 #ifdef	__needed__
452 		char	*ofile = file;
453 #endif
454 
455 		file = bulkprepare(&N, file);
456 		if (file == NULL) {
457 #ifdef	__needed__
458 			if (N.n_ifile)
459 				ofile = N.n_ifile;
460 #endif
461 			/*
462 			 * The error is typically
463 			 * "directory specified as s-file (cm14)"
464 			 */
465 			fatal(gettext(bulkerror(&N)));
466 		}
467 		ifile = N.n_ifile;
468 	} else {
469 		ifile = NULL;
470 	}
471 	if (X.x_opts & XO_G_PATH)
472 		ifile = X.x_gpath;
473 
474 	/*
475 	 * Init and check for validity of file name but do not open the file.
476 	 * This prevents us from potentially damaging files with lockit().
477 	 */
478 	sinit(&gpkt, file, SI_INIT);
479 
480 	/*
481 	 * Lock out any other user who may be trying to process
482 	 * the same file.
483 	 */
484 	if (!islockchset(copy(auxf(gpkt.p_file, 'z'), Zhold))) {
485 		if (lockit(Zhold, SCCS_LOCK_ATTEMPTS, getpid(), uuname)) {
486 			lockfatal(Zhold, getpid(), uuname);
487 		} else {
488 			timersetlockfile(Zhold);
489 		}
490 	} else {
491 		/*
492 		 * We are updating the changeset history file and thus should
493 		 * not append changeset records to the changeset file.
494 		 */
495 		if (Cs) {
496 			fclose(Cs);
497 			Cs = NULL;
498 		}
499 	}
500 
501 	sinit(&gpkt, file, SI_OPEN);
502 	gpkt.p_enter = enter;
503 	if ((gpkt.p_flags & PF_V6) == 0)
504 		gpkt.p_flags |= PF_GMT;
505 	if (first) {
506 		first = 0;
507 		dohist(file);
508 	}
509 	gpkt.p_reopen = 1;
510 	if (X.x_opts & XO_PREPEND_FILE) {
511 		gpkt.no_chksum = 1;
512 		gpkt.do_chksum = 0;
513 	}
514 	gpkt.p_stdout = stdout;
515 	gfilename[0] = '\0';
516 	strlcatl(gfilename, sizeof (gfilename),
517 		Cwd,
518 		ifile ? ifile :
519 			auxf(gpkt.p_file, 'g'),
520 		(char *)0);
521 	Gin = xfopen(gfilename, O_RDONLY|O_BINARY);
522 #ifdef	USE_SETVBUF
523 	setvbuf(Gin, NULL, _IOFBF, VBUF_SIZE);
524 #endif
525 	Pfilename[0] = '\0';
526 	if (!HADF || exists(auxf(gpkt.p_file,'p')))
527 		pp = rdpfile(&gpkt, &sid);
528 
529 	Cmrs[0] = 0;
530 	if (pp != NULL && pp->pf_cmrlist != NULL)
531 		strlcpy(Cmrs, pp->pf_cmrlist, sizeof (Cmrs));
532 
533 	if (dodelt(&gpkt,&stats,(struct sid *) 0,0) == 0)
534 		fmterr(&gpkt);
535 
536         if ((HADF) && !exists(auxf(gpkt.p_file,'p'))) {
537                 /* if no p. file exists delta can still happen if
538                  * -f flag given (in NSE mode) - uses the same logic
539                  * as get -e to assign a new SID */
540                 gpkt.p_reqsid.s_rel = 0;
541                 gpkt.p_reqsid.s_lev = 0;
542                 gpkt.p_reqsid.s_br = 0;
543                 gpkt.p_reqsid.s_seq = 0;
544                 gpkt.p_cutoff = cutoff;
545                 ilist = 0;
546                 elist = 0;
547                 ser = getser(&gpkt);
548                 newsid(&gpkt, 0);	/* sets gpkt.p_reqsid */
549         } else {
550                 gpkt.p_cutoff = pp->pf_date;
551                 ilist = pp->pf_ilist;
552                 elist = pp->pf_elist;
553                 if ((ser = sidtoser(&pp->pf_gsid,&gpkt)) == 0 ||
554                         sidtoser(&pp->pf_nsid,&gpkt))
555                                 fatal(gettext("invalid sid in p-file (de3)"));
556 		gpkt.p_reqsid = pp->pf_nsid;
557         }
558 	sid_ba(&gpkt.p_reqsid, nsid);
559 	Nsid=nsid;
560 	gfile_mtime.tv_sec = gfile_mtime.tv_nsec = 0;
561         if ((HADO || HADQ) && stat(gfilename, &sbuf) == 0) {
562                 /*
563 		 * When specifying -o (original date) and when
564 		 * in NSE mode, the mtime of the clear file is remembered for
565                  * use as delta time. Sccs is thus now vulnerable to clock
566                  * skew between NFS server and host machine and to a mis-set
567                  * clock when file is last changed.
568 		 * In non-original date mode, sccs is vulnerable to a mis-set of
569 		 * the local clock while calling 'delta'.
570                  */
571                 gfile_mtime.tv_sec = sbuf.st_mtime;
572                 gfile_mtime.tv_nsec = stat_mnsecs(&sbuf);
573 	}
574 
575 	doie(&gpkt,ilist,elist,glist);
576 	setup(&gpkt,ser);
577 	finduser(&gpkt);
578 	doflags(&gpkt);
579 	permiss(&gpkt);
580 	donamedflags(&gpkt);
581 	dometa(&gpkt);
582 	flushto(&gpkt, EUSERTXT, FLUSH_NOCOPY);
583 	gpkt.p_chkeof = 1;
584 	/* if encode flag is set, encode the g-file before diffing it
585 	 * with the s.file
586 	 */
587 	if (gpkt.p_encoding & EF_UUENCODE) {
588 		efp = xfcreat(auxf(gpkt.p_file,'e'),0644);
589 #ifdef	USE_SETVBUF
590 		setvbuf(efp, NULL, _IOFBF, VBUF_SIZE);
591 #endif
592 		encode(Gin,efp);
593 		fclose(efp);
594 		if (Gin)
595 			fclose(Gin);
596 		Gin = xfopen(auxf(gpkt.p_file,'e'), O_RDONLY|O_BINARY);
597 #ifdef	USE_SETVBUF
598 		setvbuf(Gin, NULL, _IOFBF, VBUF_SIZE);
599 #endif
600 	}
601 
602 	dfilename[0] = '\0';
603 	if ((X.x_opts & XO_PREPEND_FILE) == 0) {
604 		/*
605 		 * Extract the reference version to diff against.
606 		 */
607 		copy(auxf(gpkt.p_file,'d'),dfilename);
608 		gpkt.p_gout = xfcreat(dfilename,(mode_t)0444);
609 #ifdef	USE_SETVBUF
610 		setvbuf(gpkt.p_gout, NULL, _IOFBF, VBUF_SIZE);
611 #endif
612 		while (readmod(&gpkt)) {
613 			if (gpkt.p_flags & PF_NONL) {
614 				gpkt.p_line[--(gpkt.p_line_length)] = '\0';
615 				gpkt.p_line_length -= 2;	/* ^AN */
616 			}
617 			if (fwrite(gpkt.p_lineptr, 1, gpkt.p_line_length,
618 			    gpkt.p_gout) != gpkt.p_line_length)
619 				xmsg(dfilename, NOGETTEXT("delta"));
620 			if (gpkt.p_flags & PF_NONL) {
621 				gpkt.p_line_length += 2;	/* ^AN */
622 				gpkt.p_line[(gpkt.p_line_length)++] = '\n';
623 			}
624 		}
625 		if (fflush(gpkt.p_gout) == EOF)
626 			xmsg(dfilename, NOGETTEXT("delta"));
627 #ifdef	HAVE_FSYNC
628 		if (fsync(fileno(gpkt.p_gout)) < 0)
629 			xmsg(dfilename, NOGETTEXT("delta"));
630 #endif
631 		if (fclose(gpkt.p_gout) == EOF)
632 			xmsg(dfilename, NOGETTEXT("delta"));
633 		gpkt.p_gout = NULL;
634 		orig = gpkt.p_glnno;
635 	} else {
636 		/*
637 		 * We don't count the previous version and we
638 		 * do not have real diffs, so we need to use
639 		 * an estimation.
640 		 */
641 		orig = stats.s_ins + stats.s_unc - stats.s_del;
642 	}
643 
644 	gpkt.p_glnno = 0;
645 	gpkt.p_verbose = (HADS) ? 0 : 1;
646 	gpkt.p_did_id = 0;
647  	number_of_lines = size_of_file = 0;
648 
649 	gpkt.p_ghash = 0;	/* Reset ghash from previous readmod() calls */
650 
651 	if (gpkt.p_sflags[EXPANDFLAG - 'a'] &&
652 	    *(gpkt.p_sflags[EXPANDFLAG - 'a']) == '\0') {
653 		gpkt.p_did_id = 1;	/* No need to scan for keywds */
654 	}
655 	if ((gpkt.p_encoding & EF_UUENCODE) == 0) {
656 		/*
657 		 * Compute the checksum and scan for unsupported characters.
658 		 * This method supports nul bytes.
659 		 */
660 		fgetchk(gfilename, &gpkt);
661 		number_of_lines = gpkt.p_glines;
662 	} else {
663 		/*
664 		 * This does not support nul bytes, but this is uuencoded text.
665 		 */
666 	 	while (fgets(line,sizeof(line),Gin) != NULL) {
667 			register int	len = strlen(line);
668 			register char	**sflags = gpkt.p_sflags;
669 
670 			gpkt.p_ghash += usum(line, len);
671  			if (line[len-1] == '\n') {
672  	   			number_of_lines++;
673 			}
674 			if (gpkt.p_did_id == 0) {
675 				gpkt.p_did_id = chkid(line,
676 							sflags[IDFLAG - 'a'],
677 							sflags);
678 			}
679 		}
680 	}
681 	gpkt.p_ghash &= 0xFFFF;
682 	if (stat(gfilename, &Statbuf) == 0) {
683 		size_of_file = Statbuf.st_size;
684 	}
685 	if ((X.x_opts & XO_PREPEND_FILE) == 0) {
686 		if (Gin)
687 			fclose(Gin);
688 		Gin = NULL;
689 	}
690 	if (gpkt.p_verbose && (num_files > 1 || had_dir || had_standinp))
691  	   fprintf(gpkt.p_stdout,"\n%s:\n",gpkt.p_file);
692  	if (HADD != 0) {
693  	   if (number_of_lines > 70000 && size_of_file > 3670000) {
694  	      fprintf(stderr,
695  	         gettext("Warning: the file is greater than 70000 lines and 3.5Mb\n"));
696  	   } else {
697  	      if (size_of_file > 5872000) {
698  	         fprintf(stderr,
699  	            gettext("Warning: the file is greater than 5.6Mb\n"));
700  	      }
701  	   }
702  	}
703 
704 	if (!gpkt.p_did_id && !HADQ &&
705 	    (!gpkt.p_sflags[EXPANDFLAG - 'a'] ||
706 	    *(gpkt.p_sflags[EXPANDFLAG - 'a']))) {
707 		if (gpkt.p_sflags[IDFLAG - 'a']) {
708 			if(!(*gpkt.p_sflags[IDFLAG - 'a']))
709 				fatal(gettext("no id keywords (cm6)"));
710 			else
711 				fatal(gettext("invalid id keywords (cm10)"));
712 		} else if (gpkt.p_verbose) {
713 			fprintf(stderr,gettext("No id keywords (cm7)\n"));
714 		}
715 	}
716 
717 	/*
718 	The following while loop executes 'bdiff' on g-file and
719 	d-file. If 'bdiff' fails (usually because segmentation
720 	limit it is using is too large for 'diff'), it is
721 	invoked again, with a lower segmentation limit.
722 	*/
723 	difflim = 24000;
724 	diffloop = 0;
725 	ghash = gpkt.p_ghash;			/* Save ghash value */
726 	gpkt.p_reopen = 1;			/* Let it stay open */
727 
728 	if (X.x_opts & XO_PREPEND_FILE) {
729 		int	oihash = gpkt.p_ihash;	/* Remember hash from sinit() */
730 
731 		grewind(&gpkt);
732 		gpkt.p_reopen = 1;		/* Let it stay open */
733 		gpkt.do_chksum = 1;		/* No old g-file, do it now */
734 		gpkt.p_ihash = oihash;		/* Restore hash */
735 		if (gpkt.p_flags & PF_V6) {
736 			/*
737 			 * We do not read the "current" file as it does not yet
738 			 * exist, but we compute the sum of the hashes from the
739 			 * old file and the new beginning that is a file with
740 			 * the name of the g-file.
741 			 */
742 			if (gpkt.p_hash != NULL) {
743 				ghash += gpkt.p_hash[ser];
744 				ghash &= 0xFFFF;
745 			}
746 		}
747 	}
748 
749 	/*CONSTCOND*/
750 	while (1) {
751 		inserted = deleted = 0;
752 		gpkt.p_glnno = 0;
753 		gpkt.p_upd = 1;
754 		gpkt.p_wrttn = 1;
755 		getline(&gpkt);		/* Read the magic line */
756 		gpkt.p_chash = 0; 	/* Reset signed hash */
757 		gpkt.p_uchash = 0; 	/* Reset unsigned hash */
758 		gpkt.p_wrttn = 1;
759 		gpkt.p_ghash = ghash;	/* ghash may be destroyed in loop */
760 
761 		if (glist && gpkt.p_flags & PF_V6) {
762 			gpkt.p_ghash = 0; /* write 00000 before correcting */
763 		}
764         	if (HADF) {
765                 	newser = mkdelt(&gpkt, &gpkt.p_reqsid, &gpkt.p_gotsid,
766 				diffloop, orig);
767        		 } else {
768                 	newser = mkdelt(&gpkt,&pp->pf_nsid,&pp->pf_gsid,
769 				diffloop, orig);
770         	}
771 		diffloop = 1;
772 		flushto(&gpkt, EUSERTXT, FLUSH_COPY);
773 
774 		if (X.x_opts & XO_PREPEND_FILE) {
775 			/*
776 			 * Since we do not call "diff", we come here only once.
777 			 */
778 			Diffin = Gin;
779 			rewind(Diffin);
780 			Gin = NULL;
781 			inserted += number_of_lines;
782 			insert(&gpkt, 0, number_of_lines, newser, 0);
783 			status = 0;		/* Causes a break from while */
784 		} else {
785 			if (gpkt.p_encoding & EF_UUENCODE) {
786 				Diffin = dodiff(auxf(gpkt.p_file,'e'),
787 						dfilename, difflim);
788 			} else {
789 				Diffin = dodiff(gfilename, dfilename, difflim);
790 			}
791 			type = 0;			/* Make GCC quiet */
792 			while ((n = getdiff(&type,&linenum)) != 0) {
793 				if (type == INS) {
794 					inserted += n;
795 					insert(&gpkt, linenum , n, newser, 1);
796 				} else {
797 					deleted += n;
798 					delete(&gpkt,linenum,n,newser);
799 				}
800 			}
801 		}
802 		/*
803 		 * If the modifications added lines via putline() after the
804 		 * code above did hit EOF in the input s.file and thus caused
805 		 * a grewind(), we need to fix gpkt.p_onhash by the delta
806 		 * that results from these putline() calls.
807 		 */
808 		gpkt.p_onhash += gpkt.p_nhash;
809 		if (Diffin)
810 			fclose(Diffin);
811 		Diffin = NULL;
812 		/*
813 		 * Call readmod() only if there is remaining input from the
814 		 * s.file. This happens in case that we did not hit EOF on the
815 		 * input before.
816 		 */
817 		if (gpkt.p_iop && stell(&gpkt) > 0)
818 			while (readmod(&gpkt))
819 				;
820 		if ((X.x_opts & XO_PREPEND_FILE) == 0)
821 			wait(&status);
822  		/*
823  		 Check top byte (exit code of child).
824  		*/
825 
826  		/*
827 		 * 32 is the exit code below after a failed execlp() call.
828  		 */
829  		if (WEXITSTATUS(status) == 32) { /* 'execl' failed */
830  		   sprintf(SccsError,
831  		      gettext("cannot execute '%s' (de12)"), diffpgm);
832  		   fatal(SccsError);
833  		}
834  		if ((status != 0) && (HADD == 0)) { /* diff failed */
835 			/*
836 			Re-try.
837 			*/
838 			if (difflim -= 3000) {	/* reduce segmentation */
839 				fprintf(stderr,
840 					gettext("'%s' failed, re-trying, segmentation = %d (de13)\n"),
841  					diffpgm,
842 					difflim);
843 				xrm(&gpkt);		/* Close x-file */
844 				/*
845 				 * Rewind s-file.
846 				 */
847 				grewind(&gpkt);
848 				gpkt.p_reopen = 1;	/* Let it stay open */
849 			}
850 			else
851 				/* tried up to 500 lines, can't go on */
852 /*
853 TRANSLATION_NOTE
854 "diff" refers to the UNIX "diff" program, used by this SCCS "delta"
855 command, to check the differences found between two files.
856 */
857 				fatal(gettext("diff failed (de4)"));
858 		} else {		/* no need to try again, worked */
859 			break;			/* exit while loop */
860 		}
861 	}
862 	/*
863 	 * gpkt.p_nhash has been cleared by grewind(), restore remembered value.
864 	 */
865 	gpkt.p_nhash = gpkt.p_onhash;
866 
867 	if (gpkt.p_encoding & EF_UUENCODE) {
868 		unlink(auxf(gpkt.p_file,'e'));
869 	}
870 	if (dfilename[0]) {
871 		unlink(dfilename);
872 		dfilename[0] = '\0';
873 	}
874 	/*
875 	 * If we had a glist, the checked out file will differ from the checked
876 	 * in file. Check out the real new content and recompute + correct the
877 	 * ghash.
878 	 */
879 	if (glist && gpkt.p_flags & PF_V6)
880 		ghash = fixghash(&gpkt, newser);
881 
882 	stats.s_ins = inserted;
883 	stats.s_del = deleted;
884 	stats.s_unc = orig - deleted;
885 	if (gpkt.p_verbose) {
886 		fprintf(gpkt.p_stdout, gettext("%d inserted\n"), stats.s_ins);
887 		fprintf(gpkt.p_stdout, gettext("%d deleted\n"), stats.s_del);
888 		fprintf(gpkt.p_stdout, gettext("%d unchanged\n"),stats.s_unc);
889 	}
890 	flushline(&gpkt,&stats);
891 	stat(gpkt.p_file,&sbuf);
892 	processed_files = TRUE;
893 	rename(auxf(gpkt.p_file,'x'),gpkt.p_file);
894 	chmod(gpkt.p_file, (unsigned int)sbuf.st_mode);
895 
896 	chown(gpkt.p_file, (unsigned int)sbuf.st_uid,
897 			(unsigned int)sbuf.st_gid);
898 	if (HADO) {
899 		struct timespec	ts[2];
900 		extern dtime_t	Timenow;
901 
902 		ts[0].tv_sec = Timenow.dt_sec;
903 		ts[0].tv_nsec = Timenow.dt_nsec;
904 		ts[1].tv_sec = gfile_mtime.tv_sec;
905 		ts[1].tv_nsec = gfile_mtime.tv_nsec;
906 
907 		/*
908 		 * As SunPro make and gmake call sccs get when the time
909 		 * if s.file equals the time stamp of the g-file, make
910 		 * sure the s.file is a bit older.
911 		 */
912 		if (!(gpkt.p_flags & PF_V6)) {
913 			struct timespec	tn;
914 
915 			getnstimeofday(&tn);
916 			ts[1].tv_nsec = tn.tv_nsec;
917 		}
918 		if (ts[1].tv_nsec > 500000000)
919 			ts[1].tv_nsec -= 500000000;
920 
921 		utimensat(AT_FDCWD, gpkt.p_file, ts, 0);
922 	}
923 	if (!HADF || Pfilename[0] != '\0') {
924 		char	*qfile;
925 
926 		if (exists(qfile = auxf(gpkt.p_file, 'q'))) {
927 			Szqfile = Statbuf.st_size;
928 		}
929 		if (Szqfile) {
930 			rename(qfile, Pfilename);
931 		}
932 		else {
933 			xunlink(Pfilename);
934 		}
935 	}
936 
937 	if ((gpkt.p_flags & PF_V6) && Cs && gpkt.p_init_path) {
938 		char	cbuf[2*MAXPATHLEN];
939 
940 		gpkt.p_ghash = ghash;		/* Restore correct value */
941 		change_ba(&gpkt, cbuf, sizeof (cbuf));
942 		fprintf(Cs, "%s\n", cbuf);
943 	}
944 	sclose(&gpkt);
945 	clean_up();
946 	if (!HADN) {
947 		fflush(gpkt.p_stdout);
948 		holduid=geteuid();
949 		holdgid=getegid();
950 		setuid(getuid());
951 		setgid(getgid());
952 		unlink(gfilename);
953 		if (N.n_get) {
954 			doget(gpkt.p_file, gfilename, newser);
955 			if (HADO)
956 				dogtime(&gpkt, gfilename, &gfile_mtime);
957 		}
958 		setuid(holduid);
959 		setgid(holdgid);
960 	}
961 	if (did_intr)
962 		exit(2);
963 }
964 
965 /*
966  * Make the delta table for the current file
967  */
968 static int
mkdelt(pkt,sp,osp,diffloop,orig_nlines)969 mkdelt(pkt,sp,osp,diffloop,orig_nlines)
970 struct packet *pkt;
971 struct sid *sp, *osp;
972 int diffloop;
973 int orig_nlines;
974 {
975 	extern dtime_t Timenow;
976 	struct deltab dt;
977 	char str[max(BUFSIZ, SID_STRSIZE)];	/* Buffer for delta table IO */
978 	int newser;
979 	register char *p;
980 	int ser_inc, opred, nulldel;
981 
982 	if (!diffloop && pkt->p_verbose) {
983 		sid_ba(sp,str);
984 		fprintf(pkt->p_stdout,"%s\n",str);
985 		fflush(pkt->p_stdout);
986 	}
987 	putmagic(pkt, "00000");
988 	newstats(pkt,str,"0");
989 	dt.d_sid = *sp;
990 
991 	/*
992 	Check if 'null' deltas should be inserted
993 	(only if 'null' flag is in file and
994 	releases are being skipped) and set
995 	'nulldel' indicator appropriately.
996 	*/
997 	if (pkt->p_sflags[NULLFLAG - 'a'] && (sp->s_rel > osp->s_rel + 1) &&
998 			!sp->s_br && !sp->s_seq &&
999 			!osp->s_br && !osp->s_seq)
1000 		nulldel = 1;
1001 	else
1002 		nulldel = 0;
1003 	/*
1004 	Calculate how many serial numbers are needed.
1005 	*/
1006 	if (nulldel)
1007 		ser_inc = sp->s_rel - osp->s_rel;
1008 	else
1009 		ser_inc = 1;
1010 	/*
1011 	Find serial number of the new delta.
1012 	*/
1013 	newser = dt.d_serial = maxser(pkt) + ser_inc;
1014 	/*
1015 	Find old predecessor's serial number.
1016 	*/
1017 	opred = sidtoser(osp,pkt);
1018 	if (nulldel)
1019 		dt.d_pred = newser - 1;	/* set predecessor to 'null' delta */
1020 	else
1021 		dt.d_pred = opred;
1022 
1023 #ifdef	NO_NANOSECS
1024 	time2dt(&dt.d_dtime, Timenow, 0); /* Timenow was set by dodelt() */
1025 #else
1026 	dt.d_dtime = Timenow;		/* Timenow was set by dodelt() */
1027 #endif
1028 
1029         /* Since the NSE always preserves the clear file after delta and
1030          * makes it read only (no get is required since keywords are not
1031          * supported), the delta time is set to be the mtime of the clear
1032          * file.
1033          */
1034         if ((HADO || HADQ) && (gfile_mtime.tv_sec != 0)) {
1035 		time2dt(&dt.d_dtime, gfile_mtime.tv_sec, gfile_mtime.tv_nsec);
1036         }
1037 	if (X.x_opts & XO_DATE) {
1038 		dt.d_dtime = X.x_dtime;
1039 	}
1040 	strlcpy(dt.d_pgmr, logname(), LOGSIZE);
1041 	if (X.x_user)
1042 		strlcpy(dt.d_pgmr, X.x_user, LOGSIZE);
1043 	dt.d_type = 'D';
1044 	del_ba(&dt,str, pkt->p_flags & ~PF_GMT);
1045 	putline(pkt,str);
1046 	if (ilist)
1047 		mkixg(pkt,INCLUSER,INCLUDE);
1048 	if (elist)
1049 		mkixg(pkt,EXCLUSER,EXCLUDE);
1050 	if (glist)
1051 		mkixg(pkt,IGNRUSER,IGNORE);
1052 	if (Mrs) {
1053 		if ((p = pkt->p_sflags[VALFLAG - 'a']) == NULL)
1054 			fatal(gettext("MRs not allowed (de8)"));
1055 		if (*p && !diffloop && valmrs(pkt,p))
1056 			fatal(gettext("invalid MRs (de9)"));
1057 		putmrs(pkt);
1058 	} else if (pkt->p_sflags[VALFLAG - 'a'] && !HADQ) {
1059 		fatal(gettext("MRs required (de10)"));
1060 	}
1061 /*
1062 *
1063 * CMF enhancement
1064 *
1065 */
1066 	if (pkt->p_sflags[CMFFLAG - 'a']) {
1067 		if (Mrs) {
1068 			 cmrerror(gettext("input CMR's ignored"));
1069 			 Mrs = NOGETTEXT("");
1070 		}
1071 		if (!deltack(pkt->p_file,Cmrs,Nsid, pkt->p_sflags[CMFFLAG - 'a'], pkt->p_sflags)) {
1072 			 fatal(gettext("Delta denied due to CMR difficulties"));
1073 		}
1074 		putcmrs(pkt); /* this routine puts cmrs on the out put file */
1075 	}
1076 	if (pkt->p_flags & PF_V6) {
1077 		Checksum_offset = ftell(gpkt.p_xiop);
1078 		gpkt.p_mail = X.x_mail;
1079 		sidext_ba(pkt, &dt);
1080 		gpkt.p_mail = NULL;
1081 	}
1082 
1083 	sprintf(str, NOGETTEXT("%c%c "), CTLCHAR, COMMENTS);
1084 	putline(pkt,str);
1085 	{
1086 	  char *comment = savecmt(Comments);
1087 	  putline(pkt,comment);
1088 	  putline(pkt,"\n");
1089 	}
1090 	sprintf(str,CTLSTR,CTLCHAR,EDELTAB);
1091 	putline(pkt,str);
1092 	if (nulldel)			/* insert 'null' deltas */
1093 		while (--ser_inc) {
1094 			sprintf(str, NOGETTEXT("%c%c %s/%s/%05d\n"),
1095 			  CTLCHAR, STATS,
1096 			  NOGETTEXT("00000"), NOGETTEXT("00000"),
1097 			  orig_nlines);
1098 			putline(pkt,str);
1099 			dt.d_sid.s_rel -= 1;
1100 			dt.d_serial -= 1;
1101 			if (ser_inc != 1)
1102 				dt.d_pred -= 1;
1103 			else
1104 				dt.d_pred = opred;	/* point to old pred */
1105 			del_ba(&dt,str, pkt->p_flags);
1106 			putline(pkt,str);
1107 			sprintf(str, NOGETTEXT("%c%c "), CTLCHAR, COMMENTS);
1108 			putline(pkt,str);
1109 			putline(pkt,NOGETTEXT("AUTO NULL DELTA\n"));
1110 			sprintf(str,CTLSTR,CTLCHAR,EDELTAB);
1111 			putline(pkt,str);
1112 		}
1113 	return(newser);
1114 }
1115 
1116 /*
1117  * Write include/exclude/ignore table for delta table
1118  */
1119 static void
mkixg(pkt,reason,ch)1120 mkixg(pkt,reason,ch)
1121 struct packet *pkt;
1122 int reason;
1123 char ch;
1124 {
1125 	int n;
1126  	char str[BUFSIZ];	/* Only limits the size of a single entry */
1127 
1128 	sprintf(str, NOGETTEXT("%c%c"), CTLCHAR, ch);
1129 	putline(pkt,str);
1130 	for (n = maxser(pkt); n; n--) {
1131 		if (pkt->p_apply[n].a_reason == reason) {
1132 			sprintf(str, NOGETTEXT(" %u"), n);
1133 			putline(pkt,str);
1134 		}
1135 	}
1136 	putline(pkt,"\n");
1137 }
1138 
1139 static void
putmrs(pkt)1140 putmrs(pkt)
1141 struct packet *pkt;
1142 {
1143 	register char **argv;
1144 	char str[LENMR+6];
1145 	extern char **Varg;
1146 
1147 	for (argv = &Varg[VSTART]; *argv; argv++) {
1148 		sprintf(str, NOGETTEXT("%c%c %s\n"), CTLCHAR, MRNUM, *argv);
1149 		if (strcmp(str,NOGETTEXT("\001m \012")))
1150 			putline(pkt,str);
1151 	}
1152 }
1153 
1154 
1155 
1156 /*
1157 *
1158 *	putcmrs takes the cmrs list on the Mrs line built by deltack
1159 * 	and puts them in the packet
1160 *
1161 */
1162 static void
putcmrs(pkt)1163 putcmrs(pkt)
1164 struct packet *pkt;
1165 	{
1166 		char str[510];
1167 		sprintf(str, NOGETTEXT("%c%c %s\n"), CTLCHAR, MRNUM, Cmrs);
1168 		putline(pkt,str);
1169 	}
1170 
1171 
1172 static char ambig[] = NOGETTEXT("ambiguous `r' keyletter value (de15)");
1173 
1174 /*
1175  * Read the p-file and write a new version as q-file.
1176  */
1177 static struct pfile *
rdpfile(pkt,sp)1178 rdpfile(pkt,sp)
1179 register struct packet *pkt;
1180 struct sid *sp;
1181 {
1182 	char *user;
1183 	struct pfile pf;
1184 	static struct pfile goodpf;
1185 	char line[BUFSIZ];		/* Limits the line length of a p-file */
1186 	int cnt, uniq, fd;
1187 	FILE *in, *out;
1188 	char *outname;
1189 
1190 	uniq = cnt = -1;
1191 	if ((user=logname()) == NULL)
1192 	   fatal(gettext("User ID not in password file (cm9)"));
1193 	zero((char *)&goodpf,sizeof(goodpf));
1194 	in = xfopen(auxf(pkt->p_file,'p'), O_RDONLY|O_BINARY);
1195 	outname = auxf(pkt->p_file, 'q');
1196 	if ((fd=open(outname, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0444)) < 0) {
1197 	   efatal(gettext("cannot create lock file (cm4)"));
1198 	}
1199 #ifdef	HAVE_FCHMOD
1200 	fchmod(fd, (mode_t)0644);
1201 #else
1202 	chmod(outname, (mode_t)0644);
1203 #endif
1204 	out = fdfopen(fd, O_WRONLY|O_BINARY);
1205 	while (fgets(line,sizeof(line),in) != NULL) {
1206 		pf_ab(line,&pf,1);
1207 		pf.pf_date = cutoff;
1208 		if (equal(pf.pf_user,user)||getuid()==0) {
1209 			if (sp->s_rel == 0) {
1210 				if (++cnt) {
1211 					if (fflush(out) == EOF)
1212 						xmsg(outname, NOGETTEXT("rdpfile"));
1213 #ifdef	HAVE_FSYNC
1214 					if (fsync(fileno(out)) < 0)
1215 						xmsg(outname, NOGETTEXT("rdpfile"));
1216 #endif
1217 					if (fclose(out) == EOF)
1218 						xmsg(outname, NOGETTEXT("rdpfile"));
1219 					fclose(in);
1220 					fatal(gettext("missing -r argument (de1)"));
1221 				}
1222 				goodpf = pf;
1223 				continue;
1224 			}
1225 			else if ((sp->s_rel == pf.pf_nsid.s_rel &&
1226 				sp->s_lev == pf.pf_nsid.s_lev &&
1227 				sp->s_br == pf.pf_nsid.s_br &&
1228 				sp->s_seq == pf.pf_nsid.s_seq) ||
1229 				(sp->s_rel == pf.pf_gsid.s_rel &&
1230 				sp->s_lev == pf.pf_gsid.s_lev &&
1231 				sp->s_br == pf.pf_gsid.s_br &&
1232 				sp->s_seq == pf.pf_gsid.s_seq)) {
1233 					if (++uniq) {
1234 						if (fflush(out) == EOF)
1235 							xmsg(outname, NOGETTEXT("rdpfile"));
1236 #ifdef	HAVE_FSYNC
1237 						if (fsync(fileno(out)) < 0)
1238 							xmsg(outname, NOGETTEXT("rdpfile"));
1239 #endif
1240 						if (fclose(out) == EOF)
1241 							xmsg(outname, NOGETTEXT("rdpfile"));
1242 						fclose(in);
1243 						fatal(ambig);
1244 					}
1245 					goodpf = pf;
1246 					continue;
1247 			}
1248 		}
1249 		if(fputs(line,out)==EOF)
1250 			xmsg(outname, NOGETTEXT("rdpfile"));
1251 	}
1252 	fflush(stderr);
1253 	if (fflush(out) == EOF)
1254 		xmsg(outname, NOGETTEXT("rdpfile"));
1255 #ifdef	HAVE_FSYNC
1256 	if (fsync(fileno(out)) < 0)
1257 		xmsg(outname, NOGETTEXT("rdpfile"));
1258 #endif
1259 	if (fclose(out) == EOF)
1260 		xmsg(outname, NOGETTEXT("rdpfile"));
1261 	copy(auxf(pkt->p_file,'p'),Pfilename);
1262 	fclose(in);
1263 	if (!goodpf.pf_user[0])
1264 		fatal(gettext("login name or SID specified not in p-file (de2)"));
1265 	return(&goodpf);
1266 }
1267 
1268 /*
1269  * Open a FILE * to the diff output.
1270  */
1271 static FILE *
dodiff(newf,oldf,difflim)1272 dodiff(newf,oldf,difflim)
1273 char *newf, *oldf;
1274 int difflim;
1275 {
1276 	register int i;
1277 	register int n;
1278 	int pfd[2];
1279 	FILE *iop;
1280 	char num[10];
1281 	struct rlimit	rlim;
1282 
1283 	if (HADUCD)
1284 		return  (xfopen(Dfilename, O_RDONLY|O_BINARY));
1285 	xpipe(pfd);
1286 	if ((i = vfork()) < 0) {
1287 		int	errsav = errno;
1288 
1289 		close(pfd[0]);
1290 		close(pfd[1]);
1291 		errno = errsav;
1292 		efatal(gettext("cannot fork, try again (de11)"));
1293 	}
1294 	else if (i == 0) {
1295 #ifdef	set_child_standard_fds
1296 		set_child_standard_fds(STDIN_FILENO,
1297 					pfd[1],
1298 					STDERR_FILENO);
1299 #ifdef	F_SETFD
1300 		fcntl(pfd[0], F_SETFD, 1);
1301 		n = getdtablesize();	/* We are single threaded, so cache */
1302 		for (i = 5; i < n; i++)
1303 			fcntl(i, F_SETFD, 1);
1304 #endif
1305 #else
1306 		close(pfd[0]);
1307 		close(1);
1308 		dup(pfd[1]);
1309 		close(pfd[1]);
1310 
1311 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
1312 		/*
1313 		 * Set max # of file descriptors to allow bdiff to hold all
1314 		 * files open and to reduce the number of files to close.
1315 		 */
1316 		getrlimit(RLIMIT_NOFILE, &rlim);
1317 		if (rlim.rlim_cur > 20)
1318 			rlim.rlim_cur = 20;	/* Suffifient for bdiff/diff */
1319 		setrlimit(RLIMIT_NOFILE, &rlim);
1320 #endif
1321 		n = getdtablesize();	/* We are single threaded, so cache */
1322 		for (i = 5; i < n; i++)
1323 			close(i);
1324 #endif
1325 		sprintf(num, NOGETTEXT("%d"), difflim);
1326 		/*
1327 		 * Since we support un-uuencoded handling of binary data, we
1328 		 * need to call diff -a with delta -d. It is granted that
1329 		 * Diffpgmp is a diff(1) version that supports -a.
1330 		 */
1331  		if (HADD) {
1332 #if	defined(PROTOTYPES) && defined(INS_BASE)
1333 		   diffpgm = Diffpgmp;
1334  		   execl(Diffpgmp, Diffpgmp, "-a", oldf, newf, (char *)0);
1335 #endif
1336 		   diffpgm = Diffpgm;
1337  		   execl(Diffpgm, Diffpgm, "-a", oldf, newf, (char *)0);
1338 		   diffpgm = Diffpgm2;
1339  		   execl(Diffpgm2, Diffpgm2, "-a", oldf, newf, (char *)0);
1340 #ifdef	USE_FSDIFF
1341  		} else if (HADB) {
1342 #else
1343  		} else {
1344 #endif
1345 #if	defined(PROTOTYPES) && defined(INS_BASE)
1346 		   diffpgm = BDiffpgmp;
1347  		   execl(BDiffpgmp,BDiffpgmp,oldf,newf,num,"-s", (char *)0);
1348 #endif
1349 		   diffpgm = BDiffpgm;
1350  		   execl(BDiffpgm,BDiffpgm,oldf,newf,num,"-s", (char *)0);
1351 		   diffpgm = BDiffpgm2;
1352  		   execl(BDiffpgm2,BDiffpgm2,oldf,newf,num,"-s", (char *)0);
1353 #ifdef	USE_FSDIFF
1354  		} else {
1355 		   diffpgm = FDiffpgmp;
1356  		   execl(FDiffpgmp, FDiffpgmp, oldf, newf, (char *)0);
1357 #endif
1358 		}
1359 		close(1);
1360 		_exit(32);	/* tell parent that 'execl' failed */
1361 	}
1362 	else {
1363 		close(pfd[1]);
1364 		iop = fdfopen(pfd[0], O_RDONLY|O_BINARY);
1365 		return(iop);
1366 	}
1367 	/*NOTREACHED*/
1368 	return (0);	/* fake for gcc */
1369 }
1370 
1371 /*
1372  * Parse the part of the diff output that contains the line numbers and the
1373  * delete/append/change instructions.
1374  */
1375 static int
getdiff(type,plinenum)1376 getdiff(type,plinenum)
1377 register char *type;
1378 register int *plinenum;
1379 {
1380 #define	LINE_SIZE	1024			/* not too large for memset() */
1381 	long line[LINE_SIZE/sizeof (long) + 1];	/* align to speed up memset() */
1382 	register char *p;
1383 	int num_lines = 0;
1384 	static int chg_num, chg_ln;
1385 	int lowline, highline;
1386 	int	llen;
1387 
1388 	if ((p = rddiff((char *)line, LINE_SIZE+1, &llen)) == NULL)
1389 		return(0);
1390 
1391 	if (*p == '-') {
1392 		*type = INS;
1393 		*plinenum = chg_ln;
1394 		num_lines = chg_num;
1395 	}
1396 	else {
1397 		p = linerange(p,&lowline,&highline);
1398 		*plinenum = lowline;
1399 
1400 		switch(*p++) {
1401 		case 'd':
1402 			num_lines = highline - lowline + 1;
1403 			*type = DEL;
1404 			skipline((char *)line, num_lines);
1405 			break;
1406 
1407 		case 'a':
1408 			linerange(p,&lowline,&highline);
1409 			num_lines = highline - lowline + 1;
1410 			*type = INS;
1411 			break;
1412 
1413 		case 'c':
1414 			chg_ln = lowline;
1415 			num_lines = highline - lowline + 1;
1416 			linerange(p,&lowline,&highline);
1417 			chg_num = highline - lowline + 1;
1418 			*type = DEL;
1419 			skipline((char *)line, num_lines);
1420 			break;
1421 		}
1422 	}
1423 
1424 	return(num_lines);
1425 }
1426 
1427 /*
1428  * Skip the next chunk of kept lines from the old file and then
1429  * insert the new lines from the diff output.
1430  */
1431 static void
insert(pkt,linenum,n,ser,off)1432 insert(pkt, linenum, n, ser, off)
1433 struct	packet	*pkt;
1434 int	linenum, n, ser;
1435 	int	off;
1436 {
1437 	long	str[LINE_SIZE/sizeof (long) + 1];	/* align for memset() */
1438 	char	*s = (char *)str;
1439  	int 	first;
1440 	int	nonl = 0;
1441 	int	llen;
1442 
1443 	/*
1444 	 * We only count newlines and thus need to add one to number_of_lines
1445 	 * to get the same view as bdiff/diff.
1446 	 */
1447 	if ((pkt->p_props & CK_NONL) && (linenum + n) >= (number_of_lines+1)) {
1448 		if ((pkt->p_encoding & EF_UUENCODE) == 0) {
1449 			nonl++;
1450 		}
1451 	}
1452 
1453 	after(pkt, linenum);
1454 	sprintf(s, NOGETTEXT("%c%c %d\n"), CTLCHAR, INS, ser);
1455 	putline(pkt, s);
1456 	if (off)
1457 		off = 2;			/* strlen("> ") from diff */
1458 	while (--n >= 0) {
1459  		first = 1;
1460  		for (;;) {			/* Loop over partial line */
1461 			if (rddiff(s, LINE_SIZE+1, &llen) == NULL) {
1462 				fatal(gettext("Cannot read the diffs file (de19)"));
1463 			}
1464 			if (first) {
1465 				first = 0;
1466 				if (n == 0 && nonl) {	/* No newline at end */
1467 					putctlnnl(pkt);	/* ^AN escape	    */
1468 				} else if (s[off] == CTLCHAR) /* ^A escape? */
1469 					putctl(pkt);
1470 				putlline(pkt, s+off, llen-off);	/* Skip "> " */
1471 			} else {
1472 				putlline(pkt, s, llen);
1473 			}
1474 			if (s[llen-1] == '\n') {
1475 				break;
1476 			}
1477 		}
1478 	}
1479 	sprintf(s, NOGETTEXT("%c%c %d\n"), CTLCHAR, END, ser);
1480 	putline(pkt, s);
1481 }
1482 
1483 /*
1484  * Add delete markers in the weave data.
1485  */
1486 static void
delete(pkt,linenum,n,ser)1487 delete(pkt, linenum, n, ser)
1488 struct	packet	*pkt;
1489 int	linenum, n, ser;
1490 {
1491 	char str[BUFSIZ];	/* Only used for ^A lines in the weave */
1492 
1493 	before(pkt, linenum);
1494 	sprintf(str, NOGETTEXT("%c%c %d\n"), CTLCHAR, DEL, ser);
1495 	putline(pkt, str);
1496 	after(pkt, linenum + n - 1);
1497 	sprintf(str, NOGETTEXT("%c%c %d\n"), CTLCHAR, END, ser);
1498 	putline(pkt, str);
1499 }
1500 
1501 static void
after(pkt,n)1502 after(pkt, n)
1503 struct	packet	*pkt;
1504 int	n;
1505 {
1506 	before(pkt, n);
1507 	if (pkt->p_glnno == n) {
1508 		for (;;) {
1509 			if (pkt->p_line[pkt->p_line_length-1] != '\n') {
1510 				getline(pkt);
1511 			}
1512 			else {
1513 				putline(pkt, (char *)0);
1514 				break;
1515 			}
1516 		}
1517 	}
1518 }
1519 
1520 static void
before(pkt,n)1521 before(pkt, n)
1522 struct	packet	*pkt;
1523 int	n;
1524 {
1525 	while (pkt->p_glnno < n) {
1526 		if (!readmod(pkt))
1527 			break;
1528 	}
1529 }
1530 
1531 /*
1532  * Parse the line range from the diff output
1533  */
1534 static char *
linerange(cp,low,high)1535 linerange(cp, low, high)
1536 char	*cp;
1537 int	*low, *high;
1538 {
1539 	cp = satoi(cp, low);
1540 	if (*cp == ',')
1541 		cp = satoi(++cp, high);
1542 	else
1543 		*high = *low;
1544 
1545 	return(cp);
1546 }
1547 
1548 /*
1549  * Skip lines from the diff outout, e.g. lines that start with "< ".
1550  */
1551 static void
skipline(lp,num)1552 skipline(lp, num)
1553 char	*lp;
1554 int	num;
1555 {
1556 	int	llen;
1557 
1558  	for (++num; --num; ) {
1559  		do {
1560  		   (void)rddiff(lp, LINE_SIZE+1, &llen);
1561  		} while (lp[llen-1] != '\n');
1562  	}
1563 }
1564 
1565 /*
1566  * This is the central read routine.
1567  * fgets() is a faulty construction as it does not return the # of bytes read.
1568  * fgets() always nul terminates the bytes read, so filling the buffer allows
1569  * to detect how many bytes have been read.
1570  */
1571 static char *
rddiff(s,n,ll)1572 rddiff(s, n, ll)
1573 	char	*s;	/* Buffer to fill */
1574 	int	n;	/* size of buffer */
1575 	int	*ll;	/* # of bytes read */
1576 {
1577 	char	*r;
1578 
1579 	(void) memset(s, '\377', n);	/* Filling allows to detect real end */
1580 	if ((r = fgets(s, n, Diffin)) != NULL) {
1581 		int l = strlen(r);
1582 
1583 		if (r[l-1] != '\n') {	/* Rare case: too long or with nul */
1584 			for (l = n; --l >= 0; )
1585 				if (r[l] == '\0')
1586 					break;
1587 		}
1588 		*ll = l;
1589 		if (HADP) {
1590 			if (fwrite(s, 1, l, gpkt.p_stdout) != l)
1591 				FAILPUT;
1592 		}
1593 	}
1594 	return (r);
1595 }
1596 
1597 static void
enter(pkt,ch,n,sidp)1598 enter(pkt,ch,n,sidp)
1599 struct packet *pkt;
1600 char ch;
1601 int n;
1602 struct sid *sidp;
1603 {
1604 	char str[SID_STRSIZE];
1605 	register struct apply *ap;
1606 
1607 	sid_ba(sidp,str);
1608 	ap = &pkt->p_apply[n];
1609 	if (pkt->p_cutoff > pkt->p_idel[n].i_datetime.tv_sec)
1610 		switch(ap->a_code) {
1611 
1612 		case SX_EMPTY:
1613 			switch (ch) {
1614 			case INCLUDE:
1615 				condset(ap,APPLY,INCLUSER);
1616 				break;
1617 			case EXCLUDE:
1618 				condset(ap,NOAPPLY,EXCLUSER);
1619 				break;
1620 			case IGNORE:
1621 				condset(ap,SX_EMPTY,IGNRUSER);
1622 				break;
1623 			}
1624 			break;
1625 		case APPLY:
1626 			fatal(gettext("internal error in delta/enter() (de5)"));
1627 			break;
1628 		case NOAPPLY:
1629 			fatal(gettext("internal error in delta/enter() (de6)"));
1630 			break;
1631 		default:
1632 			fatal(gettext("internal error in delta/enter() (de7)"));
1633 			break;
1634 		}
1635 }
1636 
1637 static void
clean_up()1638 clean_up()
1639 {
1640 	uname(&un);
1641 	uuname = un.nodename;
1642 	if (mylock(auxf(gpkt.p_file,'z'), getpid(),uuname)) {
1643 		sclose(&gpkt);
1644 		sfree(&gpkt);
1645 		if (gpkt.p_xiop) {
1646 			fclose(gpkt.p_xiop);
1647 			gpkt.p_xiop = NULL;
1648 			unlink(auxf(gpkt.p_file,'x'));
1649 		}
1650 		if(Gin) {
1651 			fclose(Gin);
1652 			Gin = NULL;
1653 		}
1654 		unlink(auxf(gpkt.p_file,'d'));
1655 		unlink(auxf(gpkt.p_file,'q'));
1656 		if (gpkt.p_encoding & EF_UUENCODE) {
1657 			unlink(auxf(gpkt.p_file,'e'));
1658 		}
1659 		xrm(&gpkt);
1660 		ffreeall();
1661 		uname(&un);
1662 		uuname = un.nodename;
1663 		timersetlockfile(NULL);
1664 		if (!islockchset(Zhold))
1665 			unlockit(Zhold, getpid(), uuname);
1666 	}
1667 	if (SETHOME_CHSET() && !processed_files) {
1668 		unlockchset(getpid(), uuname);
1669 	}
1670 }
1671 
1672 /*
1673  * Compute the checksum for the new version and check for characters that
1674  * are not allowed in the file.
1675  *
1676  * SCCSv4 disallows ^A (0x01) at the start of a line, nul bytes and requires a
1677  *	newline at the end of the file.
1678  *
1679  * SCCSv6 currently disallows nul bytes in the file.
1680  *	Since our diff(1) implementation supports to treat even files with
1681  *	nul bytes as text files, we could support nul bytes in the future.
1682  *
1683  * Both versions allow an unlimited line length.
1684  *
1685  * Since fgets() does not report the amount of bytes read, we cannot support
1686  * nul bytes on platforms with record oriented IO (VMS).
1687  */
1688 /*ARGSUSED*/
1689 static void
fgetchk(file,pkt)1690 fgetchk(file, pkt)
1691 char	*file;
1692 struct	packet	*pkt;
1693 {
1694 	FILE	*inptr;
1695 #ifndef	RECORD_IO
1696 	char	*p = NULL;	/* Intialize to make gcc quiet */
1697 	char	*pn =  NULL;
1698 	char	line[VBUF_SIZE+1];
1699 #else
1700 	char	line[BUFSIZ];
1701 	int	search_on = 0;
1702 #endif
1703 	off_t	nline;
1704 	off_t	soh = -1;	/* Last line # that starts with ^A */
1705 	int	isctl;
1706 	int	idx = 0;
1707 	int	warned = 0;
1708 	int	nwarned = 0;
1709 	char	chkflags = 0;
1710 	char	lastchar;
1711 	unsigned int sum = 0;
1712 	int	pktv6 = pkt->p_flags & PF_V6;
1713 
1714 	inptr = xfopen(file, O_RDONLY|O_BINARY);
1715 #ifdef	USE_SETVBUF
1716 	setvbuf(inptr, NULL, _IOFBF, VBUF_SIZE);
1717 #endif
1718 	/*
1719 	 * This gives the illusion that a zero-length file ends
1720 	 * in a newline so that it won't be mistaken for a
1721 	 * binary file.
1722 	 */
1723 	lastchar = '\n';
1724 	(void)memset(line, '\377', sizeof (line));
1725 	nline = 0;
1726 #ifndef	RECORD_IO
1727 	/*
1728 	 * In most cases (non record oriented I/O), we can optimize the way we
1729 	 * scan files for '\0' bytes, line-ends '\n' and ^A '\1'. The optimized
1730 	 * algorithm allows to avoid to do a reverse scan for '\0' from the end
1731 	 * of the buffer.
1732 	 */
1733 	while ((idx = fread(line, 1, sizeof (line) - 1, inptr)) > 0) {
1734 		sum += usum(line, idx);
1735 		if (lastchar == '\n' && line[0] == CTLCHAR) {
1736 			chkflags |= CK_CTLCHAR;
1737 			soh = nline;
1738 			if (pktv6 == 0)
1739 				goto err;
1740 			if (!warned) {
1741 				warnctl(file, nline+1);
1742 				warned = 1;
1743 			}
1744 		}
1745 		lastchar = line[idx-1];
1746 		p = findbytes(line, idx, '\0');
1747 		if (p != NULL) {
1748 			chkflags |= CK_NULL;
1749 			pn = p;
1750 		}
1751 		for (p = line;
1752 		    (p = findbytes(p, idx - (p-line), '\n')) != NULL; p++) {
1753 			if (pn && p > pn) {		/* '\0' before '\n' */
1754 				if (pktv6) {
1755 					if (!nwarned) {
1756 						warnnull(file, nline);
1757 						nwarned = 1;
1758 					}
1759 				} else {
1760 					goto err;
1761 				}
1762 			}
1763 			nline++;
1764 			if ((p - line) >= (idx-1))	/* '\n' last in buf */
1765 				break;
1766 
1767 			if (p[1] == CTLCHAR) {
1768 				chkflags |= CK_CTLCHAR;
1769 	err:
1770 				if (pktv6 &&
1771 				    (p[1] == CTLCHAR)) {
1772 					if (!warned) {
1773 						warnctl(file, nline+1);
1774 						warned = 1;
1775 					}
1776 					continue;
1777 				}
1778 				fclose(inptr);
1779 				isctl = soh == nline;
1780 				sprintf(SccsError,
1781 				gettext(
1782 			  isctl ?
1783 			  "file '%s' begins with '\\001' on line %jd (de20)":
1784 			  "file '%s' contains '\\000' on line %jd (de14)"),
1785 				file, (Intmax_t)++nline);
1786 				fatal(SccsError);
1787 			}
1788 		}
1789 		line[idx] = '\0';
1790 		if (pkt->p_did_id == 0) {
1791 			pkt->p_did_id =
1792 				chkid(line, pkt->p_sflags[IDFLAG - 'a'], pkt->p_sflags);
1793 		}
1794 	}
1795 #else	/* !RECORD_IO */
1796 	/*
1797 	 * We support nul bytes with fgets() by pre-filling the buffer.
1798 	 */
1799 	while (fgets(line, sizeof (line), inptr) != NULL) {
1800 	   if (lastchar == '\n' && line[0] == CTLCHAR) {
1801 	      chkflags |= CK_CTLCHAR;
1802 	      soh = nline;
1803 	      if (pktv6 == 0) {
1804 		nline++;
1805 		goto err;
1806 	      }
1807 	      if (!warned) {
1808 		warnctl(file, nline+1);
1809 		warned = 1;
1810 	      }
1811 	   }
1812 	   search_on = 0;
1813 	   for (idx = sizeof (line)-1; idx >= 0; idx--) {
1814 	      if (search_on > 0) {
1815 		 if (line[idx] == '\0') {
1816 		    chkflags |= CK_NULL;
1817 	err:
1818 		    if (pktv6) {
1819 			if ((chkflags & CK_NULL) && !nwarned) {
1820 				warnnull(file, nline);
1821 				nwarned = 1;
1822 			}
1823 			continue;
1824 		    }
1825 		    fclose(inptr);
1826 		    isctl = soh == nline;
1827 		    sprintf(SccsError,
1828 		      gettext(
1829 			  isctl ?
1830 			  "file '%s' begins with '\\001' on line %jd (de20)":
1831 			  "file '%s' contains '\\000' on line %jd (de14)"),
1832 		      file, (Intmax_t)nline);
1833 		    fatal(SccsError);
1834 		 }
1835 	      } else {
1836 		 if (line[idx] == '\0') {
1837 		    sum += usum(line, idx);
1838 		    search_on = 1;
1839 		    lastchar = line[idx-1];
1840 		    if (lastchar == '\n') {
1841 		       nline++;
1842 		    }
1843 		 }
1844 	      }
1845 	   }
1846 	   if (pkt->p_did_id == 0) {
1847 		pkt->p_did_id =
1848 			chkid(line, pkt->p_sflags[IDFLAG - 'a'], pkt->p_sflags);
1849 	   }
1850 	   (void)memset(line, '\377', sizeof (line));
1851 	}
1852 #endif	/* !RECORD_IO */
1853 	fclose(inptr);
1854 
1855 	pkt->p_ghash = sum & 0xFFFF;
1856 	pkt->p_glines = nline;
1857 
1858 	if (lastchar != '\n')
1859 		chkflags |= CK_NONL;
1860 	pkt->p_props |= chkflags;
1861 
1862 	if (chkflags & CK_NONL) {
1863 #ifndef	RECORD_IO
1864 		if (!pktv6)
1865 		if (pn && nline == 0)	/* Found null byte but no newline */
1866 			goto err;
1867 #endif
1868 		if (pktv6 == 0) {
1869 			sprintf(SccsError,
1870 			    gettext("No newline at end of file '%s' (de18)"),
1871 			    file);
1872 			fatal(SccsError);
1873 		} else {
1874 			fprintf(stderr,
1875 			    gettext("WARNING [%s]: No newline at end of file (de18)\n"),
1876 			    file);
1877 		}
1878 	}
1879 }
1880 
1881 static void
warnctl(file,nline)1882 warnctl(file, nline)
1883 	char	*file;
1884 	off_t	nline;
1885 {
1886 	fprintf(stderr,
1887 		gettext(
1888 		"WARNING [%s]: line %jd begins with ^A\n"),
1889 		file, (Intmax_t)nline);
1890 }
1891 
1892 static void
warnnull(file,nline)1893 warnnull(file, nline)
1894 	char	*file;
1895 	off_t	nline;
1896 {
1897 	fprintf(stderr,
1898 		gettext(
1899 		"WARNING [%s]: line %jd contains a '\\000'\n"),
1900 		file, (Intmax_t)nline);
1901 }
1902 
1903 static int
fixghash(pkt,ser)1904 fixghash(pkt, ser)
1905 	struct	packet	*pkt;
1906 	int		ser;
1907 {
1908 	char		ghbuf[10];
1909 	signed char	*q;
1910 	struct packet	pk2;
1911 	struct stats	stats;
1912 
1913 	putline(pkt,(char *) 0);	/* Flush last unwritten line	*/
1914 	fflush(pkt->p_xiop);		/* Flush stdio buffers		*/
1915 
1916 	sinit(&pk2, auxf(pkt->p_file,'x'), SI_OPEN|SI_FORCE);
1917 
1918 	pk2.do_chksum = 0;		/* Checksums are still wrong	*/
1919 	pk2.p_stdout = stderr;
1920 	pk2.p_cutoff = MAX_TIME;
1921 
1922 	if (dodelt(&pk2, &stats, (struct sid *) 0, 0) == 0)
1923 		fmterr(&pk2);
1924 	flushto(&pk2, EUSERTXT, FLUSH_NOCOPY);
1925 
1926 	pk2.p_chkeof = 1;
1927 	pk2.p_gotsid = pk2.p_idel[ser].i_sid;
1928 	pk2.p_reqsid = pk2.p_gotsid;
1929 
1930 	setup(&pk2, ser);
1931 
1932 	pk2.p_ghash = 0;
1933 	while (readmod(&pk2))		/* Compute ghash for gotten content */
1934 		;
1935 	pk2.p_ghash &= 0xFFFF;
1936 
1937 	fseek(pkt->p_xiop, Checksum_offset, SEEK_SET);
1938 	fprintf(pkt->p_xiop, "%c%c s %5.5d\n",
1939 		CTLCHAR, SIDEXTENS, pk2.p_ghash);
1940 	pkt->p_nhash -= 5 * '0';
1941 	sprintf(ghbuf, "%5.5d", pk2.p_ghash);
1942 	q = (signed char *) ghbuf;
1943 	while (*q)
1944 		pkt->p_nhash += *q++;
1945 
1946 	return (pk2.p_ghash);
1947 }
1948 
1949 /* SVR4.0 does not support getdtablesize().				  */
1950 
1951 #ifndef	HAVE_GETDTABLESIZE
1952 int
getdtablesize()1953 getdtablesize()
1954 {
1955 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1956 	struct rlimit	rlim;
1957 
1958 	rlim.rlim_cur = 20;
1959 	getrlimit(RLIMIT_NOFILE, &rlim);
1960 	return (rlim.rlim_cur);
1961 #endif
1962 	return (20);
1963 }
1964 #endif
1965 
1966 /*
1967  * Since we introduced a global lock file, this is needed in order to
1968  * be able to remove the global lock file in case that no real work has
1969  * yet been done. This typically helps to automatically remove the global
1970  * lock file if you type ^C while delta(1) is asking for delta comments and
1971  * did not yet process any file.
1972  */
1973 static RETSIGTYPE
intr(sig)1974 intr(sig)
1975 	int	sig;
1976 {
1977 	did_intr = TRUE;
1978 	if (!processed_files) {
1979 		clean_up();
1980 		exit(2);
1981 	}
1982 }
1983 
1984 static void
setintr()1985 setintr()
1986 {
1987 #if	defined(HAVE_SIGPROCMASK) && defined(SA_RESTART)
1988 	struct sigaction sa;
1989 
1990 	sigemptyset(&sa.sa_mask);
1991 	sa.sa_handler = intr;
1992 	sa.sa_flags = SA_RESTART;
1993 	(void) sigaction(SIGINT, &sa, (struct sigaction *)0);
1994 #else
1995 #ifdef	HAVE_SIGSETMASK
1996 	struct sigvec	sv;
1997 
1998 	sv.sv_mask = 0;
1999 	sv.sv_handler = intr;
2000 	sv.sv_flags = 0;
2001 	(void) sigvec(SIGINT, &sv, (struct sigvec *)0);
2002 #else
2003 #ifdef	HAVE_SIGSET
2004 	sigset(SIGINT, intr);
2005 #else
2006 	signal(SIGINT, intr);
2007 #endif
2008 #endif
2009 #endif
2010 }
2011