From nobody@FreeBSD.org  Sat Apr 28 19:18:27 2007
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 2641C16A400
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 28 Apr 2007 19:18:27 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [69.147.83.33])
	by mx1.freebsd.org (Postfix) with ESMTP id 149C013C46E
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 28 Apr 2007 19:18:27 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l3SJIQ6r049080
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 28 Apr 2007 19:18:26 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id l3SJDPLm048416;
	Sat, 28 Apr 2007 19:13:25 GMT
	(envelope-from nobody)
Message-Id: <200704281913.l3SJDPLm048416@www.freebsd.org>
Date: Sat, 28 Apr 2007 19:13:25 GMT
From: Jan Schaumann<jschauma@netmeister.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: touch(1)ing a directory and failing yields return code 0
X-Send-Pr-Version: www-3.0

>Number:         112213
>Category:       bin
>Synopsis:       [patch] touch(1)ing a directory and failing yields return code 0
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Apr 28 19:20:05 GMT 2007
>Closed-Date:    Sun Mar 28 11:36:59 UTC 2010
>Last-Modified:  Sun Mar 28 11:36:59 UTC 2010
>Originator:     Jan Schaumann
>Release:        
>Organization:
>Environment:
>Description:
When using touch(1) on a directory that I can't update the timestamp on
(say, if the filesystem is mounted read-only), it will return 0 as the
return value, even though it failed.

The reason this happens is in touch.c#225:

    /* Try reading/writing. */
    if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode) &&
        rw(*argv, &sb, fflag))
            rval = 1;
    else
            warn("%s", *argv);

At this point, it tries to update the timestamp using utimes(2), which
failed, so it would continue to try to update it by reading and writing
the file.

However, since the file in question is a directory, it doesn't try this
and simply warns instead of setting the return value to 1.
>How-To-Repeat:
$ mkdir foo
$ touch foo/bar
$ mount -u -o ro /
$ touch foo/bar
touch: foo/bar: Read-only file system
$ echo $?
1
$ touch foo
touch: foo: Read-only file system
$ echo $?
0
$
>Fix:
See NetBSD's touch(1):

                /* Try reading/writing. */
                if (!S_ISLNK(sb.st_mode) && rw(*argv, &sb, fflag))
                        rval = 1;


This still is slightly suboptimal, since the error message will be

$ touch foo
touch: foo: Is a directory
$ echo $?
1
$ 

But that's better than returning 0.
>Release-Note:
>Audit-Trail:

From: Jaakko Heinonen <jh@saunalahti.fi>
To: bug-followup@FreeBSD.org, jschauma@netmeister.org
Cc:  
Subject: Re: bin/112213: touch(1)ing a directory and failing yields return
	code 0
Date: Tue, 10 Jun 2008 18:38:30 +0300

 The if statement you are referring to seems to be incorrect.
 
    202			/* Try reading/writing. */
    203			if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode) &&
    204			    rw(*argv, &sb, fflag))
    205				rval = 1;
    206			else
    207				warn("%s", *argv);
 
 rval is correctly set to 1 if rw() fails but if rw() succeeds a bogus
 warning is printed. Secondly rval is not set at all when *argv is a
 symbolic link or directory. (It should be set because earlier attempts
 to set times failed.)
 
 I think that the following patch fixes the bug and it definitely fixes
 the case you gave:
 
 $ touch foo/bar ; echo $?
 touch: foo/bar: Read-only file system
 1
 $ touch foo ; echo $?
 touch: foo: Read-only file system
 1
 
 
 
 Index: usr.bin/touch/touch.c
 ===================================================================
 --- usr.bin/touch/touch.c	(revision 179703)
 +++ usr.bin/touch/touch.c	(working copy)
 @@ -222,11 +222,13 @@
  			continue;
  
  		/* Try reading/writing. */
 -		if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode) &&
 -		    rw(*argv, &sb, fflag))
 +		if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode)) {
 +			if (rw(*argv, &sb, fflag))
 +				rval = 1;
 +		} else {
  			rval = 1;
 -		else
  			warn("%s", *argv);
 +		}
  	}
  	exit(rval);
  }
