test.c revision 88471
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 88471 2001-12-25 08:10:34Z ache $"; 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> 2586619Sknu#include <stdarg.h> 261556Srgrimes#include <stdio.h> 271556Srgrimes#include <stdlib.h> 281556Srgrimes#include <string.h> 291556Srgrimes#include <unistd.h> 301556Srgrimes 3186505Sknu#ifdef SHELL 3286505Sknu#define main testcmd 3386505Sknu#include "bltin/bltin.h" 3486618Sknu#else 3588084Sache#include <locale.h> 3688084Sache 3786618Sknustatic void error(const char *, ...) __attribute__((__noreturn__)); 3886618Sknu 3986618Sknustatic void 4086618Sknu#ifdef __STDC__ 4186618Sknuerror(const char *msg, ...) 4286618Sknu#else 4386618Sknuerror(va_alist) 4486618Sknu va_dcl 4586505Sknu#endif 4686618Sknu{ 4786618Sknu va_list ap; 4886618Sknu#ifndef __STDC__ 4986618Sknu const char *msg; 5086505Sknu 5186618Sknu va_start(ap); 5286618Sknu msg = va_arg(ap, const char *); 5386618Sknu#else 5486618Sknu va_start(ap, msg); 5586618Sknu#endif 5686618Sknu verrx(2, msg, ap); 5786618Sknu /*NOTREACHED*/ 5886618Sknu va_end(ap); 5986618Sknu} 6086618Sknu#endif 6186618Sknu 6249884Ssheldonh/* test(1) accepts the following grammar: 6349884Ssheldonh oexpr ::= aexpr | aexpr "-o" oexpr ; 6449884Ssheldonh aexpr ::= nexpr | nexpr "-a" aexpr ; 6549884Ssheldonh nexpr ::= primary | "!" primary 6649884Ssheldonh primary ::= unary-operator operand 6749884Ssheldonh | operand binary-operator operand 6849884Ssheldonh | operand 6949884Ssheldonh | "(" oexpr ")" 7049884Ssheldonh ; 7149884Ssheldonh unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| 7249884Ssheldonh "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; 731556Srgrimes 7449884Ssheldonh binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| 7549884Ssheldonh "-nt"|"-ot"|"-ef"; 7649884Ssheldonh operand ::= <any legal UNIX file name> 7749884Ssheldonh*/ 781556Srgrimes 7949884Ssheldonhenum token { 8049884Ssheldonh EOI, 8149884Ssheldonh FILRD, 8249884Ssheldonh FILWR, 8349884Ssheldonh FILEX, 8449884Ssheldonh FILEXIST, 8549884Ssheldonh FILREG, 8649884Ssheldonh FILDIR, 8749884Ssheldonh FILCDEV, 8849884Ssheldonh FILBDEV, 8949884Ssheldonh FILFIFO, 9049884Ssheldonh FILSOCK, 9149884Ssheldonh FILSYM, 9249884Ssheldonh FILGZ, 9349884Ssheldonh FILTT, 9449884Ssheldonh FILSUID, 9549884Ssheldonh FILSGID, 9649884Ssheldonh FILSTCK, 9749884Ssheldonh FILNT, 9849884Ssheldonh FILOT, 9949884Ssheldonh FILEQ, 10049884Ssheldonh FILUID, 10149884Ssheldonh FILGID, 10249884Ssheldonh STREZ, 10349884Ssheldonh STRNZ, 10449884Ssheldonh STREQ, 10549884Ssheldonh STRNE, 10649884Ssheldonh STRLT, 10749884Ssheldonh STRGT, 10849884Ssheldonh INTEQ, 10949884Ssheldonh INTNE, 11049884Ssheldonh INTGE, 11149884Ssheldonh INTGT, 11249884Ssheldonh INTLE, 11349884Ssheldonh INTLT, 11449884Ssheldonh UNOT, 11549884Ssheldonh BAND, 11649884Ssheldonh BOR, 11749884Ssheldonh LPAREN, 11849884Ssheldonh RPAREN, 11949884Ssheldonh OPERAND 1201556Srgrimes}; 1211556Srgrimes 12249884Ssheldonhenum token_types { 12349884Ssheldonh UNOP, 12449884Ssheldonh BINOP, 12549884Ssheldonh BUNOP, 12649884Ssheldonh BBINOP, 12749884Ssheldonh PAREN 1281556Srgrimes}; 1291556Srgrimes 13049884Ssheldonhstruct t_op { 13149884Ssheldonh const char *op_text; 13249884Ssheldonh short op_num, op_type; 13349884Ssheldonh} const ops [] = { 13449884Ssheldonh {"-r", FILRD, UNOP}, 13549884Ssheldonh {"-w", FILWR, UNOP}, 13649884Ssheldonh {"-x", FILEX, UNOP}, 13749884Ssheldonh {"-e", FILEXIST,UNOP}, 13849884Ssheldonh {"-f", FILREG, UNOP}, 13949884Ssheldonh {"-d", FILDIR, UNOP}, 14049884Ssheldonh {"-c", FILCDEV,UNOP}, 14149884Ssheldonh {"-b", FILBDEV,UNOP}, 14249884Ssheldonh {"-p", FILFIFO,UNOP}, 14349884Ssheldonh {"-u", FILSUID,UNOP}, 14449884Ssheldonh {"-g", FILSGID,UNOP}, 14549884Ssheldonh {"-k", FILSTCK,UNOP}, 14649884Ssheldonh {"-s", FILGZ, UNOP}, 14749884Ssheldonh {"-t", FILTT, UNOP}, 14849884Ssheldonh {"-z", STREZ, UNOP}, 14949884Ssheldonh {"-n", STRNZ, UNOP}, 15049884Ssheldonh {"-h", FILSYM, UNOP}, /* for backwards compat */ 15149884Ssheldonh {"-O", FILUID, UNOP}, 15249884Ssheldonh {"-G", FILGID, UNOP}, 15349884Ssheldonh {"-L", FILSYM, UNOP}, 15449884Ssheldonh {"-S", FILSOCK,UNOP}, 15549884Ssheldonh {"=", STREQ, BINOP}, 15649884Ssheldonh {"!=", STRNE, BINOP}, 15749884Ssheldonh {"<", STRLT, BINOP}, 15849884Ssheldonh {">", STRGT, BINOP}, 15949884Ssheldonh {"-eq", INTEQ, BINOP}, 16049884Ssheldonh {"-ne", INTNE, BINOP}, 16149884Ssheldonh {"-ge", INTGE, BINOP}, 16249884Ssheldonh {"-gt", INTGT, BINOP}, 16349884Ssheldonh {"-le", INTLE, BINOP}, 16449884Ssheldonh {"-lt", INTLT, BINOP}, 16549884Ssheldonh {"-nt", FILNT, BINOP}, 16649884Ssheldonh {"-ot", FILOT, BINOP}, 16749884Ssheldonh {"-ef", FILEQ, BINOP}, 16849884Ssheldonh {"!", UNOT, BUNOP}, 16949884Ssheldonh {"-a", BAND, BBINOP}, 17049884Ssheldonh {"-o", BOR, BBINOP}, 17149884Ssheldonh {"(", LPAREN, PAREN}, 17249884Ssheldonh {")", RPAREN, PAREN}, 17349884Ssheldonh {0, 0, 0} 1741556Srgrimes}; 1751556Srgrimes 17649884Ssheldonhstruct t_op const *t_wp_op; 17749884Ssheldonhchar **t_wp; 1781556Srgrimes 17976883Skrisstatic int aexpr __P((enum token)); 18076883Skrisstatic int binop __P((void)); 18176883Skrisstatic int equalf __P((const char *, const char *)); 18276883Skrisstatic int filstat __P((char *, enum token)); 18376883Skrisstatic int getn __P((const char *)); 18488471Sachestatic long long getq __P((const char *)); 18576883Skrisstatic int intcmp __P((const char *, const char *)); 18676883Skrisstatic int isoperand __P((void)); 18776883Skrisint main __P((int, char **)); 18876883Skrisstatic int newerf __P((const char *, const char *)); 18976883Skrisstatic int nexpr __P((enum token)); 19076883Skrisstatic int oexpr __P((enum token)); 19176883Skrisstatic int olderf __P((const char *, const char *)); 19276883Skrisstatic int primary __P((enum token)); 19376883Skrisstatic void syntax __P((const char *, const char *)); 19476883Skrisstatic enum token t_lex __P((char *)); 19549884Ssheldonh 1961556Srgrimesint 1971556Srgrimesmain(argc, argv) 1981556Srgrimes int argc; 19949884Ssheldonh char **argv; 2001556Srgrimes{ 20149884Ssheldonh int res; 20255179Ssheldonh char *p; 2031556Srgrimes 20455179Ssheldonh if ((p = rindex(argv[0], '/')) == NULL) 20555179Ssheldonh p = argv[0]; 20655179Ssheldonh else 20755179Ssheldonh p++; 20855179Ssheldonh if (strcmp(p, "[") == 0) { 20986622Sknu if (strcmp(argv[--argc], "]") != 0) 21086618Sknu error("missing ]"); 2111556Srgrimes argv[argc] = NULL; 2121556Srgrimes } 2131556Srgrimes 21486622Sknu /* no expression => false */ 21586622Sknu if (--argc <= 0) 21686622Sknu return 1; 21786622Sknu 21888084Sache#ifndef SHELL 21988084Sache (void)setlocale(LC_CTYPE, ""); 22088084Sache#endif 22150302Sgreen /* XXX work around the absence of an eaccess(2) syscall */ 22250087Sgreen (void)setgid(getegid()); 22350087Sgreen (void)setuid(geteuid()); 22450087Sgreen 22549884Ssheldonh t_wp = &argv[1]; 22649884Ssheldonh res = !oexpr(t_lex(*t_wp)); 2271556Srgrimes 22849884Ssheldonh if (*t_wp != NULL && *++t_wp != NULL) 22949884Ssheldonh syntax(*t_wp, "unexpected operator"); 23049884Ssheldonh 23149884Ssheldonh return res; 2321556Srgrimes} 2331556Srgrimes 23449884Ssheldonhstatic void 23549884Ssheldonhsyntax(op, msg) 23649884Ssheldonh const char *op; 23749884Ssheldonh const char *msg; 2381556Srgrimes{ 2391556Srgrimes 24049884Ssheldonh if (op && *op) 24186618Sknu error("%s: %s", op, msg); 24249884Ssheldonh else 24386618Sknu error("%s", msg); 2441556Srgrimes} 2451556Srgrimes 24649884Ssheldonhstatic int 24749884Ssheldonhoexpr(n) 24849884Ssheldonh enum token n; 2491556Srgrimes{ 25049884Ssheldonh int res; 2511556Srgrimes 25249884Ssheldonh res = aexpr(n); 25349884Ssheldonh if (t_lex(*++t_wp) == BOR) 25449884Ssheldonh return oexpr(t_lex(*++t_wp)) || res; 25549884Ssheldonh t_wp--; 25649884Ssheldonh return res; 25749884Ssheldonh} 2584171Sache 25949884Ssheldonhstatic int 26049884Ssheldonhaexpr(n) 26149884Ssheldonh enum token n; 26249884Ssheldonh{ 26349884Ssheldonh int res; 2641556Srgrimes 26549884Ssheldonh res = nexpr(n); 26649884Ssheldonh if (t_lex(*++t_wp) == BAND) 26749884Ssheldonh return aexpr(t_lex(*++t_wp)) && res; 26849884Ssheldonh t_wp--; 26949884Ssheldonh return res; 2701556Srgrimes} 2711556Srgrimes 2721556Srgrimesstatic int 27349884Ssheldonhnexpr(n) 27449884Ssheldonh enum token n; /* token */ 2751556Srgrimes{ 27649884Ssheldonh if (n == UNOT) 27749884Ssheldonh return !nexpr(t_lex(*++t_wp)); 27849884Ssheldonh return primary(n); 2791556Srgrimes} 2801556Srgrimes 2811556Srgrimesstatic int 28249884Ssheldonhprimary(n) 28349884Ssheldonh enum token n; 2841556Srgrimes{ 28549884Ssheldonh enum token nn; 28649884Ssheldonh int res; 2871556Srgrimes 28849884Ssheldonh if (n == EOI) 28949884Ssheldonh return 0; /* missing expression */ 29049884Ssheldonh if (n == LPAREN) { 29149884Ssheldonh if ((nn = t_lex(*++t_wp)) == RPAREN) 29249884Ssheldonh return 0; /* missing expression */ 29349884Ssheldonh res = oexpr(nn); 29449884Ssheldonh if (t_lex(*++t_wp) != RPAREN) 29549884Ssheldonh syntax(NULL, "closing paren expected"); 29649884Ssheldonh return res; 29749884Ssheldonh } 29849884Ssheldonh if (t_wp_op && t_wp_op->op_type == UNOP) { 29949884Ssheldonh /* unary expression */ 30049884Ssheldonh if (*++t_wp == NULL) 30149884Ssheldonh syntax(t_wp_op->op_text, "argument expected"); 30249884Ssheldonh switch (n) { 30349884Ssheldonh case STREZ: 30449884Ssheldonh return strlen(*t_wp) == 0; 30549884Ssheldonh case STRNZ: 30649884Ssheldonh return strlen(*t_wp) != 0; 30749884Ssheldonh case FILTT: 30849884Ssheldonh return isatty(getn(*t_wp)); 30949884Ssheldonh default: 31049884Ssheldonh return filstat(*t_wp, n); 31149884Ssheldonh } 31249884Ssheldonh } 3131556Srgrimes 31449884Ssheldonh if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { 31549884Ssheldonh return binop(); 31649884Ssheldonh } 31749884Ssheldonh 31849884Ssheldonh return strlen(*t_wp) > 0; 3191556Srgrimes} 3201556Srgrimes 3211556Srgrimesstatic int 32249884Ssheldonhbinop() 3231556Srgrimes{ 32449884Ssheldonh const char *opnd1, *opnd2; 32549884Ssheldonh struct t_op const *op; 3261556Srgrimes 32749884Ssheldonh opnd1 = *t_wp; 32849884Ssheldonh (void) t_lex(*++t_wp); 32949884Ssheldonh op = t_wp_op; 3301556Srgrimes 33149884Ssheldonh if ((opnd2 = *++t_wp) == NULL) 33249884Ssheldonh syntax(op->op_text, "argument expected"); 33349884Ssheldonh 33449884Ssheldonh switch (op->op_num) { 33549884Ssheldonh case STREQ: 33649884Ssheldonh return strcmp(opnd1, opnd2) == 0; 33749884Ssheldonh case STRNE: 33849884Ssheldonh return strcmp(opnd1, opnd2) != 0; 33949884Ssheldonh case STRLT: 34049884Ssheldonh return strcmp(opnd1, opnd2) < 0; 34149884Ssheldonh case STRGT: 34249884Ssheldonh return strcmp(opnd1, opnd2) > 0; 34349884Ssheldonh case INTEQ: 34462925Sse return intcmp(opnd1, opnd2) == 0; 34549884Ssheldonh case INTNE: 34662925Sse return intcmp(opnd1, opnd2) != 0; 34749884Ssheldonh case INTGE: 34862925Sse return intcmp(opnd1, opnd2) >= 0; 34949884Ssheldonh case INTGT: 35062925Sse return intcmp(opnd1, opnd2) > 0; 35149884Ssheldonh case INTLE: 35262925Sse return intcmp(opnd1, opnd2) <= 0; 35349884Ssheldonh case INTLT: 35462925Sse return intcmp(opnd1, opnd2) < 0; 35549884Ssheldonh case FILNT: 35649884Ssheldonh return newerf (opnd1, opnd2); 35749884Ssheldonh case FILOT: 35849884Ssheldonh return olderf (opnd1, opnd2); 35949884Ssheldonh case FILEQ: 36049884Ssheldonh return equalf (opnd1, opnd2); 36149884Ssheldonh default: 36249884Ssheldonh abort(); 36349884Ssheldonh /* NOTREACHED */ 3641556Srgrimes } 3651556Srgrimes} 3661556Srgrimes 36749884Ssheldonhstatic int 36849884Ssheldonhfilstat(nm, mode) 36949884Ssheldonh char *nm; 37049884Ssheldonh enum token mode; 3711556Srgrimes{ 37249884Ssheldonh struct stat s; 3731556Srgrimes 37449884Ssheldonh if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s)) 37549884Ssheldonh return 0; 3762664Scsgr 37749884Ssheldonh switch (mode) { 37849884Ssheldonh case FILRD: 37949884Ssheldonh return access(nm, R_OK) == 0; 38049884Ssheldonh case FILWR: 38149884Ssheldonh return access(nm, W_OK) == 0; 38249884Ssheldonh case FILEX: 38350302Sgreen /* XXX work around access(2) false positives for superuser */ 38450087Sgreen if (access(nm, X_OK) != 0) 38550087Sgreen return 0; 38650087Sgreen if (S_ISDIR(s.st_mode) || getuid() != 0) 38750087Sgreen return 1; 38850087Sgreen return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; 38949884Ssheldonh case FILEXIST: 39049884Ssheldonh return access(nm, F_OK) == 0; 39149884Ssheldonh case FILREG: 39249884Ssheldonh return S_ISREG(s.st_mode); 39349884Ssheldonh case FILDIR: 39449884Ssheldonh return S_ISDIR(s.st_mode); 39549884Ssheldonh case FILCDEV: 39649884Ssheldonh return S_ISCHR(s.st_mode); 39749884Ssheldonh case FILBDEV: 39849884Ssheldonh return S_ISBLK(s.st_mode); 39949884Ssheldonh case FILFIFO: 40049884Ssheldonh return S_ISFIFO(s.st_mode); 40149884Ssheldonh case FILSOCK: 40249884Ssheldonh return S_ISSOCK(s.st_mode); 40349884Ssheldonh case FILSYM: 40449884Ssheldonh return S_ISLNK(s.st_mode); 40549884Ssheldonh case FILSUID: 40649884Ssheldonh return (s.st_mode & S_ISUID) != 0; 40749884Ssheldonh case FILSGID: 40849884Ssheldonh return (s.st_mode & S_ISGID) != 0; 40949884Ssheldonh case FILSTCK: 41049884Ssheldonh return (s.st_mode & S_ISVTX) != 0; 41149884Ssheldonh case FILGZ: 41249884Ssheldonh return s.st_size > (off_t)0; 41349884Ssheldonh case FILUID: 41449884Ssheldonh return s.st_uid == geteuid(); 41549884Ssheldonh case FILGID: 41649884Ssheldonh return s.st_gid == getegid(); 41749884Ssheldonh default: 41849884Ssheldonh return 1; 4192675Scsgr } 42049884Ssheldonh} 4212675Scsgr 42249884Ssheldonhstatic enum token 42349884Ssheldonht_lex(s) 42449884Ssheldonh char *s; 42549884Ssheldonh{ 42649884Ssheldonh struct t_op const *op = ops; 42749884Ssheldonh 42849884Ssheldonh if (s == 0) { 42949884Ssheldonh t_wp_op = NULL; 43049884Ssheldonh return EOI; 43149884Ssheldonh } 43249884Ssheldonh while (op->op_text) { 43349884Ssheldonh if (strcmp(s, op->op_text) == 0) { 43449884Ssheldonh if ((op->op_type == UNOP && isoperand()) || 43549884Ssheldonh (op->op_num == LPAREN && *(t_wp+1) == 0)) 43649884Ssheldonh break; 43749884Ssheldonh t_wp_op = op; 43849884Ssheldonh return op->op_num; 4391556Srgrimes } 44049884Ssheldonh op++; 4411556Srgrimes } 44249884Ssheldonh t_wp_op = NULL; 44349884Ssheldonh return OPERAND; 4441556Srgrimes} 4451556Srgrimes 44649884Ssheldonhstatic int 44749884Ssheldonhisoperand() 4481556Srgrimes{ 44949884Ssheldonh struct t_op const *op = ops; 45049884Ssheldonh char *s; 45149884Ssheldonh char *t; 4521556Srgrimes 45349884Ssheldonh if ((s = *(t_wp+1)) == 0) 45449884Ssheldonh return 1; 45549884Ssheldonh if ((t = *(t_wp+2)) == 0) 45649884Ssheldonh return 0; 45749884Ssheldonh while (op->op_text) { 45849884Ssheldonh if (strcmp(s, op->op_text) == 0) 45949884Ssheldonh return op->op_type == BINOP && 46049884Ssheldonh (t[0] != ')' || t[1] != '\0'); 46149884Ssheldonh op++; 46249884Ssheldonh } 46349884Ssheldonh return 0; 4641556Srgrimes} 4651556Srgrimes 46649884Ssheldonh/* atoi with error detection */ 46749884Ssheldonhstatic int 46849884Ssheldonhgetn(s) 46949884Ssheldonh const char *s; 4701556Srgrimes{ 47149884Ssheldonh char *p; 47249884Ssheldonh long r; 4731556Srgrimes 47449884Ssheldonh errno = 0; 47549884Ssheldonh r = strtol(s, &p, 10); 47649884Ssheldonh 47788084Sache if (s == p) 47888084Sache error("%s: bad number", s); 47988084Sache 48049884Ssheldonh if (errno != 0) 48187961Sache error((errno == EINVAL) ? "%s: bad number" : 48287961Sache "%s: out of range", s); 48349884Ssheldonh 48449884Ssheldonh while (isspace((unsigned char)*p)) 48586622Sknu p++; 48649884Ssheldonh 48749884Ssheldonh if (*p) 48886622Sknu error("%s: bad number", s); 48949884Ssheldonh 49049884Ssheldonh return (int) r; 4911556Srgrimes} 49249884Ssheldonh 49362925Sse/* atoi with error detection and 64 bit range */ 49488471Sachestatic long long 49562925Ssegetq(s) 49662925Sse const char *s; 49762925Sse{ 49862925Sse char *p; 49988471Sache long long r; 50062925Sse 50162925Sse errno = 0; 50288471Sache r = strtoll(s, &p, 10); 50362925Sse 50488084Sache if (s == p) 50588084Sache error("%s: bad number", s); 50688084Sache 50762925Sse if (errno != 0) 50887961Sache error((errno == EINVAL) ? "%s: bad number" : 50987961Sache "%s: out of range", s); 51062925Sse 51162925Sse while (isspace((unsigned char)*p)) 51286622Sknu p++; 51362925Sse 51462925Sse if (*p) 51586622Sknu error("%s: bad number", s); 51662925Sse 51762925Sse return r; 51862925Sse} 51962925Sse 52049884Ssheldonhstatic int 52162925Sseintcmp (s1, s2) 52262925Sse const char *s1, *s2; 52362925Sse{ 52488471Sache long long q1, q2; 52562925Sse 52662925Sse 52762925Sse q1 = getq(s1); 52862925Sse q2 = getq(s2); 52962925Sse 53062925Sse if (q1 > q2) 53162925Sse return 1; 53262925Sse 53362925Sse if (q1 < q2) 53462925Sse return -1; 53562925Sse 53662925Sse return 0; 53762925Sse} 53862925Sse 53962925Ssestatic int 54049884Ssheldonhnewerf (f1, f2) 54149884Ssheldonh const char *f1, *f2; 54249884Ssheldonh{ 54349884Ssheldonh struct stat b1, b2; 54449884Ssheldonh 54549884Ssheldonh return (stat (f1, &b1) == 0 && 54649884Ssheldonh stat (f2, &b2) == 0 && 54749884Ssheldonh b1.st_mtime > b2.st_mtime); 54849884Ssheldonh} 54949884Ssheldonh 55049884Ssheldonhstatic int 55149884Ssheldonholderf (f1, f2) 55249884Ssheldonh const char *f1, *f2; 55349884Ssheldonh{ 55449884Ssheldonh struct stat b1, b2; 55549884Ssheldonh 55649884Ssheldonh return (stat (f1, &b1) == 0 && 55749884Ssheldonh stat (f2, &b2) == 0 && 55849884Ssheldonh b1.st_mtime < b2.st_mtime); 55949884Ssheldonh} 56049884Ssheldonh 56149884Ssheldonhstatic int 56249884Ssheldonhequalf (f1, f2) 56349884Ssheldonh const char *f1, *f2; 56449884Ssheldonh{ 56549884Ssheldonh struct stat b1, b2; 56649884Ssheldonh 56749884Ssheldonh return (stat (f1, &b1) == 0 && 56849884Ssheldonh stat (f2, &b2) == 0 && 56949884Ssheldonh b1.st_dev == b2.st_dev && 57049884Ssheldonh b1.st_ino == b2.st_ino); 57149884Ssheldonh} 572