test.c revision 90111
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 90111 2002-02-02 06:50:57Z imp $"; 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 4086618Sknuerror(const char *msg, ...) 4186618Sknu{ 4286618Sknu va_list ap; 4386618Sknu va_start(ap, msg); 4486618Sknu verrx(2, msg, ap); 4586618Sknu /*NOTREACHED*/ 4686618Sknu va_end(ap); 4786618Sknu} 4886618Sknu#endif 4986618Sknu 5049884Ssheldonh/* test(1) accepts the following grammar: 5149884Ssheldonh oexpr ::= aexpr | aexpr "-o" oexpr ; 5249884Ssheldonh aexpr ::= nexpr | nexpr "-a" aexpr ; 5349884Ssheldonh nexpr ::= primary | "!" primary 5449884Ssheldonh primary ::= unary-operator operand 5549884Ssheldonh | operand binary-operator operand 5649884Ssheldonh | operand 5749884Ssheldonh | "(" oexpr ")" 5849884Ssheldonh ; 5949884Ssheldonh unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| 6049884Ssheldonh "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; 611556Srgrimes 6249884Ssheldonh binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| 6349884Ssheldonh "-nt"|"-ot"|"-ef"; 6449884Ssheldonh operand ::= <any legal UNIX file name> 6549884Ssheldonh*/ 661556Srgrimes 6749884Ssheldonhenum token { 6849884Ssheldonh EOI, 6949884Ssheldonh FILRD, 7049884Ssheldonh FILWR, 7149884Ssheldonh FILEX, 7249884Ssheldonh FILEXIST, 7349884Ssheldonh FILREG, 7449884Ssheldonh FILDIR, 7549884Ssheldonh FILCDEV, 7649884Ssheldonh FILBDEV, 7749884Ssheldonh FILFIFO, 7849884Ssheldonh FILSOCK, 7949884Ssheldonh FILSYM, 8049884Ssheldonh FILGZ, 8149884Ssheldonh FILTT, 8249884Ssheldonh FILSUID, 8349884Ssheldonh FILSGID, 8449884Ssheldonh FILSTCK, 8549884Ssheldonh FILNT, 8649884Ssheldonh FILOT, 8749884Ssheldonh FILEQ, 8849884Ssheldonh FILUID, 8949884Ssheldonh FILGID, 9049884Ssheldonh STREZ, 9149884Ssheldonh STRNZ, 9249884Ssheldonh STREQ, 9349884Ssheldonh STRNE, 9449884Ssheldonh STRLT, 9549884Ssheldonh STRGT, 9649884Ssheldonh INTEQ, 9749884Ssheldonh INTNE, 9849884Ssheldonh INTGE, 9949884Ssheldonh INTGT, 10049884Ssheldonh INTLE, 10149884Ssheldonh INTLT, 10249884Ssheldonh UNOT, 10349884Ssheldonh BAND, 10449884Ssheldonh BOR, 10549884Ssheldonh LPAREN, 10649884Ssheldonh RPAREN, 10749884Ssheldonh OPERAND 1081556Srgrimes}; 1091556Srgrimes 11049884Ssheldonhenum token_types { 11149884Ssheldonh UNOP, 11249884Ssheldonh BINOP, 11349884Ssheldonh BUNOP, 11449884Ssheldonh BBINOP, 11549884Ssheldonh PAREN 1161556Srgrimes}; 1171556Srgrimes 11849884Ssheldonhstruct t_op { 11949884Ssheldonh const char *op_text; 12049884Ssheldonh short op_num, op_type; 12149884Ssheldonh} const ops [] = { 12249884Ssheldonh {"-r", FILRD, UNOP}, 12349884Ssheldonh {"-w", FILWR, UNOP}, 12449884Ssheldonh {"-x", FILEX, UNOP}, 12549884Ssheldonh {"-e", FILEXIST,UNOP}, 12649884Ssheldonh {"-f", FILREG, UNOP}, 12749884Ssheldonh {"-d", FILDIR, UNOP}, 12849884Ssheldonh {"-c", FILCDEV,UNOP}, 12949884Ssheldonh {"-b", FILBDEV,UNOP}, 13049884Ssheldonh {"-p", FILFIFO,UNOP}, 13149884Ssheldonh {"-u", FILSUID,UNOP}, 13249884Ssheldonh {"-g", FILSGID,UNOP}, 13349884Ssheldonh {"-k", FILSTCK,UNOP}, 13449884Ssheldonh {"-s", FILGZ, UNOP}, 13549884Ssheldonh {"-t", FILTT, UNOP}, 13649884Ssheldonh {"-z", STREZ, UNOP}, 13749884Ssheldonh {"-n", STRNZ, UNOP}, 13849884Ssheldonh {"-h", FILSYM, UNOP}, /* for backwards compat */ 13949884Ssheldonh {"-O", FILUID, UNOP}, 14049884Ssheldonh {"-G", FILGID, UNOP}, 14149884Ssheldonh {"-L", FILSYM, UNOP}, 14249884Ssheldonh {"-S", FILSOCK,UNOP}, 14349884Ssheldonh {"=", STREQ, BINOP}, 14449884Ssheldonh {"!=", STRNE, BINOP}, 14549884Ssheldonh {"<", STRLT, BINOP}, 14649884Ssheldonh {">", STRGT, BINOP}, 14749884Ssheldonh {"-eq", INTEQ, BINOP}, 14849884Ssheldonh {"-ne", INTNE, BINOP}, 14949884Ssheldonh {"-ge", INTGE, BINOP}, 15049884Ssheldonh {"-gt", INTGT, BINOP}, 15149884Ssheldonh {"-le", INTLE, BINOP}, 15249884Ssheldonh {"-lt", INTLT, BINOP}, 15349884Ssheldonh {"-nt", FILNT, BINOP}, 15449884Ssheldonh {"-ot", FILOT, BINOP}, 15549884Ssheldonh {"-ef", FILEQ, BINOP}, 15649884Ssheldonh {"!", UNOT, BUNOP}, 15749884Ssheldonh {"-a", BAND, BBINOP}, 15849884Ssheldonh {"-o", BOR, BBINOP}, 15949884Ssheldonh {"(", LPAREN, PAREN}, 16049884Ssheldonh {")", RPAREN, PAREN}, 16149884Ssheldonh {0, 0, 0} 1621556Srgrimes}; 1631556Srgrimes 16449884Ssheldonhstruct t_op const *t_wp_op; 16549884Ssheldonhchar **t_wp; 1661556Srgrimes 16790111Simpstatic int aexpr(enum token); 16890111Simpstatic int binop(void); 16990111Simpstatic int equalf(const char *, const char *); 17090111Simpstatic int filstat(char *, enum token); 17190111Simpstatic int getn(const char *); 17290111Simpstatic long long getq(const char *); 17390111Simpstatic int intcmp(const char *, const char *); 17490111Simpstatic int isoperand(void); 17590111Simpint main(int, char **); 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{ 18749884Ssheldonh int res; 18855179Ssheldonh char *p; 1891556Srgrimes 19055179Ssheldonh if ((p = rindex(argv[0], '/')) == NULL) 19155179Ssheldonh p = argv[0]; 19255179Ssheldonh else 19355179Ssheldonh p++; 19455179Ssheldonh if (strcmp(p, "[") == 0) { 19586622Sknu if (strcmp(argv[--argc], "]") != 0) 19686618Sknu error("missing ]"); 1971556Srgrimes argv[argc] = NULL; 1981556Srgrimes } 1991556Srgrimes 20086622Sknu /* no expression => false */ 20186622Sknu if (--argc <= 0) 20286622Sknu return 1; 20386622Sknu 20488084Sache#ifndef SHELL 20588084Sache (void)setlocale(LC_CTYPE, ""); 20688084Sache#endif 20750302Sgreen /* XXX work around the absence of an eaccess(2) syscall */ 20850087Sgreen (void)setgid(getegid()); 20950087Sgreen (void)setuid(geteuid()); 21050087Sgreen 21149884Ssheldonh t_wp = &argv[1]; 21249884Ssheldonh res = !oexpr(t_lex(*t_wp)); 2131556Srgrimes 21449884Ssheldonh if (*t_wp != NULL && *++t_wp != NULL) 21549884Ssheldonh syntax(*t_wp, "unexpected operator"); 21649884Ssheldonh 21749884Ssheldonh return res; 2181556Srgrimes} 2191556Srgrimes 22049884Ssheldonhstatic void 22190111Simpsyntax(const char *op, const char *msg) 2221556Srgrimes{ 2231556Srgrimes 22449884Ssheldonh if (op && *op) 22586618Sknu error("%s: %s", op, msg); 22649884Ssheldonh else 22786618Sknu error("%s", msg); 2281556Srgrimes} 2291556Srgrimes 23049884Ssheldonhstatic int 23190111Simpoexpr(enum token n) 2321556Srgrimes{ 23349884Ssheldonh int res; 2341556Srgrimes 23549884Ssheldonh res = aexpr(n); 23649884Ssheldonh if (t_lex(*++t_wp) == BOR) 23749884Ssheldonh return oexpr(t_lex(*++t_wp)) || res; 23849884Ssheldonh t_wp--; 23949884Ssheldonh return res; 24049884Ssheldonh} 2414171Sache 24249884Ssheldonhstatic int 24390111Simpaexpr(enum token n) 24449884Ssheldonh{ 24549884Ssheldonh int res; 2461556Srgrimes 24749884Ssheldonh res = nexpr(n); 24849884Ssheldonh if (t_lex(*++t_wp) == BAND) 24949884Ssheldonh return aexpr(t_lex(*++t_wp)) && res; 25049884Ssheldonh t_wp--; 25149884Ssheldonh return res; 2521556Srgrimes} 2531556Srgrimes 2541556Srgrimesstatic int 25590111Simpnexpr(enum token n) 2561556Srgrimes{ 25749884Ssheldonh if (n == UNOT) 25849884Ssheldonh return !nexpr(t_lex(*++t_wp)); 25949884Ssheldonh return primary(n); 2601556Srgrimes} 2611556Srgrimes 2621556Srgrimesstatic int 26390111Simpprimary(enum token n) 2641556Srgrimes{ 26549884Ssheldonh enum token nn; 26649884Ssheldonh int res; 2671556Srgrimes 26849884Ssheldonh if (n == EOI) 26949884Ssheldonh return 0; /* missing expression */ 27049884Ssheldonh if (n == LPAREN) { 27149884Ssheldonh if ((nn = t_lex(*++t_wp)) == RPAREN) 27249884Ssheldonh return 0; /* missing expression */ 27349884Ssheldonh res = oexpr(nn); 27449884Ssheldonh if (t_lex(*++t_wp) != RPAREN) 27549884Ssheldonh syntax(NULL, "closing paren expected"); 27649884Ssheldonh return res; 27749884Ssheldonh } 27849884Ssheldonh if (t_wp_op && t_wp_op->op_type == UNOP) { 27949884Ssheldonh /* unary expression */ 28049884Ssheldonh if (*++t_wp == NULL) 28149884Ssheldonh syntax(t_wp_op->op_text, "argument expected"); 28249884Ssheldonh switch (n) { 28349884Ssheldonh case STREZ: 28449884Ssheldonh return strlen(*t_wp) == 0; 28549884Ssheldonh case STRNZ: 28649884Ssheldonh return strlen(*t_wp) != 0; 28749884Ssheldonh case FILTT: 28849884Ssheldonh return isatty(getn(*t_wp)); 28949884Ssheldonh default: 29049884Ssheldonh return filstat(*t_wp, n); 29149884Ssheldonh } 29249884Ssheldonh } 2931556Srgrimes 29449884Ssheldonh if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { 29549884Ssheldonh return binop(); 29649884Ssheldonh } 29749884Ssheldonh 29849884Ssheldonh return strlen(*t_wp) > 0; 2991556Srgrimes} 3001556Srgrimes 3011556Srgrimesstatic int 30290111Simpbinop(void) 3031556Srgrimes{ 30449884Ssheldonh const char *opnd1, *opnd2; 30549884Ssheldonh struct t_op const *op; 3061556Srgrimes 30749884Ssheldonh opnd1 = *t_wp; 30849884Ssheldonh (void) t_lex(*++t_wp); 30949884Ssheldonh op = t_wp_op; 3101556Srgrimes 31149884Ssheldonh if ((opnd2 = *++t_wp) == NULL) 31249884Ssheldonh syntax(op->op_text, "argument expected"); 31349884Ssheldonh 31449884Ssheldonh switch (op->op_num) { 31549884Ssheldonh case STREQ: 31649884Ssheldonh return strcmp(opnd1, opnd2) == 0; 31749884Ssheldonh case STRNE: 31849884Ssheldonh return strcmp(opnd1, opnd2) != 0; 31949884Ssheldonh case STRLT: 32049884Ssheldonh return strcmp(opnd1, opnd2) < 0; 32149884Ssheldonh case STRGT: 32249884Ssheldonh return strcmp(opnd1, opnd2) > 0; 32349884Ssheldonh case INTEQ: 32462925Sse return intcmp(opnd1, opnd2) == 0; 32549884Ssheldonh case INTNE: 32662925Sse return intcmp(opnd1, opnd2) != 0; 32749884Ssheldonh case INTGE: 32862925Sse return intcmp(opnd1, opnd2) >= 0; 32949884Ssheldonh case INTGT: 33062925Sse return intcmp(opnd1, opnd2) > 0; 33149884Ssheldonh case INTLE: 33262925Sse return intcmp(opnd1, opnd2) <= 0; 33349884Ssheldonh case INTLT: 33462925Sse return intcmp(opnd1, opnd2) < 0; 33549884Ssheldonh case FILNT: 33649884Ssheldonh return newerf (opnd1, opnd2); 33749884Ssheldonh case FILOT: 33849884Ssheldonh return olderf (opnd1, opnd2); 33949884Ssheldonh case FILEQ: 34049884Ssheldonh return equalf (opnd1, opnd2); 34149884Ssheldonh default: 34249884Ssheldonh abort(); 34349884Ssheldonh /* NOTREACHED */ 3441556Srgrimes } 3451556Srgrimes} 3461556Srgrimes 34749884Ssheldonhstatic int 34890111Simpfilstat(char *nm, enum token mode) 3491556Srgrimes{ 35049884Ssheldonh struct stat s; 3511556Srgrimes 35249884Ssheldonh if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s)) 35349884Ssheldonh return 0; 3542664Scsgr 35549884Ssheldonh switch (mode) { 35649884Ssheldonh case FILRD: 35749884Ssheldonh return access(nm, R_OK) == 0; 35849884Ssheldonh case FILWR: 35949884Ssheldonh return access(nm, W_OK) == 0; 36049884Ssheldonh case FILEX: 36150302Sgreen /* XXX work around access(2) false positives for superuser */ 36250087Sgreen if (access(nm, X_OK) != 0) 36350087Sgreen return 0; 36450087Sgreen if (S_ISDIR(s.st_mode) || getuid() != 0) 36550087Sgreen return 1; 36650087Sgreen return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; 36749884Ssheldonh case FILEXIST: 36849884Ssheldonh return access(nm, F_OK) == 0; 36949884Ssheldonh case FILREG: 37049884Ssheldonh return S_ISREG(s.st_mode); 37149884Ssheldonh case FILDIR: 37249884Ssheldonh return S_ISDIR(s.st_mode); 37349884Ssheldonh case FILCDEV: 37449884Ssheldonh return S_ISCHR(s.st_mode); 37549884Ssheldonh case FILBDEV: 37649884Ssheldonh return S_ISBLK(s.st_mode); 37749884Ssheldonh case FILFIFO: 37849884Ssheldonh return S_ISFIFO(s.st_mode); 37949884Ssheldonh case FILSOCK: 38049884Ssheldonh return S_ISSOCK(s.st_mode); 38149884Ssheldonh case FILSYM: 38249884Ssheldonh return S_ISLNK(s.st_mode); 38349884Ssheldonh case FILSUID: 38449884Ssheldonh return (s.st_mode & S_ISUID) != 0; 38549884Ssheldonh case FILSGID: 38649884Ssheldonh return (s.st_mode & S_ISGID) != 0; 38749884Ssheldonh case FILSTCK: 38849884Ssheldonh return (s.st_mode & S_ISVTX) != 0; 38949884Ssheldonh case FILGZ: 39049884Ssheldonh return s.st_size > (off_t)0; 39149884Ssheldonh case FILUID: 39249884Ssheldonh return s.st_uid == geteuid(); 39349884Ssheldonh case FILGID: 39449884Ssheldonh return s.st_gid == getegid(); 39549884Ssheldonh default: 39649884Ssheldonh return 1; 3972675Scsgr } 39849884Ssheldonh} 3992675Scsgr 40049884Ssheldonhstatic enum token 40190111Simpt_lex(char *s) 40249884Ssheldonh{ 40349884Ssheldonh struct t_op const *op = ops; 40449884Ssheldonh 40549884Ssheldonh if (s == 0) { 40649884Ssheldonh t_wp_op = NULL; 40749884Ssheldonh return EOI; 40849884Ssheldonh } 40949884Ssheldonh while (op->op_text) { 41049884Ssheldonh if (strcmp(s, op->op_text) == 0) { 41149884Ssheldonh if ((op->op_type == UNOP && isoperand()) || 41249884Ssheldonh (op->op_num == LPAREN && *(t_wp+1) == 0)) 41349884Ssheldonh break; 41449884Ssheldonh t_wp_op = op; 41549884Ssheldonh return op->op_num; 4161556Srgrimes } 41749884Ssheldonh op++; 4181556Srgrimes } 41949884Ssheldonh t_wp_op = NULL; 42049884Ssheldonh return OPERAND; 4211556Srgrimes} 4221556Srgrimes 42349884Ssheldonhstatic int 42490111Simpisoperand(void) 4251556Srgrimes{ 42649884Ssheldonh struct t_op const *op = ops; 42749884Ssheldonh char *s; 42849884Ssheldonh char *t; 4291556Srgrimes 43049884Ssheldonh if ((s = *(t_wp+1)) == 0) 43149884Ssheldonh return 1; 43249884Ssheldonh if ((t = *(t_wp+2)) == 0) 43349884Ssheldonh return 0; 43449884Ssheldonh while (op->op_text) { 43549884Ssheldonh if (strcmp(s, op->op_text) == 0) 43649884Ssheldonh return op->op_type == BINOP && 43749884Ssheldonh (t[0] != ')' || t[1] != '\0'); 43849884Ssheldonh op++; 43949884Ssheldonh } 44049884Ssheldonh return 0; 4411556Srgrimes} 4421556Srgrimes 44349884Ssheldonh/* atoi with error detection */ 44449884Ssheldonhstatic int 44590111Simpgetn(const char *s) 4461556Srgrimes{ 44749884Ssheldonh char *p; 44849884Ssheldonh long r; 4491556Srgrimes 45049884Ssheldonh errno = 0; 45149884Ssheldonh r = strtol(s, &p, 10); 45249884Ssheldonh 45388084Sache if (s == p) 45488084Sache error("%s: bad number", s); 45588084Sache 45649884Ssheldonh if (errno != 0) 45787961Sache error((errno == EINVAL) ? "%s: bad number" : 45887961Sache "%s: out of range", s); 45949884Ssheldonh 46049884Ssheldonh while (isspace((unsigned char)*p)) 46186622Sknu p++; 46249884Ssheldonh 46349884Ssheldonh if (*p) 46486622Sknu error("%s: bad number", s); 46549884Ssheldonh 46649884Ssheldonh return (int) r; 4671556Srgrimes} 46849884Ssheldonh 46962925Sse/* atoi with error detection and 64 bit range */ 47088471Sachestatic long long 47190111Simpgetq(const char *s) 47262925Sse{ 47362925Sse char *p; 47488471Sache long long r; 47562925Sse 47662925Sse errno = 0; 47788471Sache r = strtoll(s, &p, 10); 47862925Sse 47988084Sache if (s == p) 48088084Sache error("%s: bad number", s); 48188084Sache 48262925Sse if (errno != 0) 48387961Sache error((errno == EINVAL) ? "%s: bad number" : 48487961Sache "%s: out of range", s); 48562925Sse 48662925Sse while (isspace((unsigned char)*p)) 48786622Sknu p++; 48862925Sse 48962925Sse if (*p) 49086622Sknu error("%s: bad number", s); 49162925Sse 49262925Sse return r; 49362925Sse} 49462925Sse 49549884Ssheldonhstatic int 49690111Simpintcmp (const char *s1, const char *s2) 49762925Sse{ 49888471Sache long long q1, q2; 49962925Sse 50062925Sse 50162925Sse q1 = getq(s1); 50262925Sse q2 = getq(s2); 50362925Sse 50462925Sse if (q1 > q2) 50562925Sse return 1; 50662925Sse 50762925Sse if (q1 < q2) 50862925Sse return -1; 50962925Sse 51062925Sse return 0; 51162925Sse} 51262925Sse 51362925Ssestatic int 51490111Simpnewerf (const char *f1, const char *f2) 51549884Ssheldonh{ 51649884Ssheldonh struct stat b1, b2; 51749884Ssheldonh 51849884Ssheldonh return (stat (f1, &b1) == 0 && 51949884Ssheldonh stat (f2, &b2) == 0 && 52049884Ssheldonh b1.st_mtime > b2.st_mtime); 52149884Ssheldonh} 52249884Ssheldonh 52349884Ssheldonhstatic int 52490111Simpolderf (const char *f1, const char *f2) 52549884Ssheldonh{ 52649884Ssheldonh struct stat b1, b2; 52749884Ssheldonh 52849884Ssheldonh return (stat (f1, &b1) == 0 && 52949884Ssheldonh stat (f2, &b2) == 0 && 53049884Ssheldonh b1.st_mtime < b2.st_mtime); 53149884Ssheldonh} 53249884Ssheldonh 53349884Ssheldonhstatic int 53490111Simpequalf (const char *f1, const char *f2) 53549884Ssheldonh{ 53649884Ssheldonh struct stat b1, b2; 53749884Ssheldonh 53849884Ssheldonh return (stat (f1, &b1) == 0 && 53949884Ssheldonh stat (f2, &b2) == 0 && 54049884Ssheldonh b1.st_dev == b2.st_dev && 54149884Ssheldonh b1.st_ino == b2.st_ino); 54249884Ssheldonh} 543