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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * 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 
24 /*
25  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30 /*	  All Rights Reserved  	*/
31 
32 #if defined(sun)
33 #pragma ident	"@(#)test.c	1.17	06/06/20 SMI"
34 #endif
35 
36 #include "defs.h"
37 
38 /*
39  * Copyright 2008-2019 J. Schilling
40  *
41  * @(#)test.c	1.43 19/09/16 2008-2019 J. Schilling
42  */
43 #ifndef lint
44 static	UConst char sccsid[] =
45 	"@(#)test.c	1.43 19/09/16 2008-2019 J. Schilling";
46 #endif
47 
48 
49 /*
50  *      test expression
51  *      [ expression ]
52  */
53 
54 #ifdef	SCHILY_INCLUDES
55 #include	<schily/types.h>
56 #include	<schily/fcntl.h>
57 #include	<schily/stat.h>
58 #else
59 #include <sys/types.h>
60 #include <fcntl.h>
61 #include <sys/stat.h>
62 #endif
63 
64 #ifndef	HAVE_LSTAT
65 #define	lstat	stat
66 #undef	AT_SYMLINK_NOFOLLOW
67 #define	AT_SYMLINK_NOFOLLOW	0
68 #endif
69 #ifndef	HAVE_DECL_STAT
70 extern int stat	__PR((const char *, struct stat *));
71 #endif
72 #ifndef	HAVE_DECL_LSTAT
73 extern int lstat __PR((const char *, struct stat *));
74 #endif
75 
76 #define	exp	_exp	/* Some compilers do not like exp() */
77 
78 	int	test		__PR((int argn, unsigned char *com[]));
79 #ifdef	DO_SYSATEXPR
80 	void	expr		__PR((int argn, unsigned char *com[]));
81 static	long	aexpr		__PR((struct namnod *n,
82 						unsigned char *op, long y));
83 #endif
84 static	unsigned char *nxtarg	__PR((int mt));
85 static	int	exp		__PR((void));
86 static	int	e1		__PR((void));
87 static	int	e2		__PR((void));
88 static	int	e3		__PR((void));
89 static	int	test_unary	__PR((int op, unsigned char *arg));
90 static	int	test_binary	__PR((unsigned char *arg1, int op,
91 					unsigned char *arg2));
92 static	int	ftype		__PR((unsigned char *f, int field));
93 static	int	filtyp		__PR((unsigned char *f, int field));
94 #ifdef	DO_EXT_TEST
95 static	int	fsame		__PR((unsigned char *f1, unsigned char *f2));
96 static	int	ftime		__PR((unsigned char *f1, unsigned char *f2));
97 static	int	fnew		__PR((unsigned char *));
98 static	int	fowner		__PR((unsigned char *f, uid_t owner));
99 static	int	fgroup		__PR((unsigned char *f, uid_t owner));
100 #endif
101 static	int	fsizep		__PR((unsigned char *f));
102 static	Intmax_t str2imax	__PR((unsigned char *a));
103 
104 #undef	failed
105 #undef	bfailed
106 #define		failed(s1, s2)		bfailed(s1, s2, NULL)
107 static	void	bfailed		__PR((unsigned char *s1,
108 					const char *s2,
109 					unsigned char *s3));
110 
111 #ifdef	DO_POSIX_TEST
112 /*
113  * In POSIX mode, we need to overwrite the standard error code with a
114  * value > 1, this is ETEST (2).
115  */
116 #undef	ERROR
117 #define	ERROR	ETEST
118 #endif
119 
120 #ifdef	DO_SYSATEXPR
121 static int	isexpr;
122 #endif
123 static int	ap, ac;
124 static unsigned char **av;
125 static jmp_buf	testsyntax;
126 
127 #define	nargs()	(ac - ap)
128 
129 /*
130  * Set up test_unops[] to avoid calling test_unary() with non-unary
131  * operators. The following #defines influence the number os unary
132  * operators:
133  *
134  * DO_POSIX_TEST				-e -S
135  * DO_EXT_TEST					-C -D -G -N -O -P
136  * defined(DO_EXT_TEST) && defined(DO_SET_O)	-o
137  * normal unaries from old Bourne Shell		Lbcdfghknprstuwxz
138  */
139 #ifdef	PROTOTYPES
140 const char	test_unops[] = "Lbcdfghknprstuwxz"
141 #ifdef	DO_POSIX_TEST
142 		"eS"
143 #endif
144 #ifdef	DO_EXT_TEST
145 		"CDGNOP"
146 #endif
147 #if defined(DO_EXT_TEST) && defined(DO_SET_O)
148 		"o"
149 #endif
150 		"";
151 #else	/* !PROTOTYPES */
152 #if defined(DO_POSIX_TEST) || defined(DO_EXT_TEST)
153 const char	test_unops[] = "LbcdfghknprstuwxzeSCDGNOPo";
154 #else
155 const char	test_unops[] = "Lbcdfghknprstuwxz";
156 #endif
157 #endif	/* !PROTOTYPES */
158 
159 int
test(argn,com)160 test(argn, com)
161 	int		argn;
162 	unsigned char	*com[];
163 {
164 #ifdef	DO_POSIX_TEST
165 	int	not;
166 	int	inv = 0;
167 	int	op;
168 #endif
169 	ac = argn;
170 	av = com;
171 	ap = 1;
172 #ifdef	DO_SYSATEXPR
173 	isexpr = 0;
174 #endif
175 
176 	if (eq(com[0], "[")) {
177 		if (!eq(com[--ac], "]")) {
178 			Failure((unsigned char *)"test", nobracket);
179 			return (SYNBAD);
180 		}
181 	}
182 	com[ac] = 0;
183 	if (ac <= 1)				/* POSIX case: 0 args	*/
184 		return (1);			/* test exits false	*/
185 	if (setjmp(testsyntax))
186 		return (ETEST);
187 
188 #ifdef	DO_POSIX_TEST
189 	not = com[1][0] == '!' && com[1][1] == '\0';
190 	com++;
191 	switch (ac) {
192 
193 	default:				/* POSIX >4 args unspec	*/
194 		break;
195 
196 	case 5:
197 		if (not) {
198 			inv = 1;
199 			com++;
200 			not = com[0][0] == '!' && com[0][1] == '\0';
201 
202 		} else if ((com[0][0] == '(' && com[0][1] == '\0') &&
203 			    (com[3][0] == ')' && com[3][1] == '\0')) {
204 			com++;
205 			not = com[0][0] == '!' && com[0][1] == '\0';
206 			goto two;
207 		} else {
208 			break;			/* Unspecified by POSIX	*/
209 		}
210 		/* FALLTHROUGH */
211 
212 	case 4:
213 		op = syslook(com[1], test_ops, no_test_ops);
214 		if (op)
215 			return (inv ^ !test_binary(com[0], op, com[2]));
216 
217 		if (not) {
218 			inv = 1;
219 			com++;
220 			not = com[0][0] == '!' && com[0][1] == '\0';
221 
222 		} else if ((com[0][0] == '(' && com[0][1] == '\0') &&
223 			    (com[2][0] == ')' && com[2][1] == '\0')) {
224 			com++;
225 			not = com[0][0] == '!' && com[0][1] == '\0';
226 			goto one;
227 		} else {
228 			break;			/* Unspecified by POSIX	*/
229 		}
230 		/* FALLTHROUGH */
231 	case 3:
232 	two:
233 		if (not)
234 			return (inv ^ (com[1][0] != 0));
235 
236 		if (com[0][0] == '-' &&
237 		    com[0][1] != '\0' && com[0][2] == '\0' &&
238 		    strchr(test_unops, com[0][1]))
239 			return (inv ^ !test_unary(com[0][1], com[1]));
240 
241 		break;				/* Unspecified by POSIX	*/
242 	case 2:
243 	one:
244 		/*
245 		 * Compatibility for UNIX -t without parameter
246 		 */
247 		if (!(flags2 & posixflg) && eq(com[0], "-t"))
248 			break;
249 
250 		return (inv ^ (com[0][0] == 0));
251 	}
252 #endif
253 
254 	return (exp() ? 0 : 1);
255 }
256 
257 #ifdef	DO_SYSATEXPR
258 void
expr(argn,com)259 expr(argn, com)
260 	int		argn;
261 	unsigned char	*com[];
262 {
263 	int		incr = 0;
264 	struct namnod	*n = NULL;		/* Make GCC happy */
265 	char		buf[40];
266 
267 	ac = argn;
268 	av = com;
269 	ap = optskip(argn, com, "@ expr");
270 	if (ap < 0)
271 		return;
272 	isexpr = 1;
273 
274 	if (ac == 2) {				/* @ var++ */
275 		int len = length(av[ap]);
276 
277 		if (len > 3) {
278 			unsigned char	*p = av[ap] + len - 3;
279 
280 			if (eq(p, "++"))
281 				incr = 1;
282 			else if (eq(p, "--"))
283 				incr = -1;
284 			if (incr) {
285 				*p = '\0';
286 				n = lookup(av[ap]);
287 			}
288 		}
289 		if (incr == 0) {
290 			Failure((unsigned char *)"@", noarg);
291 			return;
292 		}
293 	} else if (ac < 4) {
294 		Failure((unsigned char *)"@", noarg);
295 		return;
296 	}
297 	if (setjmp(testsyntax))
298 		return;
299 	if (incr) {
300 		snprintf(buf, sizeof (buf), "%ld", aexpr(n, UC "+=", incr));
301 	} else {
302 		n = lookup(av[ap++]);
303 		snprintf(buf, sizeof (buf), "%ld", aexpr(n, av[ap++], exp(0)));
304 	}
305 	assign(n, UC buf);
306 }
307 
308 static long
aexpr(n,op,y)309 aexpr(n, op, y)
310 	struct namnod	*n;
311 	unsigned char	*op;
312 	long		y;
313 {
314 	long		x;
315 	char		c = *op;
316 
317 	if (eq(op, "="))
318 		return (y);
319 
320 	if (c == 0 || op[1] != '=' || op[2])
321 		bfailed((unsigned char *)"@", badop, op);
322 
323 	if (n->namval == NULL)
324 		failed((unsigned char *)"@", unset);
325 	x = str2imax(n->namval);
326 
327 	switch (c) {
328 
329 	case '+':	return (x + y);
330 	case '-':	return (x - y);
331 	case '*':	return (x * y);
332 	case '/':
333 			if (y == 0)
334 				failed((unsigned char *)"@", divzero);
335 			return (x / y);
336 	case '%':
337 			if (y == 0)
338 				failed((unsigned char *)"@", divzero);
339 			return (x % y);
340 
341 	default:
342 		bfailed((unsigned char *)"@", badop, op);
343 	}
344 
345 	return (-1);
346 }
347 #endif
348 
349 static unsigned char *
nxtarg(mt)350 nxtarg(mt)
351 	int	mt;
352 {
353 	if (ap >= ac) {
354 		if (mt) {
355 			ap++;
356 			return (0);
357 		}
358 		failed((unsigned char *)"test", noarg);
359 	}
360 	return (av[ap++]);
361 }
362 
363 /*
364  * The main test expression evaluator.
365  * Returns	0 -> FALSE
366  *		!= 0 -> TRUE
367  */
368 /* ARGSUSED */
369 static int
exp()370 exp()
371 {
372 	int	p1;
373 	unsigned char	*p2;
374 
375 	p1 = e1();
376 	p2 = nxtarg(1);
377 	if (p2 != 0) {
378 		if (eq(p2, "-o"))
379 			return (p1 | exp());
380 
381 #ifdef	__nono__
382 		if (!eq(p2, ")"))
383 			failed((unsigned char *)"test", synmsg);
384 #endif
385 	}
386 	ap--;
387 	return (p1);
388 }
389 
390 static int
e1()391 e1()
392 {
393 	int	p1;
394 	unsigned char	*p2;
395 
396 	p1 = e2();
397 	p2 = nxtarg(1);
398 
399 	if ((p2 != 0) && eq(p2, "-a"))
400 		return (p1 & e1());
401 	ap--;
402 	return (p1);
403 }
404 
405 static int
e2()406 e2()
407 {
408 	if (eq(nxtarg(0), "!"))
409 		return (!e3());
410 	ap--;
411 	return (e3());
412 }
413 
414 static int
e3()415 e3()
416 {
417 	int	p1;
418 	unsigned char	*a;
419 	unsigned char	*p2;
420 
421 	a = nxtarg(0);
422 	if (eq(a, "(")) {
423 		p1 = exp();
424 		if (!eq(nxtarg(0), ")"))
425 			failed((unsigned char *)"test", noparen);
426 		return (p1);
427 	}
428 	p2 = nxtarg(1);
429 	ap--;
430 	if ((p2 == 0) || (!eq(p2, "=") && !eq(p2, "!="))) {
431 		if (eq(a, "-t")) {
432 			unsigned char	*na;
433 
434 			if (ap >= ac)		/* no args */
435 				return (isatty(STDOUT_FILENO));
436 			na = nxtarg(0);
437 			ap--;
438 			if (eq(na, "-a") || eq(na, "-o"))
439 				return (isatty(STDOUT_FILENO));
440 		}
441 		if (a[0] == '-' && a[1] != '\0' && a[2] == '\0' &&
442 		    strchr(test_unops, a[1]))
443 			return (test_unary(a[1], nxtarg(0)));
444 	}
445 
446 	p2 = nxtarg(1);
447 	if (p2 == 0) {
448 #ifdef	DO_SYSATEXPR
449 		if (isexpr && digit(*a)) {
450 			ll_1 = str2imax(a);
451 			return (ll_1);
452 		}
453 #endif
454 		return (!eq(a, ""));
455 	}
456 
457 	p1 = syslook(p2, test_ops, no_test_ops);
458 	if (p1 == TEST_AND || p1 == TEST_OR) {
459 		ap--;
460 		return (!eq(a, ""));
461 	}
462 	if (p1) {
463 		return (test_binary(a, p1, nxtarg(0)));
464 	}
465 
466 #ifdef	DO_SYSATEXPR
467 	if (isexpr) {
468 		char	c = *p2;
469 
470 		if (c && p2[1] == '\0') {
471 			if (c == '+')
472 				return (ll_1 + ll_2);
473 			if (c == '-')
474 				return (ll_1 - ll_2);
475 			if (c == '*')
476 				return (ll_1 * ll_2);
477 			if (c == '/') {
478 				if (ll_2 == 0)
479 					failed((unsigned char *)"@", divzero);
480 				return (ll_1 / ll_2);
481 			}
482 			if (c == '%') {
483 				if (ll_2 == 0)
484 					failed((unsigned char *)"@", divzero);
485 				return (ll_1 % ll_2);
486 			}
487 			if (c == '&')
488 				return (ll_1 & ll_2);
489 			if (c == '|')
490 				return (ll_1 | ll_2);
491 			if (c == '>')
492 				return (ll_1 > ll_2);
493 			if (c == '<')
494 				return (ll_1 < ll_2);
495 		}
496 		if (eq(p2, "&&"))
497 			return (ll_1 && ll_2);
498 		if (eq(p2, "||"))
499 			return (ll_1 || ll_2);
500 		if (eq(p2, ">="))
501 			return (ll_1 >= ll_2);
502 		if (eq(p2, "<="))
503 			return (ll_1 <= ll_2);
504 		if (eq(p2, ">>"))
505 			return (ll_1 >> ll_2);
506 		if (eq(p2, "<<"))
507 			return (ll_1 << ll_2);
508 	}
509 #endif
510 
511 	bfailed((unsigned char *)btest, badop, p2);
512 	/* NOTREACHED */
513 
514 	return (0);		/* Not reached, but keeps GCC happy */
515 }
516 
517 static int
test_unary(op,arg)518 test_unary(op, arg)
519 	int		op;
520 	unsigned char	*arg;
521 {
522 	switch (op) {
523 #ifdef	DO_POSIX_TEST
524 	case 'e':
525 			return (chk_access(arg, F_OK, 0) == 0);
526 #endif
527 	case 'r':
528 			return (chk_access(arg, S_IREAD, 0) == 0);
529 	case 'w':
530 			return (chk_access(arg, S_IWRITE, 0) == 0);
531 	case 'x':
532 			return (chk_access(arg, S_IEXEC, 0) == 0);
533 	case 'd':
534 			return (filtyp(arg, S_IFDIR));
535 #ifdef	DO_EXT_TEST
536 	case 'D':
537 #ifdef	S_IFDOOR
538 			return (filtyp(arg, S_IFDOOR));
539 #else
540 			return (0);
541 #endif
542 	case 'C':
543 #ifdef	S_IFCTG
544 			return (filtyp(arg, S_IFCTG));
545 #else
546 			return (0);
547 #endif
548 #endif
549 	case 'c':
550 			return (filtyp(arg, S_IFCHR));
551 	case 'b':
552 			return (filtyp(arg, S_IFBLK));
553 	case 'f':
554 			if (ucb_builtins) {
555 				struct stat statb;
556 
557 				return (lstatat((char *)arg, &statb, 0) >= 0 &&
558 					(statb.st_mode & S_IFMT) != S_IFDIR);
559 			} else {
560 				return (filtyp(arg, S_IFREG));
561 			}
562 	case 'u':
563 			return (ftype(arg, S_ISUID));
564 	case 'g':
565 			return (ftype(arg, S_ISGID));
566 	case 'k':
567 #ifdef	S_ISVTX
568 			return (ftype(arg, S_ISVTX));
569 #else
570 			return (0);
571 #endif
572 #if	defined(DO_EXT_TEST) && defined(DO_SET_O)
573 	case 'o':
574 			if (arg && *arg == '?') {
575 				return (lookopt(++arg) != NULL);
576 			}
577 			if (arg)
578 				return (optval(lookopt(arg)));
579 			return (0);	/* should never happen */
580 #endif
581 	case 'p':
582 			return (filtyp(arg, S_IFIFO));
583 	case 'h':
584 	case 'L':
585 			return (filtyp(arg, S_IFLNK));
586 #ifdef	DO_EXT_TEST
587 	case 'P':
588 #if defined(S_IFPORT) && S_IFPORT != S_IFIFO	/* Do not use it on Ultrix */
589 
590 			return (filtyp(arg, S_IFPORT));
591 #else
592 			return (0);
593 #endif
594 #endif
595 #ifdef	DO_POSIX_TEST
596 	case 'S':
597 #ifdef	S_IFSOCK
598 			return (filtyp(arg, S_IFSOCK));
599 #else
600 			return (0);
601 #endif
602 #endif
603 	case 's':
604 			return (fsizep(arg));
605 	case 't':
606 			return (isatty(atoi((char *)arg)));
607 #ifdef	DO_EXT_TEST
608 	case 'O':
609 			return (fowner(arg, geteuid()));
610 	case 'G':
611 			return (fgroup(arg, getegid()));
612 	case 'N':
613 			return (fnew(arg));
614 #endif
615 	case 'n':
616 			return (!eq(arg, ""));
617 	case 'z':
618 			return (eq(arg, ""));
619 
620 	default:
621 			failed((unsigned char *)"test", noarg);
622 			return (SYNBAD);
623 	}
624 }
625 
626 static int
test_binary(arg1,op,arg2)627 test_binary(arg1, op, arg2)
628 	unsigned char	*arg1;
629 	int		op;
630 	unsigned char	*arg2;
631 {
632 	Intmax_t	ll_1 = 0;	/* Avoid warning from silly GCC */
633 	Intmax_t	ll_2 = 0;	/* Avoid warning from silly GCC */
634 
635 	if (op >= TEST_EQ) {
636 		ll_1 = str2imax(arg1);
637 		ll_2 = str2imax(arg2);
638 	}
639 	switch (op) {
640 
641 	case TEST_AND:	return (*arg1 && *arg2);
642 	case TEST_OR:	return (*arg1 || *arg2);
643 
644 #ifdef	DO_EXT_TEST
645 	case TEST_EF:	return (fsame(arg1, arg2));
646 	case TEST_NT:	return (ftime(arg1, arg2) > 0);
647 	case TEST_OT:	return (ftime(arg1, arg2) < 0);
648 #endif
649 	case TEST_SEQ:	return (eq(arg1, arg2));
650 	case TEST_SNEQ:	return (!eq(arg1, arg2));
651 
652 	case TEST_EQ:	return (ll_1 == ll_2);
653 	case TEST_NE:	return (ll_1 != ll_2);
654 	case TEST_GT:	return (ll_1 > ll_2);
655 	case TEST_LT:	return (ll_1 < ll_2);
656 	case TEST_GE:	return (ll_1 >= ll_2);
657 	case TEST_LE:	return (ll_1 <= ll_2);
658 
659 	default:	return (SYNBAD);
660 	}
661 }
662 
663 static int
ftype(f,field)664 ftype(f, field)
665 	unsigned char	*f;
666 	int		field;
667 {
668 	struct stat statb;
669 
670 	if (lstatat((char *)f, &statb, 0) < 0)
671 		return (0);
672 	if ((statb.st_mode & field) == field)
673 		return (1);
674 	return (0);
675 }
676 
677 static int
filtyp(f,field)678 filtyp(f, field)
679 	unsigned char	*f;
680 	int		field;
681 {
682 	struct stat statb;
683 	int	flag = (field == S_IFLNK) ? AT_SYMLINK_NOFOLLOW : 0;
684 
685 	if (lstatat((char *)f, &statb, flag) < 0)
686 		return (0);
687 	if ((statb.st_mode & S_IFMT) == field)
688 		return (1);
689 	else
690 		return (0);
691 }
692 
693 #ifdef	DO_EXT_TEST
694 static int
fsame(f1,f2)695 fsame(f1, f2)
696 	unsigned char	*f1;
697 	unsigned char	*f2;
698 {
699 	struct	stat	statb1;
700 	struct	stat	statb2;
701 
702 	if (lstatat((char *)f1, &statb1, 0) < 0)	/* lstat() ??? */
703 		return (FALSE);
704 	if (lstatat((char *)f2, &statb2, 0) < 0)	/* lstat() ??? */
705 		return (FALSE);
706 	if (statb1.st_ino == statb2.st_ino && statb1.st_dev == statb2.st_dev)
707 		return (1);
708 	return (FALSE);
709 }
710 
711 static int					/* mod time f1 - mod time f2 */
ftime(f1,f2)712 ftime(f1, f2)
713 	unsigned char	*f1;
714 	unsigned char	*f2;
715 {
716 	struct	stat	statb1;
717 	struct	stat	statb2;
718 	int		ret;
719 
720 	ret = lstatat((char *)f1, &statb1, 0);	/* lstat() ??? */
721 	if (lstatat((char *)f2, &statb2, 0) < 0) /* lstat() ??? */
722 		return (ret < 0 ? 0:1);
723 	if (ret < 0)
724 		return (-1);
725 	if (statb1.st_mtime > statb2.st_mtime)
726 		return (1);
727 	if (statb1.st_mtime == statb2.st_mtime &&
728 	    stat_mnsecs(&statb1) > stat_mnsecs(&statb2))
729 		return (1);
730 	if (statb1.st_mtime < statb2.st_mtime)
731 		return (-1);
732 	if (statb1.st_mtime == statb2.st_mtime &&
733 	    stat_mnsecs(&statb1) < stat_mnsecs(&statb2))
734 		return (-1);
735 	return (0);
736 }
737 
738 static int
fnew(f)739 fnew(f)
740 	unsigned char	*f;
741 {
742 	struct	stat	statb;
743 
744 	if (lstatat((char *)f, &statb, 0) < 0)	/* lstat() ??? */
745 		return (0);
746 
747 	if (statb.st_mtime > statb.st_atime)
748 		return (1);
749 	if (statb.st_mtime == statb.st_atime &&
750 	    stat_mnsecs(&statb) > stat_ansecs(&statb))
751 		return (1);
752 	return (0);
753 }
754 
755 static int
fowner(f,owner)756 fowner(f, owner)
757 	unsigned char	*f;
758 	uid_t		owner;
759 {
760 	struct	stat	statb;
761 
762 	if (lstatat((char *)f, &statb, 0) < 0)	/* lstat() ??? */
763 		return (FALSE);
764 	return (statb.st_uid == owner);
765 }
766 
767 static int
fgroup(f,group)768 fgroup(f, group)
769 	unsigned char	*f;
770 	gid_t		group;
771 {
772 	struct	stat	statb;
773 
774 	if (lstatat((char *)f, &statb, 0) < 0)	/* lstat() ??? */
775 		return (FALSE);
776 	return (statb.st_gid == group);
777 }
778 #endif
779 
780 static int
fsizep(f)781 fsizep(f)
782 	unsigned char	*f;
783 {
784 	struct stat statb;
785 
786 	if (lstatat((char *)f, &statb, 0) < 0)
787 		return (0);
788 	return (statb.st_size > 0);
789 }
790 
791 static Intmax_t
str2imax(a)792 str2imax(a)
793 	unsigned char	*a;
794 {
795 	Intmax_t	i;
796 	char		*ep;
797 
798 #ifdef	HAVE_STRTOLL
799 	i = strtoll((char *)a, &ep, 10);
800 #else
801 	i = strtol((char *)a, &ep, 10);
802 #endif
803 #ifdef	DO_POSIX_TEST
804 	if ((char *)a == ep || *ep != '\0')
805 		bfailed((unsigned char *)ep, badnum, NULL);
806 #endif
807 	return (i);
808 }
809 
810 static void
bfailed(s1,s2,s3)811 bfailed(s1, s2, s3)
812 	unsigned char	*s1;
813 	const char	*s2;
814 	unsigned char	*s3;
815 {
816 #ifdef	DO_POSIX_FAILURE
817 	failure_real(ETEST, s1, s2, s3, 0);
818 #else
819 	failed_real(ETEST, s1, s2, s3);
820 #endif
821 	longjmp(testsyntax, 1);
822 }
823