Date: Fri, 02 Mar 2001 09:49:17 +0000 From: Tony Finch <dot@dotat.at> To: FreeBSD-gnats-submit@freebsd.org Subject: ports/25490: [PATCH] fix various bugs in stat(1) Message-ID: <E14YmBZ-0000cI-00@hand.dotat.at>
next in thread | raw e-mail | index | archive | help
>Number: 25490 >Category: ports >Synopsis: [PATCH] fix various bugs in stat(1) >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-ports >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Mar 02 01:50:01 PST 2001 >Closed-Date: >Last-Modified: >Originator: Tony Finch <dot@dotat.at> >Release: FreeBSD 4.2-STABLE i386 >Organization: Covalent Technologies, Inc. >Environment: FreeBSD hand.dotat.at 4.2-STABLE FreeBSD 4.2-STABLE #4: Wed Feb 21 00:26:12 GMT 2001 fanf@hand.dotat.at:/FreeBSD/obj/FreeBSD/releng4/sys/DELL-Latitude-CSx i386 stat-1.3 Print inode contents >Description: The program is chock-a-block with buffer overflows. It prints the symbolic mode incorrectly in a few cases. It handles backslashes in a bogus fashion. >How-To-Repeat: fanf@hand.dotat.at:/FreeBSD/ports/sysutils/stat :; stat -f `perl -e 'print "."x1028'` . File: "." .................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... Segmentation fault (core dumped) fanf@hand.dotat.at:/FreeBSD/ports/sysutils/stat :; touch it fanf@hand.dotat.at:/FreeBSD/ports/sysutils/stat :; chmod +s it fanf@hand.dotat.at:/FreeBSD/ports/sysutils/stat :; ll it -rwSr-Sr-- 1 fanf fanf 0 Mar 2 09:31 it fanf@hand.dotat.at:/FreeBSD/ports/sysutils/stat :; stat it File: "it" Size: 0 Allocated Blocks: 0 Filetype: Regular File Mode: (6644/-rw-s-sr--) Uid: (1014/fanf) Gid: (1014/fanf) Device: 160771 Inode: 435037 Links: 1 Access: Fri Mar 2 09:31:21 2001 Modify: Fri Mar 2 09:31:21 2001 Change: Fri Mar 2 09:31:32 2001 fanf@hand.dotat.at:/FreeBSD/ports/sysutils/stat :; stat -f '%f\n' . File: "." Directoryn >Fix: In adittion to fixing the above bugs, this also extends the format syntax so that you can specify in more detail how the filename, symlink target, device major and minor numbers, and times are printed. --- stat.fmt.c.orig Sun Feb 16 13:12:33 1997 +++ stat.fmt.c Fri Mar 2 09:22:21 2001 @@ -1,7 +1,7 @@ /* $Id$ */ #ifndef lint -static char *sccsid = "@(#)stat.c 1.3 (UKC) 17/10/85"; -#endif lint +static const char *sccsid = "@(#)stat.c 1.3 (UKC) 17/10/85"; +#endif /* lint */ /*** * program name: @@ -11,28 +11,16 @@ * switches: -f fmt Display the i-node according to the format characters in "fmt". Syntax is like that of printf(3s) with the - following formatting characters:- - %f File type. - %d Device inode lives on. - %i Inode itself. - %p Protection bits. - %l # of links. - %u The user id - %g The group id. - %t Type of device. - %s Total size of file. - %a Access time. - %m Modified time. - %c Status change time. - %b # of blocks allocated. + formatting characters as encoded in FmtTbl below. * libraries used: - standard + getopt + libc * compile time parameters: - cc -O -o stat stat.c -lgetopt + cc -O -o stat stat.c * history: pur-ee!pucc-j!rsk, rsk@purdue-asc.arpa Original version by Hoch in the dark days of v6; this one by Rsk for 4.2 BSD. + fix-ups by fanf in 2001 ***/ @@ -40,468 +28,531 @@ * System - wide header files */ -#include <stdio.h> -#include <sys/time.h> #include <sys/types.h> -#include <ctype.h> #include <sys/stat.h> -#include <pwd.h> +#include <sys/time.h> + +#include <ctype.h> +#include <errno.h> #include <grp.h> -#include <stdlib.h> -#include <unistd.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> - /* - * Global structures and definitions - */ + /* + * Global structures and definitions + */ #define FAIL -1 /* Failure return code from call */ #define OKAY 0 /* Success return code from call */ -char *fmt_str; /* Format string for displaying i-nodes */ char *progname; /* Name we're called as */ -char *fmt_app __P((char *, char *)); -void FmtInode __P((char *, char*, struct stat *)); -void Usage __P((void)); +struct mystat { + char *filename; + char *linkname; + struct stat st; +}; -/* -** STAT_IT -- Display an i-node. -** -** Print the contents of an i-node. -** -** Parameters: -** ip -- Reference to a stat structure. -** -** Returns: -** None. -** -** Notes: -** None. -** -*/ - -int -stat_it(filename) -char *filename; -{ - int count; - char buf [BUFSIZ]; - struct stat Sbuf; /* for return values from stat() call */ -#define LBUFSIZ 256 /* Length of symbolic link translation buffer */ - char Lbuf [LBUFSIZ]; /* Symbolic link translation buffer */ - - if( lstat(filename,&Sbuf) == FAIL) { - fprintf(stderr,"Can't lstat %s\n",filename); - return(FAIL); - } - - if( (Sbuf.st_mode & S_IFMT) == S_IFLNK) { - if( (count = readlink(filename, Lbuf, sizeof Lbuf)) == FAIL) { - fprintf(stderr, "Can't readlink %s\n", filename); - return(FAIL); - } - if( count < LBUFSIZ) - Lbuf[count] = '\0'; - printf(" File: \"%s\" -> \"%s\"\n", filename, Lbuf); - } else - printf(" File: \"%s\"\n", filename); +typedef size_t FmtFunc __P((char *, size_t, char *, struct mystat *)); +size_t FmtInode __P((char *, size_t, char *, struct mystat *)); - FmtInode(buf, fmt_str, &Sbuf); - printf("%s\n", buf); - - return(OKAY); -} - -/* -** UTOS -- Uid to string mapping -** -** Return the login of the given -** uid. -** -** Parameters: -** buf -- Buffer to fill, -** ip -- Reference to a stat structure. -** -** Returns: -** None. -** -** Notes: -** None. -** + +/* +** UidToS */ - -void -UtoS(buf, ip) +size_t +UidToS(buf, len, fmt, ip) char buf []; -struct stat *ip; +size_t len; +char *fmt; +struct mystat *ip; { struct passwd *pwent; - extern struct passwd *getpwuid(); (void) setpwent(); - if ((pwent = getpwuid(ip -> st_uid)) == NULL) { - fprintf(stderr, "getpwuid() failed\n"); - exit(1); - } - (void) sprintf(buf, "%lu/%s", - ip -> st_uid, - pwent->pw_name); + if( (pwent = getpwuid(ip -> st.st_uid)) == NULL) + return snprintf(buf, len, "%lu", + (unsigned long) ip -> st.st_uid); + else + return snprintf(buf, len, "%lu/%s", + (unsigned long) ip -> st.st_gid, + pwent -> pw_name); } -/* -** GTOS -- Group to string mapping -** -** Given a numeric group-id, return -** the ASCII name of that group. -** -** Parameters: -** buf -- Buffer to fill, -** ip -- Reference to a stat structure. -** -** Returns: -** None. -** -** Notes: -** None. -** + +/* +** GidToS */ - -void -GtoS(buf, ip) +size_t +GidToS(buf, len, fmt, ip) char buf []; -struct stat *ip; +size_t len; +char *fmt; +struct mystat *ip; { struct group *grent; - extern struct group *getgrid(); (void) setgrent(); - if( (grent = getgrgid(ip -> st_gid)) == NULL) { - fprintf(stderr, "getgrgid(%lu) failed\n", ip -> st_gid); - exit(1); - } - (void) sprintf(buf, "%lu/%s", - ip -> st_gid, - grent -> gr_name); + if( (grent = getgrgid(ip -> st.st_gid)) == NULL) + return snprintf(buf, len, "%lu", + (unsigned long) ip -> st.st_gid); + else + return snprintf(buf, len, "%lu/%s", + (unsigned long) ip -> st.st_gid, + grent -> gr_name); } - -/* -** DEVTOS -- Device to string mapping -** -** Return a string containing the type -** of the device, if the file is a device. -** Else return a null string. -** -** Parameters: -** buf -- Buffer to fill, -** ip -- Reference to a stat structure. -** -** Returns: -** None. -** -** Notes: -** None. -** + +/* +** RDevToS */ - -void -DevToS(buf, ip) +size_t +RDevToS(buf, len, fmt, ip) char buf []; -struct stat *ip; +size_t len; +char *fmt; +struct mystat *ip; { - if ((ip -> st_mode & S_IFMT) == S_IFCHR - || (ip -> st_mode & S_IFMT) == S_IFBLK) - sprintf(buf, "Device Type: %lu", ip -> st_rdev); + if( !S_ISCHR(ip -> st.st_mode) && !S_ISBLK(ip -> st.st_mode)) + return 0; + else if( fmt != NULL) + return FmtInode(buf, len, fmt, ip); + else if( minor(ip -> st.st_rdev) > 255 + || minor(ip -> st.st_rdev) < 0) + return snprintf(buf, len, "%3d,0x%08x", + major(ip -> st.st_rdev), + minor(ip -> st.st_rdev)); else - strcpy(buf, ""); + return snprintf(buf, len, "%3d,%3d", + major(ip -> st.st_rdev), + minor(ip -> st.st_rdev)); } -/* -** MODETOS -- Mode word to string mapping -** -** Display the contents of the mode field -** in a readable format. -** -** Parameters: -** buf -- Buffer to write on, -** mode -- Mode field to interpret. -** -** Returns: -** None. -** -** Notes: -** None. -** + +/* +** ModeToS */ - -void -ModeToS(buf, ip) +size_t +ModeToS(buf, len, fmt, ip) char buf []; -struct stat *ip; +size_t len; +char *fmt; +struct mystat *ip; { - sprintf(buf, "%04o/----------", ip -> st_mode & 07777); + char mode[12]; - if(ip -> st_mode & 0000001) /* Other execute */ - buf[5 + 9] = 'x'; - if(ip -> st_mode & 0000002) /* Other write */ - buf[5 + 8] = 'w'; - if(ip -> st_mode & 0000004) /* Other read */ - buf[5 + 7] = 'r'; - if(ip -> st_mode & 0000010) /* Group execute */ - buf[5 + 6] = 'x'; - if(ip -> st_mode & 0000020) /* Group write */ - buf[5 + 5] = 'w'; - if(ip -> st_mode & 0000040) /* Group read */ - buf[5 + 4] = 'r'; - if(ip -> st_mode & 0000100) /* User execute */ - buf[5 + 3] = 'x'; - if(ip -> st_mode & 0000200) /* User write */ - buf[5 + 2] = 'w'; - if(ip -> st_mode & 0000400) /* User read */ - buf[5 + 1] = 'r'; - if(ip -> st_mode & 0001000) /* Sticky bit */ - buf[5 + 9] = 't'; - if(ip -> st_mode & 0002000) /* Set group id */ - buf[5 + 6] = 's'; - if(ip -> st_mode & 0004000) /* Set user id */ - buf[5 + 4] = 's'; - switch( ip -> st_mode & S_IFMT) { - case S_IFDIR: buf[5 + 0] = 'd'; - break; - case S_IFCHR: buf[5 + 0] = 'c'; - break; - case S_IFBLK: buf[5 + 0] = 'b'; - break; - case S_IFREG: buf[5 + 0] = '-'; - break; - case S_IFLNK: buf[5 + 0] = 'l'; - break; - case S_IFSOCK: buf[5 + 0] = 's'; - break; - default : buf[5 + 0] = '?'; - } + strmode(ip -> st.st_mode, mode); + if( mode[10] == ' ') + mode[10] = '\0'; + return snprintf(buf, len, "%04o/%s", + (int)(ip -> st.st_mode & ~S_IFMT), mode); } -/* -** TYPETOS -- Filetype to string mapping -** -** Given a filetype, return a string -** representation of that type. -** -** Parameters: -** buf -- Buffer to fill, -** ip -- Reference to a stat structure. -** -** Returns: -** None. -** -** Notes: -** None. -** + +/* +** TypeToS */ - -void -TypeToS(buf, ip) +size_t +TypeToS(buf, len, fmt, ip) char buf []; -struct stat *ip; +size_t len; +char *fmt; +struct mystat *ip; { - switch( ip -> st_mode & S_IFMT ) { + switch( ip -> st.st_mode & S_IFMT ) { case S_IFDIR: - strcpy(buf, "Directory"); - break; + return strlcpy(buf, "Directory", len); case S_IFCHR: - strcpy(buf, "Character Device"); - break; + return strlcpy(buf, "Character Device", len); case S_IFBLK: - strcpy(buf, "Block Device"); - break; + return strlcpy(buf, "Block Device", len); case S_IFREG: - strcpy(buf, "Regular File"); - break; + return strlcpy(buf, "Regular File", len); case S_IFLNK: - strcpy(buf, "Symbolic Link"); - break; + return strlcpy(buf, "Symbolic Link", len); case S_IFSOCK: - strcpy(buf, "Socket"); - break; + return strlcpy(buf, "Socket", len); default: - strcpy(buf, "Unknown"); - break; + return strlcpy(buf, "Unknown", len); } } -/* -** FMT_APP -- Append a format string -** -** Copy the first string argument -** to the second, returning a pointer -** to the next free byte. -** -** Parameters: -** src -- Source string, -** dest -- Destination string. -** -** Returns: -** Reference to the next free byte -** in the destination string. -** -** Notes: -** This routine is auxiliary to -** FmtInode() below. -** + +/* +** FileToS */ - -char * -fmt_app(src, dest) -register char *src, - *dest; +size_t +FileToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; { - - while ((*dest++ = *src++) != '\0') - ; /* NULL BODY */ - - return dest - 1; /* Back over the NUL byte */ + return strlcpy(buf, ip -> filename, len); } + +/* +** LinkToS +*/ +size_t +LinkToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + if( ip -> linkname == NULL) + return 0; + else if( fmt != NULL) + return FmtInode(buf, len, fmt, ip); + else + return strlcpy(buf, ip -> linkname, len); +} + +/* +** QtoS +*/ +size_t +QtoS(buf, len, q) +char buf []; +size_t len; +quad_t q; +{ + return snprintf(buf, len, "%qd", q); +} + +/* +** InoToS +*/ +size_t +InoToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return QtoS(buf, len, (quad_t) ip -> st.st_ino); +} + +/* +** DevToS +*/ +size_t +DevToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return QtoS(buf, len, (quad_t) ip -> st.st_dev); +} + +/* +** NLinkToS +*/ +size_t +NLinkToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return QtoS(buf, len, (quad_t) ip -> st.st_nlink); +} + +/* +** SizeToS +*/ +size_t +SizeToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return QtoS(buf, len, (quad_t) ip -> st.st_size); +} + +/* +** BlocksToS +*/ +size_t +BlocksToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return QtoS(buf, len, (quad_t) ip -> st.st_blocks); +} + +/* +** TimeToS +*/ +size_t +TimeToS(buf, len, fmt, t) +char buf []; +size_t len; +char *fmt; +time_t t; +{ + return strftime(buf, len, fmt ? fmt : "%c", localtime(&t)); +} + +/* +** ATimeToS +*/ +size_t +ATimeToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return TimeToS(buf, len, fmt, ip -> st.st_atime); +} + +/* +** CTimeToS +*/ +size_t +CTimeToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return TimeToS(buf, len, fmt, ip -> st.st_ctime); +} + +/* +** MTimeToS +*/ +size_t +MTimeToS(buf, len, fmt, ip) +char buf []; +size_t len; +char *fmt; +struct mystat *ip; +{ + return TimeToS(buf, len, fmt, ip -> st.st_mtime); +} + +/* +** Formatting table for the above functions +*/ +FmtFunc *FmtTbl[] = { + /* a */ ATimeToS, + /* b */ BlocksToS, + /* c */ CTimeToS, + /* d */ DevToS, + /* e */ NULL, + /* f */ TypeToS, + /* g */ GidToS, + /* h */ NULL, + /* i */ InoToS, + /* j */ NULL, + /* k */ NULL, + /* l */ NLinkToS, + /* m */ MTimeToS, + /* n */ FileToS, + /* o */ NULL, + /* p */ ModeToS, + /* q */ NULL, + /* r */ LinkToS, + /* s */ SizeToS, + /* t */ RDevToS, + /* u */ UidToS, + /* v */ NULL, + /* w */ NULL, + /* x */ NULL, + /* y */ NULL, + /* z */ NULL, +}; + +/* +** Backslash +*/ +int +Backslash(buf, fmt) +char *buf; +char *fmt; +{ + int c, n; - -/* -** FMTINODE -- Format an Inode + switch (*fmt) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + for(n = c = 0; *fmt >= 0 && *fmt <= 7; fmt++, n++) + c = c * 8 + *fmt - '0'; + *buf = c; + return n; + case 'a': + *buf++ = '\a'; + return 1; + case 'b': + *buf++ = '\b'; + return 1; + case 'e': + *buf++ = '\033'; + return 1; + case 'f': + *buf++ = '\f'; + return 1; + case 'n': + *buf++ = '\n'; + return 1; + case 'r': + *buf++ = '\r'; + return 1; + case 't': + *buf++ = '\t'; + return 1; + case 'v': + *buf++ = '\v'; + return 1; + default: + *buf++ = *fmt; + return 1; + } +} + +/* +** FmtInode +*/ +size_t +FmtInode(buf, len, fmt, ip) +char *buf; +size_t len; +char *fmt; +struct mystat *ip; +{ + FmtFunc *f; + char *p; + size_t count, n; + + count = 0; + for( n = strcspn(fmt, "\\%"); fmt[n]; n = strcspn(fmt, "\\%")) { + strlcpy(buf, fmt, n < len ? n+1 : len); + count += n; + buf += n; + if( n < len) + len -= n; + else + len = 0; + p = fmt += n + 1; + if( p[-1] == '\\') { + if( len > 0) + fmt += Backslash(buf, fmt); + n = 1; + } else if( islower(*p)) { + f = FmtTbl[*p - 'a']; + if( f == NULL) + continue; + n = f(buf, len, NULL, ip); + } else if( *p == '{') { + p = strchr(p, '}'); + if( p == NULL) + continue; + if( !islower(*++p)) + continue; + f = FmtTbl[*p - 'a']; + if( f == NULL) + continue; + p[-1] = '\0'; + n = f(buf, len, fmt+1, ip); + p[-1] = '}'; + } else { + continue; + } + count += n; + buf += n; + if( n < len) + len -= n; + else + len = 0; + fmt = p + 1; + } + count += strlcpy(buf, fmt, len); + return count; +} + +/* +** STAT_IT -- Display an i-node. ** -** Build a textual representation of -** the Inode into the specified buffer -** according to the printf-like format -** string. +** Print the contents of an i-node. ** ** Parameters: -** buf -- Buffer to fill, -** fmt -- Printf-like format string. -** rp -- Reference to Inode cell, +** filename -- Name of the file. ** ** Returns: ** None. ** -** ** Notes: -** The format characters recognised here are: -** -** %f File type. -** %d Device inode lives on. -** %i Inode itself. -** %p Protection bits. -** %l # of links. -** %u The user id -** %g The group id. -** %t Type of device. -** %s Total size of file. -** %a Access time. -** %m Modified time. -** %c Status change time. -** %b # of blocks allocated. -** -** Use a backslash to 'hide' any special character, e.g. '%' -** -** The default format string is: +** None. ** -** "%r,,%u,%t,%o" */ -void -FmtInode(buf, fmt, ip) -char *buf, - *fmt; -struct stat *ip; -{ - char auxbuf [64]; - register char *bufp; - register int c; - extern char *ctime(); - - for (bufp = buf; (c = *fmt++) != '\0'; ) { - if (c == '\\') - c = *fmt++; - - if (c != '%') { - *bufp++ = c; - } else { - switch (c = *fmt++) { - case 'f': /* Filetype */ - TypeToS(auxbuf, ip); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'i': /* The actual Inode */ - sprintf(auxbuf, "%ld", ip -> st_ino); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'd': /* The Device */ - sprintf(auxbuf, "%ld", ip -> st_dev); - bufp = fmt_app(auxbuf, bufp); - break; - - case 't': /* Device Type */ - DevToS(auxbuf, ip); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'p': /* Protection bits */ - ModeToS(auxbuf, ip); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'l': /* # of links */ - sprintf(auxbuf, "%d", ip -> st_nlink); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'u': /* User id */ - UtoS(auxbuf, ip); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'g': /* Group id */ - GtoS(auxbuf, ip); - bufp = fmt_app(auxbuf, bufp); - break; - - case 's': /* Total size of file */ - sprintf(auxbuf, "%qd", ip -> st_size); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'a': /* Access time */ - sprintf(auxbuf, "%24.24s", ctime(&ip -> st_atime)); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'm': /* Modified time */ - sprintf(auxbuf, "%24.24s", ctime(&ip -> st_mtime)); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'c': /* Status change time */ - sprintf(auxbuf, "%24.24s", ctime(&ip -> st_ctime)); - bufp = fmt_app(auxbuf, bufp); - break; - - case 'b': /* # of blocks allocated */ - sprintf(auxbuf, "%qd",ip -> st_blocks); - bufp = fmt_app(auxbuf, bufp); - break; - - default: /* Just copy it over */ - *bufp++ = c; - break; - } +int +stat_it(format, filename) +char *format; +char *filename; +{ + int count; + char buf [BUFSIZ]; + struct mystat Sbuf; /* for return values from stat() call */ +#define LBUFSIZ 256 /* Length of symbolic link translation buffer */ + char Lbuf [LBUFSIZ]; /* Symbolic link translation buffer */ + size_t n; + + if( lstat(filename,&Sbuf.st) == FAIL) { + fprintf(stderr,"lstat %s: %s\n", + filename, strerror(errno)); + return(FAIL); + } + + if( (Sbuf.st.st_mode & S_IFMT) == S_IFLNK) { + if( (count = readlink(filename, Lbuf, sizeof Lbuf)) == FAIL) { + fprintf(stderr, "readlink %s: %s\n", + filename, strerror(errno)); + return(FAIL); } + if( count >= sizeof Lbuf) { + fprintf(stderr, "readlink %s: Link name too long\n", + filename); + return(FAIL); + } + Lbuf[count] = '\0'; + Sbuf.linkname = Lbuf; + } else { + Sbuf.linkname = NULL; + } + Sbuf.filename = filename; + n = FmtInode(buf, sizeof buf, format, &Sbuf); + if( n >= sizeof(buf)) { + fprintf(stderr, "Formatted string too long for %s\n", filename); + return(FAIL); } + + printf("%s", buf); + return(OKAY); } -/* + +/* ** USAGE -- Display a reminder ** ** Print a reminder of the correct usage @@ -529,8 +580,7 @@ int argc; char *argv[]; { - extern int optind; - extern char *optarg; + char *format; int c; @@ -540,16 +590,11 @@ progname = argv [0]; - if (argc == 1) { - Usage(); - exit(1); - } - /* * Set some defaults ... */ - fmt_str = " Size: %s\tAllocated Blocks: %b\tFiletype: %f\n Mode: (%p)\tUid: (%u) Gid: (%g)\nDevice: %d\tInode: %i\tLinks: %l\t%t\nAccess: %a\nModify: %m\nChange: %c\n"; + format = strdup(" File: \"%n\"%{ -> \"%r\"}r\n Size: %s\tAllocated Blocks: %b\tFiletype: %f\n Mode: (%p)\tUid: (%u) Gid: (%g)\nDevice: %d\tInode: %i\tLinks: %l%{\tDevice Type: %t}t\nAccess: %a\nModify: %m\nChange: %c\n\n"); /* * Check for flag arguments ... @@ -562,16 +607,23 @@ exit(1); case 'f': /* Format specifier */ - fmt_str = optarg; + format = optarg; break; } + argc -= optind; + argv += optind; /* * Ok, now for the file arguments ... */ - for (c = 0; optind < argc; ++optind) { - c += stat_it(argv [optind]); + if (argc == 0) { + Usage(); + exit(1); + } + + while (argc--) { + c += stat_it(format, *argv++); } /* check for errors, e.g. file does not exists */ --- stat.1~ Sun Feb 16 13:16:52 1997 +++ stat.1 Fri Mar 2 09:46:16 2001 @@ -18,35 +18,47 @@ Size: 1024 Allocated Blocks: 2 Filetype: Directory Mode: (0755/drwxr-xr-x) Uid: (0/root) Gid: (0/system) Device: 0,0 Inode: 2 Links: 20 -Access: Wed Jan 8 12:40:16 1986(00000.00:00:01) -Modify: Wed Dec 18 09:32:09 1985(00021.03:08:08) -Change: Wed Dec 18 09:32:09 1985(00021.03:08:08) +Access: Wed Jan 8 12:40:16 1986 +Modify: Wed Dec 18 09:32:09 1985 +Change: Wed Dec 18 09:32:09 1985 .fi .PP .SH OPTIONS .TP .B \-f format Display the i-node according to the format characters -in "format". Syntax is like that of printf(3s) with the +in "format". +Syntax is like that of printf(3s) with the following formatting characters: .nf - %f File type. + %a Access time. + %b Number of blocks allocated. + %c Status change time. %d Device inode lives on. + %f File type. + %g The group id. %i Inode itself. + %l Number of links. + %m Modified time. + %n File name. %p Protection bits. - %l # of links. %u The user id - %g The group id. - %t Type of device. + %r Symlink name. %s Total size of file. - %a Access time. - %m Modified time. - %c Status change time. - %b # of blocks allocated. + %t Type of device. + .fi +You can also specify additional formatting information inside curly +braces between the percent and the formatting character. +For the time options %{}a, %{}c, %{}m, this format is passed to +\fIstrftime(3)\fR. +For %{}r the format between the braces is interpreted by \fIstat\fR +only if the argument is a symbolic link. +For %{}t the format between the braces is interpreted by \fIstat\fR +only if the argument is a special file. .SH "SEE ALSO" -stat(2), ls(1) +stat(2), ls(1), strftime(3). .SH DIAGNOSTICS "Can't stat file" or "Can't lstat file" usually means that it doesn't exist. "Can't readlink file" implies something is amiss with a symbolic link. >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E14YmBZ-0000cI-00>