test.c revision 86618
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 86618 2001-11-19 19:57:45Z knu $";
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>
2476883Skris#include <limits.h>
251556Srgrimes#include <stdio.h>
261556Srgrimes#include <stdlib.h>
271556Srgrimes#include <string.h>
281556Srgrimes#include <unistd.h>
291556Srgrimes
3086505Sknu#ifdef SHELL
3186505Sknu#define main testcmd
3286505Sknu#include "bltin/bltin.h"
3386618Sknu#else
3486618Sknustatic void error(const char *, ...) __attribute__((__noreturn__));
3586618Sknu
3686618Sknustatic void
3786618Sknu#ifdef __STDC__
3886618Sknuerror(const char *msg, ...)
3986618Sknu#else
4086618Sknuerror(va_alist)
4186618Sknu	va_dcl
4286505Sknu#endif
4386618Sknu{
4486618Sknu	va_list ap;
4586618Sknu#ifndef __STDC__
4686618Sknu	const char *msg;
4786505Sknu
4886618Sknu	va_start(ap);
4986618Sknu	msg = va_arg(ap, const char *);
5086618Sknu#else
5186618Sknu	va_start(ap, msg);
5286618Sknu#endif
5386618Sknu	verrx(2, msg, ap);
5486618Sknu	/*NOTREACHED*/
5586618Sknu	va_end(ap);
5686618Sknu}
5786618Sknu#endif
5886618Sknu
5949884Ssheldonh/* test(1) accepts the following grammar:
6049884Ssheldonh	oexpr	::= aexpr | aexpr "-o" oexpr ;
6149884Ssheldonh	aexpr	::= nexpr | nexpr "-a" aexpr ;
6249884Ssheldonh	nexpr	::= primary | "!" primary
6349884Ssheldonh	primary	::= unary-operator operand
6449884Ssheldonh		| operand binary-operator operand
6549884Ssheldonh		| operand
6649884Ssheldonh		| "(" oexpr ")"
6749884Ssheldonh		;
6849884Ssheldonh	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
6949884Ssheldonh		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
701556Srgrimes
7149884Ssheldonh	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
7249884Ssheldonh			"-nt"|"-ot"|"-ef";
7349884Ssheldonh	operand ::= <any legal UNIX file name>
7449884Ssheldonh*/
751556Srgrimes
7649884Ssheldonhenum token {
7749884Ssheldonh	EOI,
7849884Ssheldonh	FILRD,
7949884Ssheldonh	FILWR,
8049884Ssheldonh	FILEX,
8149884Ssheldonh	FILEXIST,
8249884Ssheldonh	FILREG,
8349884Ssheldonh	FILDIR,
8449884Ssheldonh	FILCDEV,
8549884Ssheldonh	FILBDEV,
8649884Ssheldonh	FILFIFO,
8749884Ssheldonh	FILSOCK,
8849884Ssheldonh	FILSYM,
8949884Ssheldonh	FILGZ,
9049884Ssheldonh	FILTT,
9149884Ssheldonh	FILSUID,
9249884Ssheldonh	FILSGID,
9349884Ssheldonh	FILSTCK,
9449884Ssheldonh	FILNT,
9549884Ssheldonh	FILOT,
9649884Ssheldonh	FILEQ,
9749884Ssheldonh	FILUID,
9849884Ssheldonh	FILGID,
9949884Ssheldonh	STREZ,
10049884Ssheldonh	STRNZ,
10149884Ssheldonh	STREQ,
10249884Ssheldonh	STRNE,
10349884Ssheldonh	STRLT,
10449884Ssheldonh	STRGT,
10549884Ssheldonh	INTEQ,
10649884Ssheldonh	INTNE,
10749884Ssheldonh	INTGE,
10849884Ssheldonh	INTGT,
10949884Ssheldonh	INTLE,
11049884Ssheldonh	INTLT,
11149884Ssheldonh	UNOT,
11249884Ssheldonh	BAND,
11349884Ssheldonh	BOR,
11449884Ssheldonh	LPAREN,
11549884Ssheldonh	RPAREN,
11649884Ssheldonh	OPERAND
1171556Srgrimes};
1181556Srgrimes
11949884Ssheldonhenum token_types {
12049884Ssheldonh	UNOP,
12149884Ssheldonh	BINOP,
12249884Ssheldonh	BUNOP,
12349884Ssheldonh	BBINOP,
12449884Ssheldonh	PAREN
1251556Srgrimes};
1261556Srgrimes
12749884Ssheldonhstruct t_op {
12849884Ssheldonh	const char *op_text;
12949884Ssheldonh	short op_num, op_type;
13049884Ssheldonh} const ops [] = {
13149884Ssheldonh	{"-r",	FILRD,	UNOP},
13249884Ssheldonh	{"-w",	FILWR,	UNOP},
13349884Ssheldonh	{"-x",	FILEX,	UNOP},
13449884Ssheldonh	{"-e",	FILEXIST,UNOP},
13549884Ssheldonh	{"-f",	FILREG,	UNOP},
13649884Ssheldonh	{"-d",	FILDIR,	UNOP},
13749884Ssheldonh	{"-c",	FILCDEV,UNOP},
13849884Ssheldonh	{"-b",	FILBDEV,UNOP},
13949884Ssheldonh	{"-p",	FILFIFO,UNOP},
14049884Ssheldonh	{"-u",	FILSUID,UNOP},
14149884Ssheldonh	{"-g",	FILSGID,UNOP},
14249884Ssheldonh	{"-k",	FILSTCK,UNOP},
14349884Ssheldonh	{"-s",	FILGZ,	UNOP},
14449884Ssheldonh	{"-t",	FILTT,	UNOP},
14549884Ssheldonh	{"-z",	STREZ,	UNOP},
14649884Ssheldonh	{"-n",	STRNZ,	UNOP},
14749884Ssheldonh	{"-h",	FILSYM,	UNOP},		/* for backwards compat */
14849884Ssheldonh	{"-O",	FILUID,	UNOP},
14949884Ssheldonh	{"-G",	FILGID,	UNOP},
15049884Ssheldonh	{"-L",	FILSYM,	UNOP},
15149884Ssheldonh	{"-S",	FILSOCK,UNOP},
15249884Ssheldonh	{"=",	STREQ,	BINOP},
15349884Ssheldonh	{"!=",	STRNE,	BINOP},
15449884Ssheldonh	{"<",	STRLT,	BINOP},
15549884Ssheldonh	{">",	STRGT,	BINOP},
15649884Ssheldonh	{"-eq",	INTEQ,	BINOP},
15749884Ssheldonh	{"-ne",	INTNE,	BINOP},
15849884Ssheldonh	{"-ge",	INTGE,	BINOP},
15949884Ssheldonh	{"-gt",	INTGT,	BINOP},
16049884Ssheldonh	{"-le",	INTLE,	BINOP},
16149884Ssheldonh	{"-lt",	INTLT,	BINOP},
16249884Ssheldonh	{"-nt",	FILNT,	BINOP},
16349884Ssheldonh	{"-ot",	FILOT,	BINOP},
16449884Ssheldonh	{"-ef",	FILEQ,	BINOP},
16549884Ssheldonh	{"!",	UNOT,	BUNOP},
16649884Ssheldonh	{"-a",	BAND,	BBINOP},
16749884Ssheldonh	{"-o",	BOR,	BBINOP},
16849884Ssheldonh	{"(",	LPAREN,	PAREN},
16949884Ssheldonh	{")",	RPAREN,	PAREN},
17049884Ssheldonh	{0,	0,	0}
1711556Srgrimes};
1721556Srgrimes
17349884Ssheldonhstruct t_op const *t_wp_op;
17449884Ssheldonhchar **t_wp;
1751556Srgrimes
17676883Skrisstatic int	aexpr __P((enum token));
17776883Skrisstatic int	binop __P((void));
17876883Skrisstatic int	equalf __P((const char *, const char *));
17976883Skrisstatic int	filstat __P((char *, enum token));
18076883Skrisstatic int	getn __P((const char *));
18176883Skrisstatic quad_t	getq __P((const char *));
18276883Skrisstatic int	intcmp __P((const char *, const char *));
18376883Skrisstatic int	isoperand __P((void));
18476883Skrisint		main __P((int, char **));
18576883Skrisstatic int	newerf __P((const char *, const char *));
18676883Skrisstatic int	nexpr __P((enum token));
18776883Skrisstatic int	oexpr __P((enum token));
18876883Skrisstatic int	olderf __P((const char *, const char *));
18976883Skrisstatic int	primary __P((enum token));
19076883Skrisstatic void	syntax __P((const char *, const char *));
19176883Skrisstatic enum	token t_lex __P((char *));
19249884Ssheldonh
1931556Srgrimesint
1941556Srgrimesmain(argc, argv)
1951556Srgrimes	int argc;
19649884Ssheldonh	char **argv;
1971556Srgrimes{
19849884Ssheldonh	int	res;
19955179Ssheldonh	char	*p;
2001556Srgrimes
20155179Ssheldonh	if ((p = rindex(argv[0], '/')) == NULL)
20255179Ssheldonh		p = argv[0];
20355179Ssheldonh	else
20455179Ssheldonh		p++;
20555179Ssheldonh	if (strcmp(p, "[") == 0) {
2061556Srgrimes		if (strcmp(argv[--argc], "]"))
20786618Sknu			error("missing ]");
2081556Srgrimes		argv[argc] = NULL;
2091556Srgrimes	}
2101556Srgrimes
21150302Sgreen	/* XXX work around the absence of an eaccess(2) syscall */
21250087Sgreen	(void)setgid(getegid());
21350087Sgreen	(void)setuid(geteuid());
21450087Sgreen
21586618Sknu	if (--argc <= 0)
21686618Sknu		return 1;
21786618Sknu
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
22849884Ssheldonhsyntax(op, msg)
22949884Ssheldonh	const char	*op;
23049884Ssheldonh	const char	*msg;
2311556Srgrimes{
2321556Srgrimes
23349884Ssheldonh	if (op && *op)
23486618Sknu		error("%s: %s", op, msg);
23549884Ssheldonh	else
23686618Sknu		error("%s", msg);
2371556Srgrimes}
2381556Srgrimes
23949884Ssheldonhstatic int
24049884Ssheldonhoexpr(n)
24149884Ssheldonh	enum token n;
2421556Srgrimes{
24349884Ssheldonh	int res;
2441556Srgrimes
24549884Ssheldonh	res = aexpr(n);
24649884Ssheldonh	if (t_lex(*++t_wp) == BOR)
24749884Ssheldonh		return oexpr(t_lex(*++t_wp)) || res;
24849884Ssheldonh	t_wp--;
24949884Ssheldonh	return res;
25049884Ssheldonh}
2514171Sache
25249884Ssheldonhstatic int
25349884Ssheldonhaexpr(n)
25449884Ssheldonh	enum token n;
25549884Ssheldonh{
25649884Ssheldonh	int res;
2571556Srgrimes
25849884Ssheldonh	res = nexpr(n);
25949884Ssheldonh	if (t_lex(*++t_wp) == BAND)
26049884Ssheldonh		return aexpr(t_lex(*++t_wp)) && res;
26149884Ssheldonh	t_wp--;
26249884Ssheldonh	return res;
2631556Srgrimes}
2641556Srgrimes
2651556Srgrimesstatic int
26649884Ssheldonhnexpr(n)
26749884Ssheldonh	enum token n;			/* token */
2681556Srgrimes{
26949884Ssheldonh	if (n == UNOT)
27049884Ssheldonh		return !nexpr(t_lex(*++t_wp));
27149884Ssheldonh	return primary(n);
2721556Srgrimes}
2731556Srgrimes
2741556Srgrimesstatic int
27549884Ssheldonhprimary(n)
27649884Ssheldonh	enum token n;
2771556Srgrimes{
27849884Ssheldonh	enum token nn;
27949884Ssheldonh	int res;
2801556Srgrimes
28149884Ssheldonh	if (n == EOI)
28249884Ssheldonh		return 0;		/* missing expression */
28349884Ssheldonh	if (n == LPAREN) {
28449884Ssheldonh		if ((nn = t_lex(*++t_wp)) == RPAREN)
28549884Ssheldonh			return 0;	/* missing expression */
28649884Ssheldonh		res = oexpr(nn);
28749884Ssheldonh		if (t_lex(*++t_wp) != RPAREN)
28849884Ssheldonh			syntax(NULL, "closing paren expected");
28949884Ssheldonh		return res;
29049884Ssheldonh	}
29149884Ssheldonh	if (t_wp_op && t_wp_op->op_type == UNOP) {
29249884Ssheldonh		/* unary expression */
29349884Ssheldonh		if (*++t_wp == NULL)
29449884Ssheldonh			syntax(t_wp_op->op_text, "argument expected");
29549884Ssheldonh		switch (n) {
29649884Ssheldonh		case STREZ:
29749884Ssheldonh			return strlen(*t_wp) == 0;
29849884Ssheldonh		case STRNZ:
29949884Ssheldonh			return strlen(*t_wp) != 0;
30049884Ssheldonh		case FILTT:
30149884Ssheldonh			return isatty(getn(*t_wp));
30249884Ssheldonh		default:
30349884Ssheldonh			return filstat(*t_wp, n);
30449884Ssheldonh		}
30549884Ssheldonh	}
3061556Srgrimes
30749884Ssheldonh	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
30849884Ssheldonh		return binop();
30949884Ssheldonh	}
31049884Ssheldonh
31149884Ssheldonh	return strlen(*t_wp) > 0;
3121556Srgrimes}
3131556Srgrimes
3141556Srgrimesstatic int
31549884Ssheldonhbinop()
3161556Srgrimes{
31749884Ssheldonh	const char *opnd1, *opnd2;
31849884Ssheldonh	struct t_op const *op;
3191556Srgrimes
32049884Ssheldonh	opnd1 = *t_wp;
32149884Ssheldonh	(void) t_lex(*++t_wp);
32249884Ssheldonh	op = t_wp_op;
3231556Srgrimes
32449884Ssheldonh	if ((opnd2 = *++t_wp) == NULL)
32549884Ssheldonh		syntax(op->op_text, "argument expected");
32649884Ssheldonh
32749884Ssheldonh	switch (op->op_num) {
32849884Ssheldonh	case STREQ:
32949884Ssheldonh		return strcmp(opnd1, opnd2) == 0;
33049884Ssheldonh	case STRNE:
33149884Ssheldonh		return strcmp(opnd1, opnd2) != 0;
33249884Ssheldonh	case STRLT:
33349884Ssheldonh		return strcmp(opnd1, opnd2) < 0;
33449884Ssheldonh	case STRGT:
33549884Ssheldonh		return strcmp(opnd1, opnd2) > 0;
33649884Ssheldonh	case INTEQ:
33762925Sse		return intcmp(opnd1, opnd2) == 0;
33849884Ssheldonh	case INTNE:
33962925Sse		return intcmp(opnd1, opnd2) != 0;
34049884Ssheldonh	case INTGE:
34162925Sse		return intcmp(opnd1, opnd2) >= 0;
34249884Ssheldonh	case INTGT:
34362925Sse		return intcmp(opnd1, opnd2) > 0;
34449884Ssheldonh	case INTLE:
34562925Sse		return intcmp(opnd1, opnd2) <= 0;
34649884Ssheldonh	case INTLT:
34762925Sse		return intcmp(opnd1, opnd2) < 0;
34849884Ssheldonh	case FILNT:
34949884Ssheldonh		return newerf (opnd1, opnd2);
35049884Ssheldonh	case FILOT:
35149884Ssheldonh		return olderf (opnd1, opnd2);
35249884Ssheldonh	case FILEQ:
35349884Ssheldonh		return equalf (opnd1, opnd2);
35449884Ssheldonh	default:
35549884Ssheldonh		abort();
35649884Ssheldonh		/* NOTREACHED */
3571556Srgrimes	}
3581556Srgrimes}
3591556Srgrimes
36049884Ssheldonhstatic int
36149884Ssheldonhfilstat(nm, mode)
36249884Ssheldonh	char *nm;
36349884Ssheldonh	enum token mode;
3641556Srgrimes{
36549884Ssheldonh	struct stat s;
3661556Srgrimes
36749884Ssheldonh	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
36849884Ssheldonh		return 0;
3692664Scsgr
37049884Ssheldonh	switch (mode) {
37149884Ssheldonh	case FILRD:
37249884Ssheldonh		return access(nm, R_OK) == 0;
37349884Ssheldonh	case FILWR:
37449884Ssheldonh		return access(nm, W_OK) == 0;
37549884Ssheldonh	case FILEX:
37650302Sgreen		/* XXX work around access(2) false positives for superuser */
37750087Sgreen		if (access(nm, X_OK) != 0)
37850087Sgreen			return 0;
37950087Sgreen		if (S_ISDIR(s.st_mode) || getuid() != 0)
38050087Sgreen			return 1;
38150087Sgreen		return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
38249884Ssheldonh	case FILEXIST:
38349884Ssheldonh		return access(nm, F_OK) == 0;
38449884Ssheldonh	case FILREG:
38549884Ssheldonh		return S_ISREG(s.st_mode);
38649884Ssheldonh	case FILDIR:
38749884Ssheldonh		return S_ISDIR(s.st_mode);
38849884Ssheldonh	case FILCDEV:
38949884Ssheldonh		return S_ISCHR(s.st_mode);
39049884Ssheldonh	case FILBDEV:
39149884Ssheldonh		return S_ISBLK(s.st_mode);
39249884Ssheldonh	case FILFIFO:
39349884Ssheldonh		return S_ISFIFO(s.st_mode);
39449884Ssheldonh	case FILSOCK:
39549884Ssheldonh		return S_ISSOCK(s.st_mode);
39649884Ssheldonh	case FILSYM:
39749884Ssheldonh		return S_ISLNK(s.st_mode);
39849884Ssheldonh	case FILSUID:
39949884Ssheldonh		return (s.st_mode & S_ISUID) != 0;
40049884Ssheldonh	case FILSGID:
40149884Ssheldonh		return (s.st_mode & S_ISGID) != 0;
40249884Ssheldonh	case FILSTCK:
40349884Ssheldonh		return (s.st_mode & S_ISVTX) != 0;
40449884Ssheldonh	case FILGZ:
40549884Ssheldonh		return s.st_size > (off_t)0;
40649884Ssheldonh	case FILUID:
40749884Ssheldonh		return s.st_uid == geteuid();
40849884Ssheldonh	case FILGID:
40949884Ssheldonh		return s.st_gid == getegid();
41049884Ssheldonh	default:
41149884Ssheldonh		return 1;
4122675Scsgr	}
41349884Ssheldonh}
4142675Scsgr
41549884Ssheldonhstatic enum token
41649884Ssheldonht_lex(s)
41749884Ssheldonh	char *s;
41849884Ssheldonh{
41949884Ssheldonh	struct t_op const *op = ops;
42049884Ssheldonh
42149884Ssheldonh	if (s == 0) {
42249884Ssheldonh		t_wp_op = NULL;
42349884Ssheldonh		return EOI;
42449884Ssheldonh	}
42549884Ssheldonh	while (op->op_text) {
42649884Ssheldonh		if (strcmp(s, op->op_text) == 0) {
42749884Ssheldonh			if ((op->op_type == UNOP && isoperand()) ||
42849884Ssheldonh			    (op->op_num == LPAREN && *(t_wp+1) == 0))
42949884Ssheldonh				break;
43049884Ssheldonh			t_wp_op = op;
43149884Ssheldonh			return op->op_num;
4321556Srgrimes		}
43349884Ssheldonh		op++;
4341556Srgrimes	}
43549884Ssheldonh	t_wp_op = NULL;
43649884Ssheldonh	return OPERAND;
4371556Srgrimes}
4381556Srgrimes
43949884Ssheldonhstatic int
44049884Ssheldonhisoperand()
4411556Srgrimes{
44249884Ssheldonh	struct t_op const *op = ops;
44349884Ssheldonh	char *s;
44449884Ssheldonh	char *t;
4451556Srgrimes
44649884Ssheldonh	if ((s  = *(t_wp+1)) == 0)
44749884Ssheldonh		return 1;
44849884Ssheldonh	if ((t = *(t_wp+2)) == 0)
44949884Ssheldonh		return 0;
45049884Ssheldonh	while (op->op_text) {
45149884Ssheldonh		if (strcmp(s, op->op_text) == 0)
45249884Ssheldonh			return op->op_type == BINOP &&
45349884Ssheldonh			    (t[0] != ')' || t[1] != '\0');
45449884Ssheldonh		op++;
45549884Ssheldonh	}
45649884Ssheldonh	return 0;
4571556Srgrimes}
4581556Srgrimes
45949884Ssheldonh/* atoi with error detection */
46049884Ssheldonhstatic int
46149884Ssheldonhgetn(s)
46249884Ssheldonh	const char *s;
4631556Srgrimes{
46449884Ssheldonh	char *p;
46549884Ssheldonh	long r;
4661556Srgrimes
46749884Ssheldonh	errno = 0;
46849884Ssheldonh	r = strtol(s, &p, 10);
46949884Ssheldonh
47049884Ssheldonh	if (errno != 0)
47186618Sknu	  error("%s: out of range", s);
47249884Ssheldonh
47349884Ssheldonh	while (isspace((unsigned char)*p))
47449884Ssheldonh	  p++;
47549884Ssheldonh
47649884Ssheldonh	if (*p)
47786618Sknu	  error("%s: bad number", s);
47849884Ssheldonh
47949884Ssheldonh	return (int) r;
4801556Srgrimes}
48149884Ssheldonh
48262925Sse/* atoi with error detection and 64 bit range */
48362925Ssestatic quad_t
48462925Ssegetq(s)
48562925Sse	const char *s;
48662925Sse{
48762925Sse	char *p;
48862925Sse	quad_t r;
48962925Sse
49062925Sse	errno = 0;
49162925Sse	r = strtoq(s, &p, 10);
49262925Sse
49362925Sse	if (errno != 0)
49486618Sknu	  error("%s: out of range", s);
49562925Sse
49662925Sse	while (isspace((unsigned char)*p))
49762925Sse	  p++;
49862925Sse
49962925Sse	if (*p)
50086618Sknu	  error("%s: bad number", s);
50162925Sse
50262925Sse	return r;
50362925Sse}
50462925Sse
50549884Ssheldonhstatic int
50662925Sseintcmp (s1, s2)
50762925Sse	const char *s1, *s2;
50862925Sse{
50962925Sse	quad_t q1, q2;
51062925Sse
51162925Sse
51262925Sse	q1 = getq(s1);
51362925Sse	q2 = getq(s2);
51462925Sse
51562925Sse	if (q1 > q2)
51662925Sse		return 1;
51762925Sse
51862925Sse	if (q1 < q2)
51962925Sse		return -1;
52062925Sse
52162925Sse	return 0;
52262925Sse}
52362925Sse
52462925Ssestatic int
52549884Ssheldonhnewerf (f1, f2)
52649884Ssheldonh	const char *f1, *f2;
52749884Ssheldonh{
52849884Ssheldonh	struct stat b1, b2;
52949884Ssheldonh
53049884Ssheldonh	return (stat (f1, &b1) == 0 &&
53149884Ssheldonh		stat (f2, &b2) == 0 &&
53249884Ssheldonh		b1.st_mtime > b2.st_mtime);
53349884Ssheldonh}
53449884Ssheldonh
53549884Ssheldonhstatic int
53649884Ssheldonholderf (f1, f2)
53749884Ssheldonh	const char *f1, *f2;
53849884Ssheldonh{
53949884Ssheldonh	struct stat b1, b2;
54049884Ssheldonh
54149884Ssheldonh	return (stat (f1, &b1) == 0 &&
54249884Ssheldonh		stat (f2, &b2) == 0 &&
54349884Ssheldonh		b1.st_mtime < b2.st_mtime);
54449884Ssheldonh}
54549884Ssheldonh
54649884Ssheldonhstatic int
54749884Ssheldonhequalf (f1, f2)
54849884Ssheldonh	const char *f1, *f2;
54949884Ssheldonh{
55049884Ssheldonh	struct stat b1, b2;
55149884Ssheldonh
55249884Ssheldonh	return (stat (f1, &b1) == 0 &&
55349884Ssheldonh		stat (f2, &b2) == 0 &&
55449884Ssheldonh		b1.st_dev == b2.st_dev &&
55549884Ssheldonh		b1.st_ino == b2.st_ino);
55649884Ssheldonh}
557