Responsible-Changed-From-To: freebsd-bugs->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Mon Oct 12 13:28:27 UTC 2009 
Responsible-Changed-Why:  
Take. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=112213 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/112213: commit references a PR
Date: Fri, 16 Oct 2009 20:52:58 +0000 (UTC)

 Author: jh
 Date: Fri Oct 16 20:52:45 2009
 New Revision: 198175
 URL: http://svn.freebsd.org/changeset/base/198175
 
 Log:
   - If lstat()/stat() fails with an error other than ENOENT, don't ignore
     the error and assume that the file doesn't exist. Touch could return
     success with -c option even if the file existed and time was not set.
   - If the first utimes_f() call fails with -A option, give up and don't
     continue trying to set times to current time. [1]
   - Set exit status to 1 when setting of timestamps fails for a directory
     or symbolic link even though lstat()/stat() would succeed.
   - Don't print bogus error message when rw() succeeds.
   
   PR:		bin/112213
   Submitted by:	jilles [1]
   Reviewed by:	jilles
   Approved by:	trasz (mentor)
 
 Modified:
   head/usr.bin/touch/touch.c
 
 Modified: head/usr.bin/touch/touch.c
 ==============================================================================
 --- head/usr.bin/touch/touch.c	Fri Oct 16 19:30:48 2009	(r198174)
 +++ head/usr.bin/touch/touch.c	Fri Oct 16 20:52:45 2009	(r198175)
 @@ -164,6 +164,11 @@ main(int argc, char *argv[])
  	for (rval = 0; *argv; ++argv) {
  		/* See if the file exists. */
  		if (stat_f(*argv, &sb) != 0) {
 +			if (errno != ENOENT) {
 +				rval = 1;
 +				warn("%s", *argv);
 +				continue;
 +			}
  			if (!cflag) {
  				/* Create the file. */
  				fd = open(*argv,
 @@ -206,7 +211,7 @@ main(int argc, char *argv[])
  			continue;
  
  		/* If the user specified a time, nothing else we can do. */
 -		if (timeset) {
 +		if (timeset || Aflag) {
  			rval = 1;
  			warn("%s", *argv);
  			continue;
 @@ -222,11 +227,13 @@ main(int argc, char *argv[])
  			continue;
  
  		/* Try reading/writing. */
 -		if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode) &&
 -		    rw(*argv, &sb, fflag))
 +		if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode)) {
 +			if (rw(*argv, &sb, fflag))
 +				rval = 1;
 +		} else {
  			rval = 1;
 -		else
  			warn("%s", *argv);
 +		}
  	}
  	exit(rval);
  }
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: jh 
State-Changed-When: Fri Oct 16 21:06:50 UTC 2009 
State-Changed-Why:  
Patched in head (r198175). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=112213 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/112213: commit references a PR
Date: Sun, 28 Mar 2010 11:22:48 +0000 (UTC)

 Author: jh
 Date: Sun Mar 28 11:22:38 2010
 New Revision: 205790
 URL: http://svn.freebsd.org/changeset/base/205790
 
 Log:
   MFC r198175:
   
   - If lstat()/stat() fails with an error other than ENOENT, don't ignore
     the error and assume that the file doesn't exist. Touch could return
     success with -c option even if the file existed and time was not set.
   - If the first utimes_f() call fails with -A option, give up and don't
     continue trying to set times to current time. [1]
   - Set exit status to 1 when setting of timestamps fails for a directory
     or symbolic link even though lstat()/stat() would succeed.
   - Don't print bogus error message when rw() succeeds.
   
   PR:		bin/112213
 
 Modified:
   stable/8/usr.bin/touch/touch.c
 Directory Properties:
   stable/8/usr.bin/touch/   (props changed)
 
 Modified: stable/8/usr.bin/touch/touch.c
 ==============================================================================
 --- stable/8/usr.bin/touch/touch.c	Sun Mar 28 06:51:50 2010	(r205789)
 +++ stable/8/usr.bin/touch/touch.c	Sun Mar 28 11:22:38 2010	(r205790)
 @@ -164,6 +164,11 @@ main(int argc, char *argv[])
  	for (rval = 0; *argv; ++argv) {
  		/* See if the file exists. */
  		if (stat_f(*argv, &sb) != 0) {
 +			if (errno != ENOENT) {
 +				rval = 1;
 +				warn("%s", *argv);
 +				continue;
 +			}
  			if (!cflag) {
  				/* Create the file. */
  				fd = open(*argv,
 @@ -206,7 +211,7 @@ main(int argc, char *argv[])
  			continue;
  
  		/* If the user specified a time, nothing else we can do. */
 -		if (timeset) {
 +		if (timeset || Aflag) {
  			rval = 1;
  			warn("%s", *argv);
  			continue;
 @@ -222,11 +227,13 @@ main(int argc, char *argv[])
  			continue;
  
  		/* Try reading/writing. */
 -		if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode) &&
 -		    rw(*argv, &sb, fflag))
 +		if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode)) {
 +			if (rw(*argv, &sb, fflag))
 +				rval = 1;
 +		} else {
  			rval = 1;
 -		else
  			warn("%s", *argv);
 +		}
  	}
  	exit(rval);
  }
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jh 
State-Changed-When: Sun Mar 28 11:36:58 UTC 2010 
State-Changed-Why:  
Fixed in head and stable/8. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=112213 
>Unformatted:
