From owner-svn-src-all@FreeBSD.ORG Wed Jan 12 07:38:49 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1BCD51065672; Wed, 12 Jan 2011 07:38:49 +0000 (UTC) (envelope-from dougb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DAD788FC17; Wed, 12 Jan 2011 07:38:48 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p0C7cmWZ059596; Wed, 12 Jan 2011 07:38:48 GMT (envelope-from dougb@svn.freebsd.org) Received: (from dougb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p0C7cmlH059592; Wed, 12 Jan 2011 07:38:48 GMT (envelope-from dougb@svn.freebsd.org) Message-Id: <201101120738.p0C7cmlH059592@svn.freebsd.org> From: Doug Barton Date: Wed, 12 Jan 2011 07:38:48 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r217300 - stable/7/usr.bin/stat X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 12 Jan 2011 07:38:49 -0000 Author: dougb Date: Wed Jan 12 07:38:48 2011 New Revision: 217300 URL: http://svn.freebsd.org/changeset/base/217300 Log: For stat.c ========== MFC r216196: Bring in the change from NetBSD 1.18: "If using stat (the -L flag) and it fails, fall back to lstat(). It may be the case that we're examining a broken symlink, and anything is better than nothing." The changes in 1.14 through 1.17 were not relevant to us. Obtained from: atatat@NetBSD.org MFC r216202: Bring in the change from NetBSD 1.22: "Fix a trivial truncation case, and eliminate a corner case that might print a nul character." I am purposely bypassing the following versions: 1.19 A build infrastructure change that does not apply to us 1.20 A feature I am not interested in, but don't object if someone else wants to pick it up 1.21 A build infrastructure change that does not apply to us Obtained from: atatat@NetBSD.org MFC r216203: Bring in a new feature, adding a -f option to readlink to print the path of the target, similar to realpath(1). See the discussion at: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=34662 This brings in the following changes: 1.24 "PR/34662: martijnb at atlas dot ipv6 dot stack dot nl: readlink doesn't grok -f, and there's no alternative (+fix) Patch applied with minor tweak (%y -> %R, as it was already taken) plus some nits from myself. Thanks!" Obtained from: elad@NetBSD.org 1.25 "Fix a segfault when doing 'stat -f %R' on the stdin file handle, instead fake the filename '(stdin)' like the %N format." Obtained from: mlelstv@NetBSD.org 1.27 "The ofmt variable is actually a bit mask (not the character that was in the format string) so that we can "or" it with the bits in the formats variable. This fixes the missing " -> " in front of the real path (when you use %SR). Also, the ?: needs another space." Obtained from: atatat@NetBSD.org I am purposely omitting the following changes: 1.23 A humanize_number(3) clone that should better be implemented by actually using humanize_number(3) 1.26 This is the removal of license clause 3 and 4, already handled by imp in r203971 MFC 216205: Bring in the update from NetBSD 1.28: "Fix WARNS=4 issues (-Wcast-qual -Wsign-compare)" Because of code differences I had to hand-apply parts of the patch, so responsibility for errors goes to me. Obtained from: lukem@NetBSD.org MFC 216206: [ Also applies to Makefile ] Fix an "unused variable" error that gets us all the way to WARNS=6 MFC 216207: Bring in the following changes from NetBSD. See the discussion at: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=44128 1.29 "Don't printf time_t with %d; fixes PR 44128 from yamt. With this change it successfully prints mtimes after 2038." 1.30 "Improve previous with comments." Obtained from: dholland@NetBSD.org (both) MFC 216343: Bring in the change from OpenBSD's 1.14: "synchronize synopsis and usage; "-l", "-r", "-s" and "-x" are mutually exclusive; while here, slightly improve spacing in the source code so it fits on a 80-column display again. diff greatly improved by martynas@" Obtained from: sobrado@OpenBSD.org MFC 216512: Bring in the relevant changes from NetBSD's 1.31: "Use strlcpy, not strncpy, when the desired semantics are strlcpy's rather than strncpy's." Note: NetBSD's 1.32 is their adoption of our r216206 Obtained from: dholland@NetBSD.org For stat.1 ========== MFC 216197: Add my own documentation for the change in our r216196, aka NetBSD's 1.18 For -L if stat(2) fails, fall back to lstat(2). .Dd purposely not bumped because more changes are coming. MFC 216204: Bring in the update from NetBSD 1.19, the documentation of readlink -f "PR/34662: martijnb at atlas dot ipv6 dot stack dot nl: readlink doesn't grok -f, and there's no alternative (+fix) Patch applied with minor tweak (%y -> %R, as it was already taken) plus some nits from myself. Thanks!" Obtained from: elad@NetBSD.org MFC 216209: Bring in the change from NetBSD 1.12: "document default format." Obtained from: yamt@NetBSD.org MFC 216213: Bring in the changes from NetBSD 1.13 that we did not already have, with some differences. "Sort options. Use more mdoc macros. Some nit fixes. Bump date." Obtained from: wiz@NetBSD.org MFC 216215: Bring in the changes from NetBSD 1.16 that we did not already have. "Some fixes from jmc@openbsd." Obtained from: wiz@NetBSD.org MFC 216216: Bring in the change from NetBSD 1.20: "Make sentence easier to parse. From jsing@openbsd via jmc@openbsd." Obtained from: wiz@NetBSD.org MFC 216218: Bring in the following changes from NetBSD: 1.21 "Document the flags displayed by the default format, and mention their short names. From espie@openbsd via jmc@openbsd." 1.24 "Fix three variable names. From Todd T. Fries via Jason McIntyre." Obtained from: wiz@NetBSD.org (previous 2) 1.25 "Be consistent: document the birthtime field of struct stat for the "B" field specifier." Obtained from: reed@NetBSD.org 1.26 "Drop trailing space." Obtained from: wiz@NetBSD.org 1.27 "Since we have st_birthtime in struct stat, it is in default display." Obtained from: enami@NetBSD.org Purposely skipping the following revisions: 1.22 NetBSD-specific change 1.23 Removal of license clauses 3 and 4, already handled by imp in our r203971 MFC 216219: Bring in the change from NetBSD 1.28: "\\ -> \e" Obtained from: joerg@NetBSD.org Bump .Dd because we're now up to date with the latest NetBSD version Modified: stable/7/usr.bin/stat/Makefile stable/7/usr.bin/stat/stat.1 stable/7/usr.bin/stat/stat.c Directory Properties: stable/7/usr.bin/stat/ (props changed) Modified: stable/7/usr.bin/stat/Makefile ============================================================================== --- stable/7/usr.bin/stat/Makefile Wed Jan 12 07:27:30 2011 (r217299) +++ stable/7/usr.bin/stat/Makefile Wed Jan 12 07:38:48 2011 (r217300) @@ -1,7 +1,7 @@ # $FreeBSD$ PROG= stat -WARNS?= 2 +WARNS?= 6 LINKS= ${BINDIR}/stat ${BINDIR}/readlink MLINKS= stat.1 readlink.1 Modified: stable/7/usr.bin/stat/stat.1 ============================================================================== --- stable/7/usr.bin/stat/stat.1 Wed Jan 12 07:27:30 2011 (r217299) +++ stable/7/usr.bin/stat/stat.1 Wed Jan 12 07:38:48 2011 (r217300) @@ -1,4 +1,4 @@ -.\" $NetBSD: stat.1,v 1.11 2003/05/08 13:07:10 wiz Exp $ +.\" $NetBSD: stat.1,v 1.28 2010/04/05 21:25:01 joerg Exp $ .\" .\" Copyright (c) 2002 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 24, 2010 +.Dd December 5, 2010 .Dt STAT 1 .Os .Sh NAME @@ -43,15 +43,15 @@ .Op Fl t Ar timefmt .Op Ar .Nm readlink -.Op Fl n +.Op Fl fn .Op Ar .Sh DESCRIPTION The .Nm utility displays information about the file pointed to by .Ar file . -Read, write or execute permissions of the named file are not required, but -all directories listed in the path name leading to the file must be +Read, write, or execute permissions of the named file are not required, but +all directories listed in the pathname leading to the file must be searchable. If no argument is given, .Nm @@ -60,13 +60,42 @@ displays information about the file desc When invoked as .Nm readlink , only the target of the symbolic link is printed. -If the given argument is not a symbolic link, +If the given argument is not a symbolic link and the +.Fl f +option is not specified, .Nm readlink will print nothing and exit with an error. +If the +.Fl f +option is specified, the output is canonicalized by following every symlink +in every component of the given path recursively. +.Nm readlink +will resolve both absolute and relative paths, and return the absolute pathname +corresponding to +.Ar file . +In this case, the argument does not need to be a symbolic link. .Pp The information displayed is obtained by calling .Xr lstat 2 with the given argument and evaluating the returned structure. +The default format displays the +.Fa st_dev , +.Fa st_ino , +.Fa st_mode , +.Fa st_nlink , +.Fa st_uid , +.Fa st_gid , +.Fa st_rdev , +.Fa st_size , +.Fa st_atime , +.Fa st_mtime , +.Fa st_ctime , +.Fa st_birthtime , +.Fa st_blksize , +.Fa st_blocks , +and +.Fa st_flags +fields, in that order. .Pp The options are as follows: .Bl -tag -width indent @@ -107,6 +136,14 @@ will refer to the target of if file is a symbolic link, and not to .Ar file itself. +If the link is broken or the target does not exist, +fall back on +.Xr lstat 2 +and report information about the link. +.It Fl l +Display output in +.Ic ls Fl lT +format. .It Fl n Do not force a newline to appear at the end of each piece of output. .It Fl q @@ -136,7 +173,8 @@ display the raw, numerical value (for ex epoch, etc.). .It Fl s Display information in -.Dq "shell output" , +.Dq shell output +format, suitable for initializing variables. .It Fl x Display information in a more verbose way as known from some @@ -334,49 +372,62 @@ A required field specifier, being one of .It Cm d Device upon which .Ar file -resides. +resides +.Pq Fa st_dev . .It Cm i .Ar file Ns 's -inode number. +inode number +.Pq Fa st_ino . .It Cm p -File type and permissions. +File type and permissions +.Pq Fa st_mode . .It Cm l Number of hard links to -.Ar file . +.Ar file +.Pq Fa st_nlink . .It Cm u , g User ID and group ID of .Ar file Ns 's -owner. +owner +.Pq Fa st_uid , st_gid . .It Cm r -Device number for character and block device special files. +Device number for character and block device special files +.Pq Fa st_rdev . .It Cm a , m , c , B The time .Ar file -was last accessed or modified, of when the inode was last changed, or -the birth time of the inode. +was last accessed or modified, or when the inode was last changed, or +the birth time of the inode +.Pq Fa st_atime , st_mtime , st_ctime , st_birthtime . .It Cm z The size of .Ar file -in bytes. +in bytes +.Pq Fa st_size . .It Cm b Number of blocks allocated for -.Ar file . +.Ar file +.Pq Fa st_blocks . .It Cm k -Optimal file system I/O operation block size. +Optimal file system I/O operation block size +.Pq Fa st_blksize . .It Cm f User defined flags for .Ar file . .It Cm v -Inode generation number. +Inode generation number +.Pq Fa st_gen . .El .Pp -The following four field specifiers are not drawn directly from the +The following five field specifiers are not drawn directly from the data in .Vt "struct stat" , but are: .Bl -tag -width indent .It Cm N The name of the file. +.It Cm R +The absolute pathname corresponding to the file. .It Cm T The file type, either as in .Nm ls Fl F @@ -406,12 +457,12 @@ as an output form, with the exception of .Cm p which defaults to -.Cm O , +.Cm O ; .Cm a , m , and .Cm c which default to -.Cm D , +.Cm D ; and .Cm Y , T , and @@ -421,8 +472,15 @@ which default to .Sh EXIT STATUS .Ex -std stat readlink .Sh EXAMPLES +If no options are specified, the default format is +"%d %i %Sp %l %Su %Sg %r %z \e"%Sa\e" \e"%Sm\e" \e"%Sc\e" \e"%SB\e" %k %b %#Xf %N". +.Bd -literal -offset indent +\*[Gt] stat /tmp/bar +0 78852 -rw-r--r-- 1 root wheel 0 0 "Jul 8 10:26:03 2004" "Jul 8 10:26:03 2004" "Jul 8 10:28:13 2004" "Jan 1 09:00:00 1970" 16384 0 0 /tmp/bar +.Ed +.Pp Given a symbolic link -.Pa foo +.Dq foo that points from .Pa /tmp/foo to Modified: stable/7/usr.bin/stat/stat.c ============================================================================== --- stable/7/usr.bin/stat/stat.c Wed Jan 12 07:27:30 2011 (r217299) +++ stable/7/usr.bin/stat/stat.c Wed Jan 12 07:38:48 2011 (r217300) @@ -30,7 +30,8 @@ #include #if 0 #ifndef lint -__RCSID("$NetBSD: stat.c,v 1.13 2003/07/25 03:21:17 atatat Exp $"); +__RCSID("$NetBSD: stat.c,v 1.31 2010/12/16 05:30:16 dholland Exp $" +"$OpenBSD: stat.c,v 1.14 2009/06/24 09:44:25 sobrado Exp $"); #endif #endif @@ -51,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -150,6 +152,7 @@ __FBSDID("$FreeBSD$"); #define MIDDLE_PIECE 'M' #define LOW_PIECE 'L' +#define SHOW_realpath 'R' #define SHOW_st_dev 'd' #define SHOW_st_ino 'i' #define SHOW_st_mode 'p' @@ -173,7 +176,7 @@ __FBSDID("$FreeBSD$"); void usage(const char *); void output(const struct stat *, const char *, - const char *, int, int, int); + const char *, int, int); int format1(const struct stat *, /* stat info */ const char *, /* the file name */ const char *, int, /* the format string itself */ @@ -184,7 +187,7 @@ int format1(const struct stat *, /* stat char *xfflagstostr(unsigned long); #endif -char *timefmt; +const char *timefmt; int linkfail; #define addchar(s, c, nl) \ @@ -199,7 +202,7 @@ main(int argc, char *argv[]) struct stat st; int ch, rc, errs, am_readlink; int lsF, fmtchar, usestat, fn, nonl, quiet; - char *statfmt, *options, *synopsis; + const char *statfmt, *options, *synopsis; const char *file; am_readlink = 0; @@ -214,14 +217,15 @@ main(int argc, char *argv[]) if (strcmp(getprogname(), "readlink") == 0) { am_readlink = 1; - options = "n"; - synopsis = "[-n] [file ...]"; + options = "fn"; + synopsis = "[-fn] [file ...]"; statfmt = "%Y"; fmtchar = 'f'; quiet = 1; } else { options = "f:FlLnqrst:x"; - synopsis = "[-FlLnqrsx] [-f format] [-t timefmt] [file ...]"; + synopsis = "[-FLnq] [-f format | -l | -r | -s | -x] " + "[-t timefmt] [file ...]"; } while ((ch = getopt(argc, argv, options)) != -1) @@ -239,6 +243,10 @@ main(int argc, char *argv[]) quiet = 1; break; case 'f': + if (am_readlink) { + statfmt = "%R"; + break; + } statfmt = optarg; /* FALLTHROUGH */ case 'l': @@ -306,8 +314,17 @@ main(int argc, char *argv[]) rc = fstat(STDIN_FILENO, &st); } else { file = argv[0]; - if (usestat) - rc = stat(file, &st); + if (usestat) { + /* + * Try stat() and if it fails, fall back to + * lstat() just in case we're examining a + * broken symlink. + */ + if ((rc = stat(file, &st)) == -1 && + errno == ENOENT && + (rc = lstat(file, &st)) == -1) + errno = ENOENT; + } else rc = lstat(file, &st); } @@ -319,7 +336,7 @@ main(int argc, char *argv[]) warn("%s: stat", file); } else - output(&st, file, statfmt, fn, nonl, quiet); + output(&st, file, statfmt, fn, nonl); argv++; argc--; @@ -361,10 +378,10 @@ usage(const char *synopsis) */ void output(const struct stat *st, const char *file, - const char *statfmt, int fn, int nonl, int quiet) + const char *statfmt, int fn, int nonl) { int flags, size, prec, ofmt, hilo, what; - char buf[PATH_MAX]; + char buf[PATH_MAX + 4 + 1]; const char *subfmt; int nl, t, i; @@ -501,6 +518,7 @@ output(const struct stat *st, const char } switch (*statfmt) { + fmtcase(what, SHOW_realpath); fmtcase(what, SHOW_st_dev); fmtcase(what, SHOW_st_ino); fmtcase(what, SHOW_st_mode); @@ -533,7 +551,7 @@ output(const struct stat *st, const char buf, sizeof(buf), flags, size, prec, ofmt, hilo, what); - for (i = 0; i < t && i < sizeof(buf); i++) + for (i = 0; i < t && i < (int)(sizeof(buf) - 1); i++) addchar(stdout, buf[i], &nl); continue; @@ -560,7 +578,8 @@ format1(const struct stat *st, int hilo, int what) { u_int64_t data; - char *sdata, lfmt[24], tmp[20]; + char *stmp, lfmt[24], tmp[20]; + const char *sdata; char smode[12], sid[12], path[PATH_MAX + 4]; struct passwd *pw; struct group *gr; @@ -621,28 +640,29 @@ format1(const struct stat *st, small = (sizeof(st->st_mode) == 4); data = st->st_mode; strmode(st->st_mode, smode); - sdata = smode; - l = strlen(sdata); - if (sdata[l - 1] == ' ') - sdata[--l] = '\0'; + stmp = smode; + l = strlen(stmp); + if (stmp[l - 1] == ' ') + stmp[--l] = '\0'; if (hilo == HIGH_PIECE) { data >>= 12; - sdata += 1; - sdata[3] = '\0'; + stmp += 1; + stmp[3] = '\0'; hilo = 0; } else if (hilo == MIDDLE_PIECE) { data = (data >> 9) & 07; - sdata += 4; - sdata[3] = '\0'; + stmp += 4; + stmp[3] = '\0'; hilo = 0; } else if (hilo == LOW_PIECE) { data &= 0777; - sdata += 7; - sdata[3] = '\0'; + stmp += 7; + stmp[3] = '\0'; hilo = 0; } + sdata = stmp; formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX | FMTF_STRING; if (ofmt == 0) @@ -703,7 +723,6 @@ format1(const struct stat *st, ts = *tsp; /* copy so we can muck with it */ small = (sizeof(ts.tv_sec) == 4); data = ts.tv_sec; - small = 1; tm = localtime(&ts.tv_sec); (void)strftime(path, sizeof(path), timefmt, tm); sdata = path; @@ -759,6 +778,26 @@ format1(const struct stat *st, ofmt = FMTF_UNSIGNED; break; #endif /* HAVE_STRUCT_STAT_ST_GEN */ + case SHOW_realpath: + small = 0; + data = 0; + if (file == NULL) { + (void)strlcpy(path, "(stdin)", sizeof(path)); + sdata = path; + } else { + snprintf(path, sizeof(path), " -> "); + if (realpath(file, path + 4) == NULL) { + linkfail = 1; + l = 0; + path[0] = '\0'; + } + sdata = path + (ofmt == FMTF_STRING ? 0 : 4); + } + + formats = FMTF_STRING; + if (ofmt == 0) + ofmt = FMTF_STRING; + break; case SHOW_symlink: small = 0; data = 0; @@ -784,24 +823,23 @@ format1(const struct stat *st, case SHOW_filetype: small = 0; data = 0; - sdata = smode; - sdata[0] = '\0'; + sdata = ""; if (hilo == 0 || hilo == LOW_PIECE) { switch (st->st_mode & S_IFMT) { - case S_IFIFO: (void)strcat(sdata, "|"); break; - case S_IFDIR: (void)strcat(sdata, "/"); break; + case S_IFIFO: sdata = "|"; break; + case S_IFDIR: sdata = "/"; break; case S_IFREG: if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) - (void)strcat(sdata, "*"); + sdata = "*"; break; - case S_IFLNK: (void)strcat(sdata, "@"); break; - case S_IFSOCK: (void)strcat(sdata, "="); break; + case S_IFLNK: sdata = "@"; break; + case S_IFSOCK: sdata = "="; break; #ifdef S_IFWHT - case S_IFWHT: (void)strcat(sdata, "%"); break; + case S_IFWHT: sdata = "%"; break; #endif /* S_IFWHT */ #ifdef S_IFDOOR - case S_IFDOOR: (void)strcat(sdata, ">"); break; + case S_IFDOOR: sdata = ">"; break; #endif /* S_IFDOOR */ } hilo = 0; @@ -832,7 +870,7 @@ format1(const struct stat *st, case SHOW_filename: small = 0; data = 0; - (void)strncpy(path, file, sizeof(path)); + (void)strlcpy(path, file, sizeof(path)); sdata = path; formats = FMTF_STRING; if (ofmt == 0) @@ -907,8 +945,9 @@ format1(const struct stat *st, (void)snprintf(tmp, sizeof(tmp), "%d", size); (void)strcat(lfmt, tmp); } - (void)strcat(lfmt, "d"); - return (snprintf(buf, blen, lfmt, ts.tv_sec)); + (void)strcat(lfmt, "lld"); + return (snprintf(buf, blen, lfmt, + (long long)ts.tv_sec)); } /* @@ -931,7 +970,8 @@ format1(const struct stat *st, (void)snprintf(tmp, sizeof(tmp), "%d", size); (void)strcat(lfmt, tmp); } - (void)strcat(lfmt, "d"); + /* Seconds: time_t cast to long long. */ + (void)strcat(lfmt, "lld"); /* * The stuff after the decimal point always needs zero @@ -942,8 +982,10 @@ format1(const struct stat *st, /* * We can "print" at most nine digits of precision. The * rest we will pad on at the end. + * + * Nanoseconds: long. */ - (void)snprintf(tmp, sizeof(tmp), "%dd", prec > 9 ? 9 : prec); + (void)snprintf(tmp, sizeof(tmp), "%dld", prec > 9 ? 9 : prec); (void)strcat(lfmt, tmp); /* @@ -957,8 +999,8 @@ format1(const struct stat *st, * Use the format, and then tack on any zeroes that * might be required to make up the requested precision. */ - l = snprintf(buf, blen, lfmt, ts.tv_sec, ts.tv_nsec); - for (; prec > 9 && l < blen; prec--, l++) + l = snprintf(buf, blen, lfmt, (long long)ts.tv_sec, ts.tv_nsec); + for (; prec > 9 && l < (int)blen; prec--, l++) (void)strcat(buf, "0"); return (l); }