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 2003 Sun Microsystems, Inc. All rights reserved.
27  * Use is subject to license terms.
28  */
29 /*
30  * Copyright 2006-2020 J. Schilling
31  *
32  * @(#)val.c	1.71 20/09/10 J. Schilling
33  */
34 #if defined(sun)
35 #pragma ident "@(#)val.c 1.71 20/09/10 J. Schilling"
36 #endif
37 /*
38  * @(#)val.c 1.22 06/12/12
39  */
40 
41 #if defined(sun)
42 #pragma ident	"@(#)val.c"
43 #pragma ident	"@(#)sccs:cmd/val.c"
44 #endif
45 /************************************************************************/
46 /*									*/
47 /*  val -								*/
48 /*  val [-mname] [-rSID] [-s] [-ytype] file ...				*/
49 /*									*/
50 /************************************************************************/
51 
52 #define		SCCS_MAIN	/* define global vars */
53 #include	<defines.h>
54 #include	<version.h>
55 #include	<had.h>
56 #include	<i18n.h>
57 #include	<ccstypes.h>
58 #include	<schily/sysexits.h>
59 
60 #define	FILARG_ERR	0200	/* no file name given */
61 #define	UNKDUP_ERR	0100	/* unknown or duplicate keyletter */
62 #define	CORRUPT_ERR	040	/* corrupt file error code */
63 #define	FILENAM_ERR	020	/* file name error code */
64 #define	INVALSID_ERR	010	/* invalid or ambiguous SID error  */
65 #define	NONEXSID_ERR	04	/* non-existent SID error code */
66 #define	TYPE_ERR	02	/* type arg value error code */
67 #define	NAME_ERR	01	/* name arg value error code */
68 #define	TRUE		1
69 #define	FALSE		0
70 #define	BLANK(l)	while (!(*l == '\0' || *l == ' ' || *l == '\t')) l++;
71 
72 static int	silent;		/* be silent, report only in exit code */
73 static int	debug;		/* print debug messages */
74 static int	ret_code;	/* prime return code from 'main' program */
75 static int	inline_err = 0;	/* input line error code (from 'process') */
76 static int	infile_err = 0;	/* file error code (from 'validate') */
77 static int	inpstd;		/* TRUE = args from standard input */
78 
79 static struct packet gpkt;
80 static Nparms	N;			/* Keep -N parameters		*/
81 static Xparms	X;			/* Keep -X parameters		*/
82 
83 static struct deltab dt;
84 static struct deltab odt;
85 
86 static char	path[FILESIZE];	/* storage for file name value */
87 static char	sid[50];	/* storage for sid  (-r) value */
88 static char	type[50];	/* storage for type (-y) value */
89 static char	name[50];	/* storage for name (-m) value */
90 static char	*Argv[BUFSIZ];
91 static char	line[BUFSIZ];
92 static char	save_line[BUFSIZ];
93 
94 static struct delent {		/* structure for delta table entry */
95 	char type;		/* Type: D, R or U		*/
96 	char *osid;		/* SID from delta		*/
97 	char *datetime;		/* Whole datetime string	*/
98 	char *pgmr;		/* Programmer name		*/
99 	char *serial;		/* Serial number for this delta	*/
100 	char *pred;		/* Serial # for predecessor	*/
101 } del;
102 
103 	int	main __PR((int argc, char **argv));
104 static void	process __PR((char *p_line, int argc, char **argv));
105 static void	do_validate __PR((char *c_path));
106 static void	validate __PR((char *c_path, char *c_sid, char *c_type, char *c_name));
107 static void	getdel __PR((struct delent *delp, char *lp, struct packet *pkt));
108 static void	read_to __PR((int ch, struct packet *pkt));
109 static void	report __PR((int code, char *inp_line, char *file));
110 static char *	get_line __PR((struct packet *pkt));	/* function returning ptr to line read */
111 static void	s_init __PR((struct packet *pkt, char *file));
112 static int	read_mod __PR((struct packet *pkt));
113 static void	add_q __PR((struct packet *pkt, int ser, int keep, int iord, int user));
114 static void	rem_q __PR((struct packet *pkt, int ser));
115 static void	set_keep __PR((struct packet *pkt));
116 static int	chk_ix __PR((struct queue *new, struct queue *head));
117 static int	do_delt __PR((struct packet *pkt, int goods, char *d_sid));
118 static int	getstats __PR((struct packet *pkt));
119 static char *	getastat __PR((char *p, int  *ip));
120 static void	get_setup	__PR((char *file));
121 static void	get_close	__PR((void));
122 static int	get_hashtest	__PR((int ser));
123 
124 
125 /* This is the main program that determines whether the command line
126  * comes from the standard input or read off the original command
127  * line.  See VAL(I) for more information.
128 */
129 
130 int
main(argc,argv)131 main(argc, argv)
132 int argc;
133 char	*argv[];
134 {
135 	FILE	*iop;
136 	char *lp;
137 
138 	/*
139 	 * Set locale for all categories.
140 	 */
141 	setlocale(LC_ALL, NOGETTEXT(""));
142 
143 	sccs_setinsbase(INS_BASE);
144 
145 	/*
146 	 * Set directory to search for general l10n SCCS messages.
147 	 */
148 #ifdef	PROTOTYPES
149 	(void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
150 	   NOGETTEXT(INS_BASE "/" SCCS_BIN_PRE "lib/locale/"));
151 #else
152 	(void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
153 	   NOGETTEXT("/usr/ccs/lib/locale/"));
154 #endif
155 
156 	(void) textdomain(NOGETTEXT("SUNW_SPRO_SCCS"));
157 
158 	tzset();	/* Set up timezome related vars */
159 
160 #ifdef	SCHILY_BUILD
161 	save_args(argc, argv);
162 #endif
163 	/*
164 	Set flags for 'fatal' to issue message, call clean-up
165 	routine and terminate processing.
166 	*/
167 	Fflags = FTLMSG | FTLCLN | FTLEXIT;
168 #ifdef	SCCS_FATALHELP
169 	Fflags |= FTLFUNC;
170 	Ffunc = sccsfatalhelp;
171 #endif
172 
173 	ret_code = 0;
174 	if (argc == 2 && argv[1][0] == '-' && !(argv[1][1])) {
175 		inpstd = TRUE;
176 		iop = stdin;		/* read from standard input */
177 		while (fgets(line, BUFSIZ, iop) != NULL) {
178 		    if (line[0] != '\n') {
179 			repl(line, '\n', '\0');
180 			strlcpy(save_line, line, sizeof (save_line));
181 			argv = Argv;
182 			*argv++ = "val";
183 			lp = save_line;
184 			argc = 1;
185 			while (*lp != '\0') {
186 			    while ((*lp == ' ') || (*lp == '\t'))
187 				*lp++ = '\0';
188 			    *argv++ = lp++;
189 			    argc++;
190 			    while ((*lp != ' ') && (*lp != '\t') && (*lp != '\0'))
191 				lp++;
192 			}
193 			*argv = NULL;
194 			argv = Argv;
195 			process(line, argc, argv);
196 			ret_code |= inline_err;
197 		    }
198 		}
199 	} else {
200 		inpstd = FALSE;
201 		line[0] = '\0';
202 		process(line, argc, argv);
203 		ret_code = inline_err;
204 	}
205 
206 	return (ret_code);
207 }
208 
209 
210 /* This function processes the line sent by the main routine.  It
211  * determines which keyletter values are present on the command
212  * line and assigns the values to the correct storage place.  It
213  * then calls validate for each file name on the command line
214  * It will return to main if the input line contains an error,
215  * otherwise it returns any error code found by validate.
216 */
217 
218 static void
process(p_line,argc,argv)219 process(p_line, argc, argv)
220 char	*p_line;
221 int	argc;
222 char	*argv[];
223 {
224 	register int	j;
225 	register int	line_sw;
226 	register char   *p;
227 	register int	i;
228 
229 	int	num_files;
230 
231 	char	**filelist = NULL;
232 	char	*savelinep;
233 	int 	c;
234 
235 	int current_optind;
236 	int no_arg;
237 
238 	silent = FALSE;
239 	path[0] = sid[0] = type[0] = name[0] = 0;
240 	num_files = inline_err = 0;
241 
242 	/*
243 	make copy of 'line' for use later
244 	*/
245 	savelinep = p_line;
246 	/*
247 	clear out had flags for each 'line' processed
248 	*/
249 	for (j = 0; j < HAD_SIZE; j++)
250 		had[j] = 0;
251 	/*
252 	execute loop until all characters in 'line' are checked.
253 	*/
254 
255 	current_optind = 1;
256 	optind = 1;
257 	opterr = 0;
258 	no_arg = 0;
259 	j = 1;
260 	/*CONSTCOND*/
261 	while (1) {
262 			if (current_optind < optind) {
263 				current_optind = optind;
264 				argv[j] = 0;
265 				if (optind > j+1) {
266 					if ((argv[j+1][0] != '-') &&
267 					    (no_arg == 0)) {
268 						argv[j+1] = NULL;
269 					} else {
270 						optind = j+1;
271 						current_optind = optind;
272 			 		}
273 				}
274 			}
275 			no_arg = 0;
276 			j = current_optind;
277 			c = getopt(argc, argv, "()-r:sm:y:hvTN:X:V(version)");
278 
279 				/* this takes care of options given after
280 				** file names.
281 				*/
282 			if (c == EOF) {
283 			    if (optind < argc) {
284 				/* if it's due to -- then break; */
285 				if (argv[j][0] == '-' &&
286 				    argv[j][1] == '-') {
287 					argv[j] = 0;
288 					break;
289 				}
290 				optind++;
291 				current_optind = optind;
292 				continue;
293 			    } else {
294 				break;
295 			   }
296 			}
297 			p = optarg;
298 			switch (c) {
299 				case 'h':
300 					break;
301 				case 's':
302 					silent = TRUE;
303 					break;
304 				case 'r':
305 					strlcpy(sid, p, sizeof (sid));
306 					break;
307 				case 'y':
308 					strlcpy(type, p, sizeof (type));
309 					break;
310 				case 'm':
311 					strlcpy(name, p, sizeof (name));
312 					break;
313 				case 'v':
314 					break;
315 
316 				case 'T':
317 					debug = TRUE;
318 					silent = FALSE;
319 					break;
320 
321 				case 'N':	/* Bulk names */
322 					initN(&N);
323 					if (optarg == argv[j+1]) {
324 					   no_arg = 1;
325 					   break;
326 					}
327 					N.n_parm = p;
328 					break;
329 
330 				case 'X':	/* -Xtended options */
331 					X.x_parm = optarg;
332 					X.x_flags = XO_NULLPATH;
333 					if (!parseX(&X))
334 						goto err;
335 					had[NLOWER+c-'A'] = 0;	/* Allow mult -X */
336 					break;
337 
338 				case 'V':		/* version */
339 					printf(gettext(
340 					    "val %s-SCCS version %s %s (%s-%s-%s)\n"),
341 						PROVIDER,
342 						VERSION,
343 						VDATE,
344 						HOST_CPU, HOST_VENDOR, HOST_OS);
345 					exit(EX_OK);
346 
347 				default:
348 				err:
349 					Fflags &= ~FTLEXIT;
350 					fatal(gettext("Usage: val [ -h ] [ -s ] [ -m name ] [ -r SID ] [ -T ] [ -v ]\n\t[ -y type ] [ -N[bulk-spec]][ -Xxopts ] s.filename..."));
351 					if (debug) {
352 						printf(gettext("Uknown option '%c'.\n"),
353 							optopt?optopt:c);
354 					}
355 					inline_err |= UNKDUP_ERR;
356 					if (inpstd)
357 					   report(inline_err, savelinep, "");
358 					else
359 					   report(inline_err, "", "");
360 					return;
361 			}
362 			/*
363 			 * Make sure that we only collect option letters from
364 			 * the range 'a'..'z' and 'A'..'Z'.
365 			 *
366 			 * use 'had' array and determine if the keyletter
367 			 * was given twice.
368 			 */
369 			if (ALPHA(c) &&
370 			    (had[LOWER(c)? c-'a' : NLOWER+c-'A']++)) {
371 				if (c != 'X') {
372 					if (debug) {
373 						printf(gettext(
374 						    "Duplicate option '%c'.\n"),
375 						    c);
376 					}
377 					inline_err |= UNKDUP_ERR;
378 				}
379 			}
380 	}
381 
382 	for (j = 1; j < argc; j++) {
383 		if (argv[j]) {
384 			if (filelist == NULL)
385 				filelist = &argv[j];
386 			num_files++;
387 		}
388 	}
389 	/*
390 	check if any files were named as arguments
391 	*/
392 	if (num_files == 0) {
393 		if (debug)
394 			printf(gettext("Missing file argument.\n"));
395 		inline_err |= FILARG_ERR;
396 	}
397 	/*
398 	check for error in command line.
399 	*/
400 	if (inline_err) {
401 	    if (!silent) {
402 		if (inpstd)
403 			report(inline_err, savelinep, "");
404 		else
405 			report(inline_err, "", "");
406 	    }
407 	    return;		/* return to 'main' routine */
408 	}
409 	line_sw = 1;		/* print command line flag */
410 
411 	xsethome(NULL);
412 	if (HADUCN) {					/* Parse -N args  */
413 		parseN(&N);
414 
415 		if (N.n_sdot && (sethomestat & SETHOME_OFFTREE))
416 			fatal(gettext("-Ns. not supported in off-tree project mode"));
417 	}
418 
419 	/*
420 	loop through 'validate' for each file on command line.
421 	*/
422 	for (i = 0, j = 0; j < num_files; j++) {
423 		while (filelist[i+j] == NULL) {
424 			i++;
425 			if ((i+j+1) >= argc)
426 				break;
427 		}
428 		if (filelist[i+j] == NULL)
429 			break;
430 
431 		/*
432 		read a file from 'filelist' and place into 'path'.
433 		*/
434 		if (size(filelist[i+j]) > FILESIZE) {
435 			extern char *Ffile;
436 			Ffile = filelist[i+j];
437 			fatal(gettext("too long (co7)"));
438 		}
439 		strlcpy(path, filelist[i+j], sizeof (path));
440 		if (!inpstd) {
441 			do_file(path, do_validate, 1, N.n_sdot, &X);
442 			continue;
443 		}
444 		validate(path, sid, type, name);
445 		inline_err |= infile_err;
446 		/*
447 		check for error from 'validate' and call 'report'
448 		depending on 'silent' flag.
449 		*/
450 		if (infile_err && !silent) {
451 			if (line_sw && inpstd) {
452 				report(infile_err, savelinep, path);
453 				line_sw = 0;
454 			} else
455 				report(infile_err, "", path);
456 		}
457 	}
458 	/* return to 'main' routine */
459 }
460 
461 static void
do_validate(c_path)462 do_validate(c_path)
463 	char	*c_path;
464 {
465 	if (HADUCN) {
466 #ifdef	__needed__
467 		char	*ofile = c_path;
468 #endif
469 
470 		c_path = bulkprepare(&N, c_path);
471 		if (c_path == NULL) {
472 #ifdef	__needed__
473 			if (N.n_ifile)
474 				ofile = N.n_ifile;
475 #endif
476 			/*
477 			 * The error is typically
478 			 * "directory specified as s-file (cm14)"
479 			 */
480 			fatal(gettext(bulkerror(&N)));
481 		}
482 	}
483 
484 	validate(c_path, sid, type, name);
485 	inline_err |= infile_err;
486 
487 	/*
488 	 * check for error from 'validate' and call 'report'
489 	 * depending on 'silent' flag.
490 	 */
491 	if (infile_err && !silent) {
492 		report(infile_err, "", c_path);
493 	}
494 }
495 
496 /* This function actually does the validation on the named file.
497  * It determines whether the file is an SCCS-file or if the file
498  * exists.  It also determines if the values given for type, SID,
499  * and name match those in the named file.  An error code is returned
500  * if any mismatch occurs.  See VAL(I) for more information.
501 */
502 
503 static void
validate(c_path,c_sid,c_type,c_name)504 validate(c_path, c_sid, c_type, c_name)
505 char	*c_path;
506 char	*c_sid;
507 char	*c_type;
508 char	*c_name;
509 {
510 	register char	*l;
511 	int	goods, goodt, goodn, hadmflag;
512 
513 	infile_err = goods = goodt = goodn = hadmflag = 0;
514 	dt.d_dtime.dt_sec = odt.d_dtime.dt_sec = 0;
515 	dt.d_dtime.dt_nsec = odt.d_dtime.dt_nsec = 0;
516 	dt.d_dtime.dt_zone = odt.d_dtime.dt_zone = DT_NO_ZONE;
517 
518 	s_init(&gpkt, c_path);
519 
520 	if (!sccsfile(c_path) || (gpkt.p_iop = fopen(c_path, "rb")) == NULL) {
521 		if (debug) {
522 			if (!sccsfile(c_path)) {
523 				printf(gettext("%s%s: not a sccs file\n"),
524 					"    ", c_path);
525 			} else {
526 				printf(gettext("%s%s cannot open\n"),
527 					"    ", c_path);
528 			}
529 		}
530 		infile_err |= FILENAM_ERR;
531 	} else {
532 		l = get_line(&gpkt);		/* read first line in file */
533 		/*
534 		check that it is header line.
535 		*/
536 		if (l == NULL || (l = checkmagic(&gpkt, l)) == NULL) {
537 			if (debug)
538 				printf(
539 				gettext("%s%s: corrupted first line in file\n"),
540 					"    ", c_path);
541 			infile_err |= CORRUPT_ERR;
542 		}
543 		else {
544 			if (HADV) {
545 				if (gpkt.p_flags & PF_V6)
546 					printf("SCCS V6 %s\n", c_path);
547 				else
548 					printf("SCCS V4 %s\n", c_path);
549 				sclose(&gpkt);
550 				return;
551 			}
552 
553 			/*
554 			 * Read delta table for get_hashtest()
555 			 */
556 			if (gpkt.p_flags & PF_V6 && HADH)
557 				get_setup(c_path);
558 
559 			/*
560 			 * get old file checksum count
561 			 */
562 			satoi(l, &gpkt.p_ihash);
563 			gpkt.p_chash = 0;
564 			gpkt.p_uchash = 0;
565 			if (HADR) {
566 				struct sid	ssid;
567 				char		*p;
568 
569 				/*
570 				check for invalid or ambiguous SID.
571 				*/
572 				p = sid_ab(c_sid, &ssid);
573 				if (*p ||
574 				    (ssid.s_rel == 0 && ssid.s_lev) ||
575 				    (ssid.s_lev == 0 && ssid.s_br) ||
576 				    (ssid.s_br == 0 && ssid.s_seq))
577 					infile_err |= INVALSID_ERR;
578 			}
579 			/*
580 			read delta table checking for errors and/or
581 			SID.
582 			*/
583 			if (do_delt(&gpkt, goods, c_sid)) {
584 				sclose(&gpkt);
585 				get_close();		/* for SID checksums */
586 				if (debug)
587 					printf(gettext(
588 					"%s%s: invalid delta table at line %d\n"),
589 						"    ", c_path, gpkt.p_slnno);
590 				infile_err |= CORRUPT_ERR;
591 				return;
592 			}
593 
594 			read_to(EUSERNAM, &gpkt);
595 
596 			if (HADY || HADM) {
597 				/*
598 				read flag section of delta table.
599 				*/
600 				while (((l = get_line(&gpkt)) != NULL) &&
601 					*l++ == CTLCHAR &&
602 					*l++ == FLAG) {
603 					NONBLANK(l);
604 					repl(l, '\n', '\0');
605 					if (*l == TYPEFLAG) {
606 						l += 2;
607 						if (equal(c_type, l))
608 							goodt++;
609 					}
610 					else if (*l == MODFLAG) {
611 						hadmflag++;
612 						l += 2;
613 						if (equal(c_name, l))
614 							goodn++;
615 					}
616 				}
617 
618 				/*
619 				 * If there are SCCS v6 flags or SCCS v6 global
620 				 * meta data, we need to skip this data here.
621 				 */
622 				if (gpkt.p_line != NULL &&
623 				    gpkt.p_line[0] == CTLCHAR &&
624 				    gpkt.p_line[1] != BUSERTXT)
625 					read_to(BUSERTXT, &gpkt);
626 
627 				/*
628 				 * If we did not find the mandatory begin of
629 				 * the user comment area, the file is corrupt.
630 				 */
631 				if (gpkt.p_line != NULL &&
632 				    gpkt.p_line[0] == CTLCHAR &&
633 				    gpkt.p_line[1] != BUSERTXT) {
634 					sclose(&gpkt);
635 					get_close();	/* for SID checksums */
636 					if (debug)
637 						printf(gettext(
638 						"%s%s: flag section error at line %d\n"),
639 						"    ", c_path, gpkt.p_slnno);
640 					infile_err |= CORRUPT_ERR;
641 					return;
642 				}
643 				/*
644 				check if 'y' flag matched '-y' arg value.
645 				*/
646 				if (!goodt && HADY) {
647 					if (debug)
648 						printf(gettext(
649 						"%s%s: mismatch between %cY%c and '%s'\n"),
650 							"    ", c_path,
651 							'%', '%', c_type);
652 					infile_err |= TYPE_ERR;
653 				}
654 				/*
655 				check if 'm' flag matched '-m' arg value.
656 				*/
657 				if (HADM && !hadmflag) {
658 					if (!equal(auxf(sname(c_path), 'g'), c_name)) {
659 						if (debug)
660 							printf(gettext(
661 							"%s%s: no 'm' flag\n"),
662 							"    ", c_path);
663 						infile_err |= NAME_ERR;
664 					}
665 				}
666 				else if (HADM && hadmflag && !goodn) {
667 						if (debug)
668 							printf(gettext(
669 							"%s%s: mismatch between %cM%c and '%s'\n"),
670 							"    ", c_path,
671 							'%', '%', c_name);
672 						infile_err |= NAME_ERR;
673 				}
674 			}
675 			else read_to(BUSERTXT, &gpkt);
676 			read_to(EUSERTXT, &gpkt);
677 			gpkt.p_chkeof = 1;
678 			/*
679 			read remainder of file so 'read_mod'
680 			can check for corruptness.
681 			*/
682 			while (read_mod(&gpkt))
683 				;
684 		}
685 	sclose(&gpkt);		/* close file pointer */
686 	sfree(&gpkt);		/* free line pointer */
687 	get_close();		/* for SID checksums */
688 	}
689 	/* return to 'process' function */
690 }
691 
692 
693 /* This function reads the 'delta' line from the named file and stores
694  * the information into the structure 'del'.
695 */
696 
697 static void
getdel(delp,lp,pkt)698 getdel(delp, lp, pkt)
699 register struct delent *delp;
700 register char *lp;
701 struct packet *pkt;
702 {
703 	char	*p;
704 	int	dflags = 0;
705 	int	missfld = 0;
706 
707 	if (debug) {
708 		char	str[SID_STRSIZE];
709 		char	ostr[SID_STRSIZE];
710 
711 		del_ab(&lp[-2], &dt, pkt);	/* We are called with &lp[2] */
712 
713 		if ((dt.d_dtime.dt_sec != 0 && odt.d_dtime.dt_sec != 0 &&
714 		    (dt.d_dtime.dt_sec > odt.d_dtime.dt_sec)) ||
715 		    ((dt.d_dtime.dt_sec == odt.d_dtime.dt_sec) &&
716 		    (dt.d_dtime.dt_nsec > odt.d_dtime.dt_nsec))) {
717 			sid_ba(&dt.d_sid, str);
718 			sid_ba(&odt.d_sid, ostr);
719 			printf(gettext(
720 "%s%s: warning: date for sid %s is later than the date for sid %s in line %d\n"),
721 				"    ", pkt->p_file,
722 				str, ostr, pkt->p_slnno);
723 		}
724 		odt = dt;			/* Remember last date */
725 	}
726 
727 	NONBLANK(lp);
728 	delp->type = *lp++;			/* Type	'D'		*/
729 	NONBLANK(lp);
730 	delp->osid = lp;			/* SID	"1.2"		*/
731 	BLANK(lp);
732 	if (*lp)
733 		*lp++ = '\0';
734 	else
735 		missfld++;
736 	NONBLANK(lp);				/* Find date time string */
737 	delp->datetime = lp;			/* Date	"06/12/20 23:46:27" */
738 	BLANK(lp);				/* Skip past date	*/
739 	NONBLANK(lp);				/* Find time		*/
740 	BLANK(lp);				/* Skip past time	*/
741 	if (*lp)
742 		*lp++ = '\0';
743 	else
744 		missfld++;
745 	p = lp;
746 	NONBLANK(lp);				/* Find programmer	*/
747 	/*
748 	 * Old sccs implementations did frequently write something like
749 	 * "^Ad D 4.42 82/10/19 10:30:32  64 63"
750 	 * So we check for extra blanks and later verify whether there
751 	 * are too few fields.
752 	 */
753 	if (lp != p && *p == ' ')
754 		dflags |= 1;			/* Mark as double space	*/
755 	delp->pgmr = lp;			/* Programmer	"bill"	*/
756 	BLANK(lp);				/* Skip past programmer	*/
757 	if (*lp)
758 		*lp++ = '\0';
759 	else
760 		missfld++;
761 	NONBLANK(lp);				/* Find serial		*/
762 	delp->serial = lp;			/* Serial	"42"	*/
763 	BLANK(lp);				/* Skip past serial	*/
764 	if (*lp)
765 		*lp++ = '\0';
766 	else
767 		missfld++;
768 	NONBLANK(lp);				/* Find pred		*/
769 	delp->pred = lp;			/* Pred serial	"41"	*/
770 	if (missfld == 0 && (*lp == '\0' || *lp == '\n'))
771 		missfld++;
772 	repl(lp, '\n', '\0');
773 	if (dflags && (*lp == '\0' || *lp == '\n')) {
774 		if (debug)
775 			printf(gettext("%s%s: username missing in line %d\n"),
776 			"    ", pkt->p_file, pkt->p_slnno);
777 		infile_err |= CORRUPT_ERR;
778 	}
779 	if (missfld > 1 || (missfld && dflags == 0)) {
780 		if (debug)
781 			printf(gettext("%s%s: missing field in delta in line %d\n"),
782 			"    ", pkt->p_file, pkt->p_slnno);
783 		infile_err |= CORRUPT_ERR;
784 	}
785 	if ((pkt->p_flags & PF_V6) == 0) {
786 		int	dterr = 0;
787 
788 		p = strchr(delp->datetime, '/');
789 		if ((p - delp->datetime) > 2) {
790 			if (dt.d_dtime.dt_sec < Y1969 ||
791 			    dt.d_dtime.dt_sec >= Y2038) {
792 				/*
793 				 * In this case, 4-digit year numbers are OK.
794 				 */
795 				if ((p - delp->datetime) != 4)
796 					dterr++;
797 			} else {
798 				dterr++;
799 			}
800 		}
801 		/*
802 		 * Nanoseconds not allowed in SCCSv4 mode.
803 		 */
804 		if (strchr(delp->datetime, '.'))
805 			dterr++;
806 		/*
807 		 * With 2-digit year, the length is 17.
808 		 */
809 		if (strlen(delp->datetime) > 19)
810 			dterr++;
811 		if (dterr) {
812 			if (debug)
813 				printf(gettext("%s%s: invalid v4 datetime field '%s' in line %d\n"),
814 				"    ", pkt->p_file, delp->datetime, pkt->p_slnno);
815 			infile_err |= CORRUPT_ERR;
816 		}
817 	}
818 }
819 
820 
821 /* This function does a read through the named file until it finds
822  * the character sent over as an argument.
823 */
824 
825 static void
read_to(ch,pkt)826 read_to(ch, pkt)
827 register char ch;
828 register struct packet *pkt;
829 {
830 	register char *n;
831 	while (((n = get_line(pkt)) != NULL) &&
832 			!(*n++ == CTLCHAR && *n == ch))
833 		;
834 }
835 
836 
837 /* This function will report the error that occured on the command
838  * line.  It will print one diagnostic message for each error that
839  * was found in the named file.
840 */
841 
842 static void
report(code,inp_line,file)843 report(code, inp_line, file)
844 register int	code;
845 register char	*inp_line;
846 register char	*file;
847 {
848 	char	percent;
849 	percent = '%';		/* '%' for -m and/or -y messages */
850 /* xpg4 behaviour
851 	if (*inp_line)
852 		printf("%s:\n", inp_line);
853 	if (code & NAME_ERR)
854 	   printf(gettext(" %s: %cM%c -m mismatch\n"), file, percent, percent);
855 	if (code & TYPE_ERR)
856 	   printf(gettext(" %s: %cY%c -y mismatch\n"), file, percent, percent);
857 	if (code & NONEXSID_ERR)
858 	   printf(gettext(" %s: SID nonexistent\n"), file);
859 	if (code & INVALSID_ERR)
860 	   printf(gettext(" %s: SID invalid or ambiguous\n"), file);
861 	if (code & FILENAM_ERR)
862 	   printf(gettext(" %s: can't open file or file not SCCS\n"), file);
863 	if (code & CORRUPT_ERR)
864 	   printf(gettext(" %s: corrupted SCCS file\n"), file);
865 	if (code & UNKDUP_ERR)
866 	   printf(gettext(" %s: Unknown or duplicate keyletter argument\n"), file);
867 	if (code & FILARG_ERR)
868 		printf(gettext(" %s: missing file argument\n"), file);
869 */
870 	if (*inp_line)
871 		printf("%s\n\n", inp_line);
872 	if (code & NAME_ERR)
873 	   printf(gettext("    %s: %cM%c -m mismatch\n"), file, percent, percent);
874 	if (code & TYPE_ERR)
875 	   printf(gettext("    %s: %cY%c -y mismatch\n"), file, percent, percent);
876 	if (code & NONEXSID_ERR)
877 	   printf(gettext("    %s: SID nonexistent\n"), file);
878 	if (code & INVALSID_ERR)
879 	   printf(gettext("    %s: SID invalid or ambiguous\n"), file);
880 	if (code & FILENAM_ERR)
881 	   printf(gettext("    %s: can't open file or file not SCCS\n"), file);
882 	if (code & CORRUPT_ERR)
883 	   printf(gettext("    %s: corrupted SCCS file\n"), file);
884 	if (code & UNKDUP_ERR)
885 	   printf(gettext("    %s: Unknown or duplicate keyletter argument\n"), file);
886 	if (code & FILARG_ERR)
887 		printf(gettext("    %s: missing file argument\n"), file);
888 }
889 
890 
891 /*
892 	Routine to read a line into the packet.  The main reason for
893 	it is to make sure that pkt->p_wrttn gets turned off,
894 	and to increment pkt->p_slnno.
895 */
896 
897 static char	*
get_line(pkt)898 get_line(pkt)
899 register struct packet *pkt;
900 {
901 #ifdef	NO_GETDELIM
902 	char	buf[DEF_LINE_SIZE+1];
903 	register size_t nread = 0;
904 #endif
905 	int	eof = 0;
906 	register size_t used = 0;
907 
908 #ifndef	NO_GETDELIM
909 	/*
910 	 * getdelim() allows to read lines that have embedded nul bytes
911 	 * and we don't need to call strlen().
912 	 */
913 	errno = 0;
914 	used = getdelim(&pkt->p_line, &pkt->p_line_size, '\n', pkt->p_iop);
915 	if (used == -1) {
916 		if (errno == ENOMEM)
917 			fatal(gettext("OUT OF SPACE (ut9)"));
918 		if (ferror(pkt->p_iop)) {
919 			xmsg(pkt->p_file, NOGETTEXT("getline"));
920 		} else if (feof(pkt->p_iop)) {
921 			used = 0;
922 			eof = 1;
923 		}
924 	}
925 #else
926 	/* read until EOF or newline encountered */
927 	do {
928 		(void)memset(buf, '\377', sizeof (buf));
929 		if (!(eof = (fgets(buf, sizeof (buf), pkt->p_iop) == NULL))) {
930 			for (nread = sizeof (buf); --nread > 0; )
931 				if (buf[nread] == '\0')
932 					break;
933 
934 			if ((used + nread) >=  pkt->p_line_size) {
935 				pkt->p_line_size += sizeof (buf);
936 				pkt->p_line = (char *) realloc(pkt->p_line, pkt->p_line_size);
937 				if (pkt->p_line == NULL) {
938 					efatal(gettext("OUT OF SPACE (ut9)"));
939 				}
940 			}
941 
942 			memcpy(pkt->p_line + used, buf, nread);
943 			used += nread;
944 		}
945 	} while (!eof && (pkt->p_line[used-1] != '\n'));
946 #endif
947 	pkt->p_linebase = pkt->p_line;
948 	pkt->p_line_length = used;
949 
950 	/* check end of file condition */
951 	if (eof && (used == 0)) {
952 		if (!pkt->p_chkeof) {
953 			if (debug)
954 				printf(gettext(
955 					"%s%s: incomplete delta table\n"),
956 							"    ", pkt->p_file);
957 			infile_err |= CORRUPT_ERR;
958 		}
959 		if (pkt->do_chksum && (pkt->p_chash ^ pkt->p_ihash)&0xFFFF) {
960 		   if (pkt->do_chksum && (pkt->p_uchash ^ pkt->p_ihash)&0xFFFF) {
961 			if (debug)
962 				printf(gettext(
963 				"%s%s: invalid checksum %d, expected %d\n"),
964 						"    ", pkt->p_file,
965 						pkt->p_ihash,
966 						pkt->p_chash & 0xFFFF);
967 			infile_err |= CORRUPT_ERR;
968 		   }
969 		}
970 		return (NULL);
971 	}
972 
973 	/* increment line number */
974 	if (pkt->p_line[used-1] == '\n') {
975 		pkt->p_slnno++;
976 	}
977 
978 	/* update check sum */
979 	pkt->p_chash += ssum((char *)pkt->p_line, pkt->p_line_length);
980 	pkt->p_uchash += usum((char *)pkt->p_line, pkt->p_line_length);
981 
982 	return (pkt->p_line);
983 }
984 
985 
986 /*
987 	Does initialization for sccs files and packet.
988 */
989 
990 static void
s_init(pkt,file)991 s_init(pkt, file)
992 register struct packet *pkt;
993 register char *file;
994 {
995 
996 	zero((char *) pkt, sizeof (*pkt));
997 	copy(file, pkt->p_file);
998 	pkt->p_wrttn = 1;
999 	pkt->do_chksum = 1;	/* turn on checksum check for getline */
1000 }
1001 
1002 static int
read_mod(pkt)1003 read_mod(pkt)
1004 register struct packet *pkt;
1005 {
1006 	register char *p;
1007 	int ser;
1008 	int iord;
1009 	register struct apply *ap;
1010 
1011 	while (get_line(pkt) != NULL) {
1012 		p = pkt->p_line;
1013 		if (*p++ != CTLCHAR)
1014 			continue;
1015 		else {
1016 			if (!((iord = *p++) == INS || iord == DEL || iord == END)) {
1017 				if (iord == CTLCHAR && pkt->p_flags & PF_V6)
1018 					continue;
1019 				if (iord == NONL && pkt->p_flags & PF_V6)
1020 					continue;
1021 				if (debug)
1022 					printf(gettext(
1023 					"%s%s: invalid control in weave data near line %d\n"),
1024 						"    ", pkt->p_file,
1025 						pkt->p_slnno);
1026 				infile_err |= CORRUPT_ERR;
1027 				return (0);
1028 			}
1029 			NONBLANK(p);
1030 			satoi(p, &ser);
1031 			if (iord == END)
1032 				rem_q(pkt, ser);
1033 			else if (pkt->p_apply != 0) {
1034 				ap = &pkt->p_apply[ser];
1035 				if (ap->a_code == APPLY)
1036 					add_q(pkt, ser, iord == INS ? YES : NO,
1037 					    iord, ap->a_reason & USER);
1038 				else
1039 					add_q(pkt, ser, iord == INS ? NO : 0,
1040 					    iord, ap->a_reason & USER);
1041 			} else
1042 				add_q(pkt, ser, iord == INS ? NO : 0, iord, 0);
1043 		}
1044 	}
1045 	if (pkt->p_q) {
1046 		if (debug)
1047 			printf(gettext(
1048 			"%s%s: incomplete weave data near line %d\n"),
1049 				"    ", pkt->p_file,
1050 				pkt->p_slnno);
1051 		infile_err |= CORRUPT_ERR;
1052 	}
1053 	return (0);
1054 }
1055 
1056 static void
add_q(pkt,ser,keep,iord,user)1057 add_q(pkt, ser, keep, iord, user)
1058 struct packet *pkt;
1059 int ser;
1060 int keep;
1061 int iord;
1062 int user;
1063 {
1064 	register struct queue *cur, *prev, *q;
1065 
1066 	for (cur = (struct queue *) (&pkt->p_q); (cur = (prev = cur)->q_next) != NULL; )
1067 		if (cur->q_sernum <= ser)
1068 			break;
1069 	if (cur && cur != (struct queue *)&pkt->p_q && cur->q_sernum == ser) {
1070 		if (debug)
1071 			printf(gettext(
1072 			"%s%s: duplicate delta block in weave data with serial %d near line %d\n"),
1073 				"    ", pkt->p_file,
1074 				cur->q_sernum, pkt->p_slnno);
1075 		infile_err |= CORRUPT_ERR;
1076 	}
1077 	prev->q_next = q = (struct queue *) fmalloc(sizeof (*q));
1078 	q->q_next = cur;
1079 	q->q_sernum = ser;
1080 	q->q_keep = keep;
1081 	q->q_iord = iord;
1082 	q->q_user = user;
1083 	if (pkt->p_ixuser && (q->q_ixmsg = chk_ix(q, pkt->p_q)))
1084 		++(pkt->p_ixmsg);
1085 	else
1086 		q->q_ixmsg = 0;
1087 
1088 	set_keep(pkt);
1089 }
1090 
1091 static void
rem_q(pkt,ser)1092 rem_q(pkt, ser)
1093 register struct packet *pkt;
1094 int ser;
1095 {
1096 	register struct queue *cur, *prev;
1097 
1098 	for (cur = (struct queue *) (&pkt->p_q); (cur = (prev = cur)->q_next) != NULL; )
1099 		if (cur->q_sernum == ser)
1100 			break;
1101 	if (cur && cur != (struct queue *)&pkt->p_q) {
1102 		if (cur->q_ixmsg)
1103 			--(pkt->p_ixmsg);
1104 		prev->q_next = cur->q_next;
1105 		ffree((char *) cur);
1106 		set_keep(pkt);
1107 	}
1108 	else {
1109 		if (debug)
1110 			printf(gettext(
1111 			"%s%s: incomplete delta block in weave data near line %d\n"),
1112 				"    ", pkt->p_file,
1113 				pkt->p_slnno);
1114 		infile_err |= CORRUPT_ERR;
1115 	}
1116 }
1117 
1118 static void
set_keep(pkt)1119 set_keep(pkt)
1120 register struct packet *pkt;
1121 {
1122 	register struct queue *q;
1123 	register struct sid *sp;
1124 
1125 	for (q = pkt->p_q; q; q = q->q_next)
1126 		if (q->q_keep != '\0') {
1127 			if ((pkt->p_keep = q->q_keep) == YES) {
1128 				sp = &pkt->p_idel[q->q_sernum].i_sid;
1129 				pkt->p_inssid.s_rel = sp->s_rel;
1130 				pkt->p_inssid.s_lev = sp->s_lev;
1131 				pkt->p_inssid.s_br = sp->s_br;
1132 				pkt->p_inssid.s_seq = sp->s_seq;
1133 			}
1134 			return;
1135 		}
1136 	pkt->p_keep = NO;
1137 }
1138 
1139 
1140 #define	apply(qp)	((qp->q_iord == INS && qp->q_keep == YES) || \
1141 			 (qp->q_iord == DEL && qp->q_keep == NO))
1142 static int
chk_ix(new,head)1143 chk_ix(new, head)
1144 register struct queue *new;
1145 struct queue *head;
1146 {
1147 	register int retval;
1148 	register struct queue *cur;
1149 	int firstins, lastdel;
1150 
1151 	if (!apply(new))
1152 		return (0);
1153 	for (cur = head; cur; cur = cur->q_next)
1154 		if (cur->q_user)
1155 			break;
1156 	if (!cur)
1157 		return (0);
1158 	retval = 0;
1159 	firstins = 0;
1160 	lastdel = 0;
1161 	for (cur = head; cur; cur = cur->q_next) {
1162 		if (apply(cur)) {
1163 			if (cur->q_iord == DEL)
1164 				lastdel = cur->q_sernum;
1165 			else if (firstins == 0)
1166 				firstins = cur->q_sernum;
1167 		}
1168 		else if (cur->q_iord == INS)
1169 			retval++;
1170 	}
1171 	if (retval == 0) {
1172 		if (lastdel && (new->q_sernum > lastdel))
1173 			retval++;
1174 		if (firstins && (new->q_sernum < firstins))
1175 			retval++;
1176 	}
1177 	return (retval);
1178 }
1179 
1180 
1181 /*
1182  * This function reads the delta table entries and checks for the format
1183  * as specifed in sccsfile(V).  If the format is incorrect, a corrupt
1184  * error will be issued by 'val'.  This function also checks
1185  * if the sid requested is in the file (depending if '-r' was specified).
1186  */
1187 
1188 static int
do_delt(pkt,goods,d_sid)1189 do_delt(pkt, goods, d_sid)
1190 register struct packet *pkt;
1191 register int goods;
1192 register char *d_sid;
1193 {
1194 	char *l;
1195 
1196 	while (getstats(pkt)) {
1197 		if ((((l = get_line(pkt)) != NULL) && *l++ != CTLCHAR) ||
1198 		    *l++ != BDELTAB)
1199 			return (1);
1200 		getdel(&del, l, pkt);
1201 		if (HADR && !(infile_err & INVALSID_ERR)) {
1202 			if (equal(d_sid, del.osid) &&
1203 			    (del.type == 'D' || del.type == 'U'))
1204 				goods++;
1205 		}
1206 		if (gpkt.p_flags & PF_V6 &&
1207 		    HADH && (del.type == 'D' || del.type == 'U')) {
1208 			int	ser;
1209 
1210 			satoi(del.serial, &ser);
1211 			get_hashtest(ser);
1212 		}
1213 		while ((l = get_line(pkt)) != NULL)
1214 			if (pkt->p_line[0] != CTLCHAR)
1215 				break;
1216 			else {
1217 				switch (pkt->p_line[1]) {
1218 				case EDELTAB:
1219 					break;
1220 				case COMMENTS:
1221 				case MRNUM:
1222 				case INCLUDE:
1223 				case EXCLUDE:
1224 				case IGNORE:
1225 					continue;
1226 				case SIDEXTENS:
1227 					if (pkt->p_flags & PF_V6)
1228 						continue;
1229 				default:
1230 					return (1);
1231 				}
1232 				break;
1233 			}
1234 		if (l == NULL || pkt->p_line[0] != CTLCHAR)
1235 			return (1);
1236 	}
1237 	if (pkt->p_line[1] != BUSERNAM)
1238 		return (1);
1239 	if (HADR && !goods && !(infile_err & INVALSID_ERR)) {
1240 		infile_err |= NONEXSID_ERR;
1241 	}
1242 	return (0);
1243 }
1244 
1245 
1246 /* This function reads the stats line from the sccsfile */
1247 
1248 static int
getstats(pkt)1249 getstats(pkt)
1250 register struct packet *pkt;
1251 {
1252 	register char *p = get_line(pkt);
1253 	register char *op;
1254 	register int i = 0;
1255 
1256 	if (p == NULL || *p++ != CTLCHAR || *p != STATS)
1257 		return (0);
1258 
1259 	/*
1260 	 * We do not check the format of the statistics line in non-debug mode
1261 	 * as the related values are otherwise ignored by SCCS.
1262 	 */
1263 	if (!debug)
1264 		return (1);
1265 
1266 	p++;
1267 	NONBLANK(p);
1268 	if (*p < '0' || *p > '9') {
1269 		printf(gettext(
1270 		"%s%s: illegal character in statistics in line %d\n"),
1271 		"    ", pkt->p_file, pkt->p_slnno);
1272 	}
1273 	while (*p) {
1274 		if (*p == '\n')
1275 			break;
1276 		op = p;
1277 		p = getastat(p, NULL);
1278 		if ((i == 2 && *p != '\n') || (i < 2 && *p != '/')) {
1279 			printf(gettext(
1280 			"%s%s: illegal character in statistics in line %d\n"),
1281 				"    ", pkt->p_file, pkt->p_slnno);
1282 			infile_err |= CORRUPT_ERR;
1283 			return (1);
1284 		} else if ((p - op) != 5) {
1285 			if ((p - op) > 5)
1286 				printf(gettext(
1287 				"%s%s: number exceeds '99999' in statistics in line %d\n"),
1288 				"    ", pkt->p_file, pkt->p_slnno);
1289 			else
1290 				printf(gettext(
1291 				"%s%s: illegal number length in statistics in line %d\n"),
1292 				"    ", pkt->p_file, pkt->p_slnno);
1293 			infile_err |= CORRUPT_ERR;
1294 			return (1);
1295 		}
1296 		p++;
1297 		i++;
1298 	}
1299 	return (1);
1300 }
1301 
1302 static char *
getastat(p,ip)1303 getastat(p, ip)
1304 	char	*p;
1305 	int	*ip;
1306 {
1307 	int	i = 0;
1308 	int	c;
1309 
1310 	while ((c = *p) != '\0') {
1311 		if (c < '0' || c > '9') {
1312 			if (c != '/' && c != '\n')
1313 				i = -1;
1314 			break;
1315 		}
1316 		i *= 10;
1317 		i += c - '0';
1318 		p++;
1319 	}
1320 	if (ip)
1321 		*ip = i;
1322 	return (p);
1323 }
1324 
1325 LOCAL struct packet pk2;
1326 LOCAL off_t	get_off;
1327 LOCAL int	slnno;
1328 
1329 LOCAL void
get_setup(file)1330 get_setup(file)
1331 	char	*file;
1332 {
1333 	struct stats stats;
1334 
1335 	sinit(&pk2, file, SI_OPEN);
1336 
1337 	pk2.do_chksum = 0;
1338 	pk2.p_stdout = stderr;
1339 	pk2.p_reopen = 1;
1340 	pk2.p_cutoff = MAX_TIME;
1341 
1342 	if ((pk2.p_flags & PF_V6) == 0)
1343 		pk2.p_flags |= PF_GMT;
1344 
1345 	if (dodelt(&pk2, &stats, (struct sid *) 0, 0) == 0)
1346 		fmterr(&pk2);
1347 	flushto(&pk2, EUSERTXT, FLUSH_NOCOPY);
1348 	get_off = stell(&pk2);
1349 	slnno = pk2.p_slnno;
1350 
1351 	if (pk2.p_hash == NULL) {
1352 		if (debug)
1353 			printf(gettext(
1354 			"%s%s: SID checksums missing\n"),
1355 					"    ", pk2.p_file);
1356 		infile_err |= CORRUPT_ERR;
1357 	}
1358 }
1359 
1360 LOCAL void
get_close()1361 get_close()
1362 {
1363 	sclose(&pk2);
1364 	sfree(&pk2);
1365 	xrm(&gpkt);
1366 	ffreeall();
1367 }
1368 
1369 LOCAL int
get_hashtest(ser)1370 get_hashtest(ser)
1371 	int	ser;
1372 {
1373 	int	max_ser = maxser(&pk2);
1374 
1375 	if (ser > max_ser)
1376 		return (-1);
1377 
1378 	if (pk2.p_hash == NULL)
1379 		return (-1);
1380 
1381 	sseek(&pk2, get_off, SEEK_SET);
1382 	pk2.p_slnno = slnno;
1383 
1384 	pk2.p_reopen = 1;
1385 	pk2.p_chkeof = 1;
1386 	pk2.p_gotsid = pk2.p_idel[ser].i_sid;
1387 	pk2.p_reqsid = pk2.p_gotsid;
1388 
1389 	zero((char *) pk2.p_apply, (max_ser+1)*sizeof (*pk2.p_apply));
1390 	setup(&pk2, ser);
1391 
1392 	pk2.p_ghash = 0;
1393 	while (readmod(&pk2))
1394 		;
1395 
1396 	if (pk2.p_hash == NULL)
1397 		return (0);
1398 
1399 	if (pk2.p_hash[ser] != (pk2.p_ghash & 0xFFFF)) {
1400 		if (debug) {
1401 			char	str[SID_STRSIZE];
1402 
1403 			sid_ba(&pk2.p_gotsid, str);
1404 			printf(gettext(
1405 			"%s%s: SID %s: invalid checksum %d, expected %d\n"),
1406 					"    ", pk2.p_file,
1407 					str,
1408 					pk2.p_ghash & 0xFFFF,
1409 					pk2.p_hash[ser]);
1410 		}
1411 		infile_err |= CORRUPT_ERR;
1412 		return (0);
1413 	}
1414 	return (1);
1415 }
1416