test.c revision 96376
149884Ssheldonh/*	$NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $	*/
249884Ssheldonh
349884Ssheldonh/*
449884Ssheldonh * test(1); version 7-like  --  author Erik Baalbergen
549884Ssheldonh * modified by Eric Gisin to be used as built-in.
649884Ssheldonh * modified by Arnold Robbins to add SVR3 compatibility
749884Ssheldonh * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
849884Ssheldonh * modified by J.T. Conklin for NetBSD.
91556Srgrimes *
1049884Ssheldonh * This program is in the Public Domain.
111556Srgrimes */
121556Srgrimes
131556Srgrimes#ifndef lint
1436152Scharnierstatic const char rcsid[] =
1550471Speter  "$FreeBSD: head/bin/test/test.c 96376 2002-05-11 01:25:54Z alfred $";
161556Srgrimes#endif /* not lint */
171556Srgrimes
1849884Ssheldonh#include <sys/types.h>
191556Srgrimes#include <sys/stat.h>
201556Srgrimes
211556Srgrimes#include <ctype.h>
221556Srgrimes#include <err.h>
231556Srgrimes#include <errno.h>
2493345Sache#include <inttypes.h>
2576883Skris#include <limits.h>
2686619Sknu#include <stdarg.h>
271556Srgrimes#include <stdio.h>
281556Srgrimes#include <stdlib.h>
291556Srgrimes#include <string.h>
301556Srgrimes#include <unistd.h>
311556Srgrimes
3286505Sknu#ifdef SHELL
3386505Sknu#define main testcmd
3486505Sknu#include "bltin/bltin.h"
3586618Sknu#else
3688084Sache#include <locale.h>
3788084Sache
3896376Salfredstatic void error(const char *, ...) __dead2 __printf0like(1, 2);
3986618Sknu
4086618Sknustatic void
4186618Sknuerror(const char *msg, ...)
4286618Sknu{
4386618Sknu	va_list ap;
4486618Sknu	va_start(ap, msg);
4586618Sknu	verrx(2, msg, ap);
4686618Sknu	/*NOTREACHED*/
4786618Sknu	va_end(ap);
4886618Sknu}
4986618Sknu#endif
5086618Sknu
5149884Ssheldonh/* test(1) accepts the following grammar:
5249884Ssheldonh	oexpr	::= aexpr | aexpr "-o" oexpr ;
5349884Ssheldonh	aexpr	::= nexpr | nexpr "-a" aexpr ;
5449884Ssheldonh	nexpr	::= primary | "!" primary
5549884Ssheldonh	primary	::= unary-operator operand
5649884Ssheldonh		| operand binary-operator operand
5749884Ssheldonh		| operand
5849884Ssheldonh		| "(" oexpr ")"
5949884Ssheldonh		;
6049884Ssheldonh	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
6149884Ssheldonh		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
621556Srgrimes
6349884Ssheldonh	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
6449884Ssheldonh			"-nt"|"-ot"|"-ef";
6549884Ssheldonh	operand ::= <any legal UNIX file name>
6649884Ssheldonh*/
671556Srgrimes
6849884Ssheldonhenum token {
6949884Ssheldonh	EOI,
7049884Ssheldonh	FILRD,
7149884Ssheldonh	FILWR,
7249884Ssheldonh	FILEX,
7349884Ssheldonh	FILEXIST,
7449884Ssheldonh	FILREG,
7549884Ssheldonh	FILDIR,
7649884Ssheldonh	FILCDEV,
7749884Ssheldonh	FILBDEV,
7849884Ssheldonh	FILFIFO,
7949884Ssheldonh	FILSOCK,
8049884Ssheldonh	FILSYM,
8149884Ssheldonh	FILGZ,
8249884Ssheldonh	FILTT,
8349884Ssheldonh	FILSUID,
8449884Ssheldonh	FILSGID,
8549884Ssheldonh	FILSTCK,
8649884Ssheldonh	FILNT,
8749884Ssheldonh	FILOT,
8849884Ssheldonh	FILEQ,
8949884Ssheldonh	FILUID,
9049884Ssheldonh	FILGID,
9149884Ssheldonh	STREZ,
9249884Ssheldonh	STRNZ,
9349884Ssheldonh	STREQ,
9449884Ssheldonh	STRNE,
9549884Ssheldonh	STRLT,
9649884Ssheldonh	STRGT,
9749884Ssheldonh	INTEQ,
9849884Ssheldonh	INTNE,
9949884Ssheldonh	INTGE,
10049884Ssheldonh	INTGT,
10149884Ssheldonh	INTLE,
10249884Ssheldonh	INTLT,
10349884Ssheldonh	UNOT,
10449884Ssheldonh	BAND,
10549884Ssheldonh	BOR,
10649884Ssheldonh	LPAREN,
10749884Ssheldonh	RPAREN,
10849884Ssheldonh	OPERAND
1091556Srgrimes};
1101556Srgrimes
11149884Ssheldonhenum token_types {
11249884Ssheldonh	UNOP,
11349884Ssheldonh	BINOP,
11449884Ssheldonh	BUNOP,
11549884Ssheldonh	BBINOP,
11649884Ssheldonh	PAREN
1171556Srgrimes};
1181556Srgrimes
11949884Ssheldonhstruct t_op {
12049884Ssheldonh	const char *op_text;
12149884Ssheldonh	short op_num, op_type;
12249884Ssheldonh} const ops [] = {
12349884Ssheldonh	{"-r",	FILRD,	UNOP},
12449884Ssheldonh	{"-w",	FILWR,	UNOP},
12549884Ssheldonh	{"-x",	FILEX,	UNOP},
12649884Ssheldonh	{"-e",	FILEXIST,UNOP},
12749884Ssheldonh	{"-f",	FILREG,	UNOP},
12849884Ssheldonh	{"-d",	FILDIR,	UNOP},
12949884Ssheldonh	{"-c",	FILCDEV,UNOP},
13049884Ssheldonh	{"-b",	FILBDEV,UNOP},
13149884Ssheldonh	{"-p",	FILFIFO,UNOP},
13249884Ssheldonh	{"-u",	FILSUID,UNOP},
13349884Ssheldonh	{"-g",	FILSGID,UNOP},
13449884Ssheldonh	{"-k",	FILSTCK,UNOP},
13549884Ssheldonh	{"-s",	FILGZ,	UNOP},
13649884Ssheldonh	{"-t",	FILTT,	UNOP},
13749884Ssheldonh	{"-z",	STREZ,	UNOP},
13849884Ssheldonh	{"-n",	STRNZ,	UNOP},
13949884Ssheldonh	{"-h",	FILSYM,	UNOP},		/* for backwards compat */
14049884Ssheldonh	{"-O",	FILUID,	UNOP},
14149884Ssheldonh	{"-G",	FILGID,	UNOP},
14249884Ssheldonh	{"-L",	FILSYM,	UNOP},
14349884Ssheldonh	{"-S",	FILSOCK,UNOP},
14449884Ssheldonh	{"=",	STREQ,	BINOP},
14549884Ssheldonh	{"!=",	STRNE,	BINOP},
14649884Ssheldonh	{"<",	STRLT,	BINOP},
14749884Ssheldonh	{">",	STRGT,	BINOP},
14849884Ssheldonh	{"-eq",	INTEQ,	BINOP},
14949884Ssheldonh	{"-ne",	INTNE,	BINOP},
15049884Ssheldonh	{"-ge",	INTGE,	BINOP},
15149884Ssheldonh	{"-gt",	INTGT,	BINOP},
15249884Ssheldonh	{"-le",	INTLE,	BINOP},
15349884Ssheldonh	{"-lt",	INTLT,	BINOP},
15449884Ssheldonh	{"-nt",	FILNT,	BINOP},
15549884Ssheldonh	{"-ot",	FILOT,	BINOP},
15649884Ssheldonh	{"-ef",	FILEQ,	BINOP},
15749884Ssheldonh	{"!",	UNOT,	BUNOP},
15849884Ssheldonh	{"-a",	BAND,	BBINOP},
15949884Ssheldonh	{"-o",	BOR,	BBINOP},
16049884Ssheldonh	{"(",	LPAREN,	PAREN},
16149884Ssheldonh	{")",	RPAREN,	PAREN},
16249884Ssheldonh	{0,	0,	0}
1631556Srgrimes};
1641556Srgrimes
16549884Ssheldonhstruct t_op const *t_wp_op;
16649884Ssheldonhchar **t_wp;
1671556Srgrimes
16890111Simpstatic int	aexpr(enum token);
16990111Simpstatic int	binop(void);
17090111Simpstatic int	equalf(const char *, const char *);
17190111Simpstatic int	filstat(char *, enum token);
17290111Simpstatic int	getn(const char *);
17393345Sachestatic intmax_t	getq(const char *);
17490111Simpstatic int	intcmp(const char *, const char *);
17590111Simpstatic int	isoperand(void);
17690111Simpstatic int	newerf(const char *, const char *);
17790111Simpstatic int	nexpr(enum token);
17890111Simpstatic int	oexpr(enum token);
17990111Simpstatic int	olderf(const char *, const char *);
18090111Simpstatic int	primary(enum token);
18190111Simpstatic void	syntax(const char *, const char *);
18290111Simpstatic enum	token t_lex(char *);
18349884Ssheldonh
1841556Srgrimesint
18590111Simpmain(int argc, char **argv)
1861556Srgrimes{
18790133Sknu	int	i, res;
18855179Ssheldonh	char	*p;
18990133Sknu	char	**nargv;
1901556Srgrimes
19190133Sknu	/*
19290133Sknu	 * XXX copy the whole contents of argv to a newly allocated
19390133Sknu	 * space with two extra cells filled with NULL's - this source
19490133Sknu	 * code totally depends on their presence.
19590133Sknu	 */
19690133Sknu	if ((nargv = (char **)malloc((argc + 2) * sizeof(char *))) == NULL)
19790133Sknu		error("Out of space");
19890133Sknu
19990133Sknu	for (i = 0; i < argc; i++)
20090133Sknu		nargv[i] = argv[i];
20190133Sknu
20290133Sknu	nargv[i] = nargv[i + 1] = NULL;
20390133Sknu	argv = nargv;
20490133Sknu
20555179Ssheldonh	if ((p = rindex(argv[0], '/')) == NULL)
20655179Ssheldonh		p = argv[0];
20755179Ssheldonh	else
20855179Ssheldonh		p++;
20955179Ssheldonh	if (strcmp(p, "[") == 0) {
21086622Sknu		if (strcmp(argv[--argc], "]") != 0)
21186618Sknu			error("missing ]");
2121556Srgrimes		argv[argc] = NULL;
2131556Srgrimes	}
2141556Srgrimes
21588084Sache#ifndef SHELL
21688084Sache	(void)setlocale(LC_CTYPE, "");
21788084Sache#endif
21849884Ssheldonh	t_wp = &argv[1];
21949884Ssheldonh	res = !oexpr(t_lex(*t_wp));
2201556Srgrimes
22149884Ssheldonh	if (*t_wp != NULL && *++t_wp != NULL)
22249884Ssheldonh		syntax(*t_wp, "unexpected operator");
22349884Ssheldonh
22449884Ssheldonh	return res;
2251556Srgrimes}
2261556Srgrimes
22749884Ssheldonhstatic void
22890111Simpsyntax(const char *op, const char *msg)
2291556Srgrimes{
2301556Srgrimes
23149884Ssheldonh	if (op && *op)
23286618Sknu		error("%s: %s", op, msg);
23349884Ssheldonh	else
23486618Sknu		error("%s", msg);
2351556Srgrimes}
2361556Srgrimes
23749884Ssheldonhstatic int
23890111Simpoexpr(enum token n)
2391556Srgrimes{
24049884Ssheldonh	int res;
2411556Srgrimes
24249884Ssheldonh	res = aexpr(n);
24349884Ssheldonh	if (t_lex(*++t_wp) == BOR)
24449884Ssheldonh		return oexpr(t_lex(*++t_wp)) || res;
24549884Ssheldonh	t_wp--;
24649884Ssheldonh	return res;
24749884Ssheldonh}
2484171Sache
24949884Ssheldonhstatic int
25090111Simpaexpr(enum token n)
25149884Ssheldonh{
25249884Ssheldonh	int res;
2531556Srgrimes
25449884Ssheldonh	res = nexpr(n);
25549884Ssheldonh	if (t_lex(*++t_wp) == BAND)
25649884Ssheldonh		return aexpr(t_lex(*++t_wp)) && res;
25749884Ssheldonh	t_wp--;
25849884Ssheldonh	return res;
2591556Srgrimes}
2601556Srgrimes
2611556Srgrimesstatic int
26290111Simpnexpr(enum token n)
2631556Srgrimes{
26449884Ssheldonh	if (n == UNOT)
26549884Ssheldonh		return !nexpr(t_lex(*++t_wp));
26649884Ssheldonh	return primary(n);
2671556Srgrimes}
2681556Srgrimes
2691556Srgrimesstatic int
27090111Simpprimary(enum token n)
2711556Srgrimes{
27249884Ssheldonh	enum token nn;
27349884Ssheldonh	int res;
2741556Srgrimes
27549884Ssheldonh	if (n == EOI)
27649884Ssheldonh		return 0;		/* missing expression */
27749884Ssheldonh	if (n == LPAREN) {
27849884Ssheldonh		if ((nn = t_lex(*++t_wp)) == RPAREN)
27949884Ssheldonh			return 0;	/* missing expression */
28049884Ssheldonh		res = oexpr(nn);
28149884Ssheldonh		if (t_lex(*++t_wp) != RPAREN)
28249884Ssheldonh			syntax(NULL, "closing paren expected");
28349884Ssheldonh		return res;
28449884Ssheldonh	}
28549884Ssheldonh	if (t_wp_op && t_wp_op->op_type == UNOP) {
28649884Ssheldonh		/* unary expression */
28749884Ssheldonh		if (*++t_wp == NULL)
28849884Ssheldonh			syntax(t_wp_op->op_text, "argument expected");
28949884Ssheldonh		switch (n) {
29049884Ssheldonh		case STREZ:
29149884Ssheldonh			return strlen(*t_wp) == 0;
29249884Ssheldonh		case STRNZ:
29349884Ssheldonh			return strlen(*t_wp) != 0;
29449884Ssheldonh		case FILTT:
29549884Ssheldonh			return isatty(getn(*t_wp));
29649884Ssheldonh		default:
29749884Ssheldonh			return filstat(*t_wp, n);
29849884Ssheldonh		}
29949884Ssheldonh	}
3001556Srgrimes
30149884Ssheldonh	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
30249884Ssheldonh		return binop();
30349884Ssheldonh	}
30449884Ssheldonh
30549884Ssheldonh	return strlen(*t_wp) > 0;
3061556Srgrimes}
3071556Srgrimes
3081556Srgrimesstatic int
30990111Simpbinop(void)
3101556Srgrimes{
31149884Ssheldonh	const char *opnd1, *opnd2;
31249884Ssheldonh	struct t_op const *op;
3131556Srgrimes
31449884Ssheldonh	opnd1 = *t_wp;
31549884Ssheldonh	(void) t_lex(*++t_wp);
31649884Ssheldonh	op = t_wp_op;
3171556Srgrimes
31849884Ssheldonh	if ((opnd2 = *++t_wp) == NULL)
31949884Ssheldonh		syntax(op->op_text, "argument expected");
32049884Ssheldonh
32149884Ssheldonh	switch (op->op_num) {
32249884Ssheldonh	case STREQ:
32349884Ssheldonh		return strcmp(opnd1, opnd2) == 0;
32449884Ssheldonh	case STRNE:
32549884Ssheldonh		return strcmp(opnd1, opnd2) != 0;
32649884Ssheldonh	case STRLT:
32749884Ssheldonh		return strcmp(opnd1, opnd2) < 0;
32849884Ssheldonh	case STRGT:
32949884Ssheldonh		return strcmp(opnd1, opnd2) > 0;
33049884Ssheldonh	case INTEQ:
33162925Sse		return intcmp(opnd1, opnd2) == 0;
33249884Ssheldonh	case INTNE:
33362925Sse		return intcmp(opnd1, opnd2) != 0;
33449884Ssheldonh	case INTGE:
33562925Sse		return intcmp(opnd1, opnd2) >= 0;
33649884Ssheldonh	case INTGT:
33762925Sse		return intcmp(opnd1, opnd2) > 0;
33849884Ssheldonh	case INTLE:
33962925Sse		return intcmp(opnd1, opnd2) <= 0;
34049884Ssheldonh	case INTLT:
34162925Sse		return intcmp(opnd1, opnd2) < 0;
34249884Ssheldonh	case FILNT:
34349884Ssheldonh		return newerf (opnd1, opnd2);
34449884Ssheldonh	case FILOT:
34549884Ssheldonh		return olderf (opnd1, opnd2);
34649884Ssheldonh	case FILEQ:
34749884Ssheldonh		return equalf (opnd1, opnd2);
34849884Ssheldonh	default:
34949884Ssheldonh		abort();
35049884Ssheldonh		/* NOTREACHED */
3511556Srgrimes	}
3521556Srgrimes}
3531556Srgrimes
35449884Ssheldonhstatic int
35590111Simpfilstat(char *nm, enum token mode)
3561556Srgrimes{
35749884Ssheldonh	struct stat s;
3581556Srgrimes
35949884Ssheldonh	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
36049884Ssheldonh		return 0;
3612664Scsgr
36249884Ssheldonh	switch (mode) {
36349884Ssheldonh	case FILRD:
36491737Smaxim		return (eaccess(nm, R_OK) == 0);
36549884Ssheldonh	case FILWR:
36691737Smaxim		return (eaccess(nm, W_OK) == 0);
36749884Ssheldonh	case FILEX:
36891737Smaxim		/* XXX work around eaccess(2) false positives for superuser */
36991737Smaxim		if (eaccess(nm, X_OK) != 0)
37050087Sgreen			return 0;
37191737Smaxim		if (S_ISDIR(s.st_mode) || geteuid() != 0)
37250087Sgreen			return 1;
37350087Sgreen		return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
37449884Ssheldonh	case FILEXIST:
37591737Smaxim		return (eaccess(nm, F_OK) == 0);
37649884Ssheldonh	case FILREG:
37749884Ssheldonh		return S_ISREG(s.st_mode);
37849884Ssheldonh	case FILDIR:
37949884Ssheldonh		return S_ISDIR(s.st_mode);
38049884Ssheldonh	case FILCDEV:
38149884Ssheldonh		return S_ISCHR(s.st_mode);
38249884Ssheldonh	case FILBDEV:
38349884Ssheldonh		return S_ISBLK(s.st_mode);
38449884Ssheldonh	case FILFIFO:
38549884Ssheldonh		return S_ISFIFO(s.st_mode);
38649884Ssheldonh	case FILSOCK:
38749884Ssheldonh		return S_ISSOCK(s.st_mode);
38849884Ssheldonh	case FILSYM:
38949884Ssheldonh		return S_ISLNK(s.st_mode);
39049884Ssheldonh	case FILSUID:
39149884Ssheldonh		return (s.st_mode & S_ISUID) != 0;
39249884Ssheldonh	case FILSGID:
39349884Ssheldonh		return (s.st_mode & S_ISGID) != 0;
39449884Ssheldonh	case FILSTCK:
39549884Ssheldonh		return (s.st_mode & S_ISVTX) != 0;
39649884Ssheldonh	case FILGZ:
39749884Ssheldonh		return s.st_size > (off_t)0;
39849884Ssheldonh	case FILUID:
39949884Ssheldonh		return s.st_uid == geteuid();
40049884Ssheldonh	case FILGID:
40149884Ssheldonh		return s.st_gid == getegid();
40249884Ssheldonh	default:
40349884Ssheldonh		return 1;
4042675Scsgr	}
40549884Ssheldonh}
4062675Scsgr
40749884Ssheldonhstatic enum token
40890111Simpt_lex(char *s)
40949884Ssheldonh{
41049884Ssheldonh	struct t_op const *op = ops;
41149884Ssheldonh
41249884Ssheldonh	if (s == 0) {
41349884Ssheldonh		t_wp_op = NULL;
41449884Ssheldonh		return EOI;
41549884Ssheldonh	}
41649884Ssheldonh	while (op->op_text) {
41749884Ssheldonh		if (strcmp(s, op->op_text) == 0) {
41849884Ssheldonh			if ((op->op_type == UNOP && isoperand()) ||
41949884Ssheldonh			    (op->op_num == LPAREN && *(t_wp+1) == 0))
42049884Ssheldonh				break;
42149884Ssheldonh			t_wp_op = op;
42249884Ssheldonh			return op->op_num;
4231556Srgrimes		}
42449884Ssheldonh		op++;
4251556Srgrimes	}
42649884Ssheldonh	t_wp_op = NULL;
42749884Ssheldonh	return OPERAND;
4281556Srgrimes}
4291556Srgrimes
43049884Ssheldonhstatic int
43190111Simpisoperand(void)
4321556Srgrimes{
43349884Ssheldonh	struct t_op const *op = ops;
43449884Ssheldonh	char *s;
43549884Ssheldonh	char *t;
4361556Srgrimes
43749884Ssheldonh	if ((s  = *(t_wp+1)) == 0)
43849884Ssheldonh		return 1;
43949884Ssheldonh	if ((t = *(t_wp+2)) == 0)
44049884Ssheldonh		return 0;
44149884Ssheldonh	while (op->op_text) {
44249884Ssheldonh		if (strcmp(s, op->op_text) == 0)
44349884Ssheldonh			return op->op_type == BINOP &&
44449884Ssheldonh			    (t[0] != ')' || t[1] != '\0');
44549884Ssheldonh		op++;
44649884Ssheldonh	}
44749884Ssheldonh	return 0;
4481556Srgrimes}
4491556Srgrimes
45049884Ssheldonh/* atoi with error detection */
45149884Ssheldonhstatic int
45290111Simpgetn(const char *s)
4531556Srgrimes{
45449884Ssheldonh	char *p;
45549884Ssheldonh	long r;
4561556Srgrimes
45749884Ssheldonh	errno = 0;
45849884Ssheldonh	r = strtol(s, &p, 10);
45949884Ssheldonh
46088084Sache	if (s == p)
46188084Sache		error("%s: bad number", s);
46288084Sache
46349884Ssheldonh	if (errno != 0)
46487961Sache		error((errno == EINVAL) ? "%s: bad number" :
46587961Sache					  "%s: out of range", s);
46649884Ssheldonh
46749884Ssheldonh	while (isspace((unsigned char)*p))
46886622Sknu		p++;
46949884Ssheldonh
47049884Ssheldonh	if (*p)
47186622Sknu		error("%s: bad number", s);
47249884Ssheldonh
47349884Ssheldonh	return (int) r;
4741556Srgrimes}
47549884Ssheldonh
47662925Sse/* atoi with error detection and 64 bit range */
47793345Sachestatic intmax_t
47890111Simpgetq(const char *s)
47962925Sse{
48062925Sse	char *p;
48193345Sache	intmax_t r;
48262925Sse
48362925Sse	errno = 0;
48493345Sache	r = strtoimax(s, &p, 10);
48562925Sse
48688084Sache	if (s == p)
48788084Sache		error("%s: bad number", s);
48888084Sache
48962925Sse	if (errno != 0)
49087961Sache		error((errno == EINVAL) ? "%s: bad number" :
49187961Sache					  "%s: out of range", s);
49262925Sse
49362925Sse	while (isspace((unsigned char)*p))
49486622Sknu		p++;
49562925Sse
49662925Sse	if (*p)
49786622Sknu		error("%s: bad number", s);
49862925Sse
49962925Sse	return r;
50062925Sse}
50162925Sse
50249884Ssheldonhstatic int
50390111Simpintcmp (const char *s1, const char *s2)
50462925Sse{
50593345Sache	intmax_t q1, q2;
50662925Sse
50762925Sse
50862925Sse	q1 = getq(s1);
50962925Sse	q2 = getq(s2);
51062925Sse
51162925Sse	if (q1 > q2)
51262925Sse		return 1;
51362925Sse
51462925Sse	if (q1 < q2)
51562925Sse		return -1;
51662925Sse
51762925Sse	return 0;
51862925Sse}
51962925Sse
52062925Ssestatic int
52190111Simpnewerf (const char *f1, const char *f2)
52249884Ssheldonh{
52349884Ssheldonh	struct stat b1, b2;
52449884Ssheldonh
52549884Ssheldonh	return (stat (f1, &b1) == 0 &&
52649884Ssheldonh		stat (f2, &b2) == 0 &&
52749884Ssheldonh		b1.st_mtime > b2.st_mtime);
52849884Ssheldonh}
52949884Ssheldonh
53049884Ssheldonhstatic int
53190111Simpolderf (const char *f1, const char *f2)
53249884Ssheldonh{
53349884Ssheldonh	struct stat b1, b2;
53449884Ssheldonh
53549884Ssheldonh	return (stat (f1, &b1) == 0 &&
53649884Ssheldonh		stat (f2, &b2) == 0 &&
53749884Ssheldonh		b1.st_mtime < b2.st_mtime);
53849884Ssheldonh}
53949884Ssheldonh
54049884Ssheldonhstatic int
54190111Simpequalf (const char *f1, const char *f2)
54249884Ssheldonh{
54349884Ssheldonh	struct stat b1, b2;
54449884Ssheldonh
54549884Ssheldonh	return (stat (f1, &b1) == 0 &&
54649884Ssheldonh		stat (f2, &b2) == 0 &&
54749884Ssheldonh		b1.st_dev == b2.st_dev &&
54849884Ssheldonh		b1.st_ino == b2.st_ino);
54949884Ssheldonh}
550