Re: how to redirect in bash+crontab

2012-07-24 Thread Amos Shapira
For the platforms which use a pipe for /dev/stderr try running fuser to see
what else has it open. I suspect it would be something like a mail
process initiated by cron.

In general, /dev/stderr is not a standard, not portable and IMHO shouldn't
be relied on.

The shell does exactly what is expected - the special case you ask for is
the 2 syntax and /dev/stderr is a hack to let you treat stderr as a
regular file.

I don't see what needs to be changed except the curiosity of /dev/stderr
not working any more, it might also be related to /dev being a special file
system which could create entries dynamically (sorry, I'm writing this from
home, I might remember to test this on our work servers tomorrow).

--Amos

On 24 July 2012 18:52, Oleg Goldshmidt p...@goldshmidt.org wrote:

 Hi,

 I thought I'd share an observation that was, I admit, new to me - and I
 thought I had plenty of experience. And then I have a question or two.

 I moved a bunch of scripts to a new computer (RHEL 5.4 - CentOS 6.2).
 They work, but I noticed weird permission denied messages in the mails
 cron sends. Turns out that I had functions wrapping real bash code in
 progress messages that produce output like

 Doing XYZ ... done [or Doing XYZ ... failed, or whatever is appropriate]

 Since the real output was sometimes redirected to files these messages are
 sent to stderr.

 Surprise! It all worked for years on RHEL 5.4. On CentOS 6.2, however, it
 works flawlessly from the command line, but NOT from crontab! At least
 stuff like

 echo fubar  /dev/stderr

 does not. At the same time,

 echo fubar 2

 works perfectly both interactively and through crontab. [The functional
 part of the scripts works fine - the errors come from those progress
 messages, but it's immaterial here.]

 On RHEL 5.4, CentOS 6.2, and Fedora 15 (my laptop) /dev/stderr is a
 symlink to /proc/self/fd/2 (which is what you'd expect). I wrote a little
 script that prints ls -nld and ls -nldL of /proc/self/fd/2 as well as
 the real and effective user and group IDs of the process, and ran the
 script interactively and from crontab on all three systems. Here is what I
 discovered.

 RHEL 5.4 (my uid is 500 and my gid is 500, gid 5 is tty):

 ---

 interactive:
 lrwx-- 1 500 500 64 Jul 24 10:39 /proc/self/fd/2 - /dev/pts/1
 crw--w 1 500 5 136, 1 Jul 24 10:39 /proc/self/fd/2

 crontab:
 l-wx-- 1 500 500 64 Jul 24 10:40 /proc/self/fd/2 - pipe:[27443942]
 prw--- 1 500 500 0 Jul 24 10:40 /proc/self/fd/2 # [OG] I am the owner!

 CentOS 6.2 (my uid is 500, gid is 501, group 5 is tty again):

 --

 interactive:
 lrwx-- 1 500 501 64 Jul 24 10:39 /proc/self/fd/2 - /dev/pts/0
 crw--w 1 500 5 136, 0 Jul 24 10:39 /proc/self/fd/2

 crontab:
 l-wx-- 1 500 501 64 Jul 24 10:27 /proc/self/fd/2 - pipe:[3750679]
 prw--- 1 0 501 0 Jul 24 10:27 /proc/self/fd/2 # [OG] the owner is
 root! I can't write to it!

 Fedora 15 (my uid is 500, gid is 500, gid 5 is tty):

 

 interactive:
 lrwx-- 1 500 500 64 Jul 24 11:08 /proc/self/fd/2 - /dev/pts/2
 crw--- 1 500 5 136, 2 Jul 24 11:08 /proc/self/fd/2

 crontab:
 l-wx-- 1 500 500 64 Jul 24 10:37 /proc/self/fd/2 - pipe:[47022]
 prw--- 1 0 500 0 Jul 24 10:37 /proc/self/fd/2 # [OG] the owner is
 root! I can't write to it!

 So, when run from crontab stderr is actually a pipe. On RHEL 5.4 the pipe
 belongs to the actual user and is writeable. On 6.2 and Fedora the pipe
 belongs to root and is not writeable by the user.

 When run interactively, stderr is linked to a character device (tty) that
 is writeable by the user. For some reason, on Fedora the device is not
 writeable by group tty, while on RHEL/CentOS it is.

 I think I understand WHAT is happening, e.g., redirecting to /dev/stderr
 causes the system to check the file/fifo permissions against the effective
 uid and since they are insufficient, fail. At the same time, doing 2 does
 not cause checking filesystem permissions, and hence works. I did strace in
 both cases and /dev/stderr does open(2) and then dup2(2), whereas 2
 does only dup2(2).

 However, I have a lingering feeling that both redirections should work the
 same. I expect them to be functionally equivalent (though maybe it's naive
 of me). I also do not understand WHY the behaviour changed.

 Is it a bug? If so, is it a kernel bug (it creates the /proc hierarchy,
 right?) or a cron bug (faulty effective id?) or a bash bug (should
 /dev/stderr be handled specially)? Were there (security?) reasons to change
 the ownership of the pipe (and permissions on the character tty device in
 Fedora, while we are at it)?

 Until it is resolved one way or another it looks like 2 is much
 preferable to /dev/stderr. I find it 

Re: how to redirect in bash+crontab

2012-07-24 Thread Nadav Har'El
On Tue, Jul 24, 2012, Oleg Goldshmidt wrote about how to redirect in 
bash+crontab:
 Is it a bug? If so, is it a kernel bug (it creates the /proc hierarchy,
 right?) or a cron bug (faulty effective id?) or a bash bug (should
 /dev/stderr be handled specially)? Were there (security?) reasons to change
 the ownership of the pipe (and permissions on the character tty device in
 Fedora, while we are at it)?

This is a very interesting analysis, which I've never considered before.

With pipes, we can perhaps argue the owner is wrong - that we're talking
about a fake file so Linux could have invented a different owner for
it.
However, there's an even bigger problem I think: Consider a situation
where /proc/self/fd/2 points not to a pipe, but to an on-disk file:

This file may belong to another user - it could have been passed to the
current process by inheritance, or over a unix-domain socket or
whatever. The current process *is* able to use the file descriptor, but
it won't be able to open /proc/self/fd/2. And this can't even be fixed
because the file this points to has certain owner and permission bits,
and the kernel can't mess with those (like it theoretically could with the
fake pipe file in your example).

I do think this is a logic bug, and the reason why it came to be is,
I believe, the following:

Old versions of Unix following 8th Edition Research Unix had a similar
feature called /dev/fd/... (see http://man.cat-v.org/unix_8th/4/fd).
There was a small, but for your purpose very important, difference
between how /dev/fd worked then, and how /proc/self/fd/... works in
Linux. /dev/fd/2 wasn't a symbolic link (symbolic links were new to
Unix at the time, and were not commonly used in any case). It was a
special device (you had just 127 of them). When any process open()ed
this device, the open would always succeed - the manual specified that
open(/dev/fd/n, mode) is identical to dup(n). No additional permission
testing would be done. /dev/fd/2 (and the identical /dev/stderr) would
work exactly like you wanted.

Linux deviated from this implementation for several reasons, one of them
being that is a cool feature to do ls -l /proc/self/fd and see the
names of all the open files. (there are several other important reasons
that we can discuss if you want). This alternative implementation broke
the correct behavior that Unix's /dev/fd/2 had - as you discovered.

I don't know if Linux should be fixed at this point, as so much water
has passed under the bridge since Unix implemented /dev/stderr
correctly. I think /dev/stderr (and stdin, stdout) at least could
easily have been fixed - even if the rest of /proc/fd is more difficult
to fix.

But I think it's important that this caveat is documented in proc(5),
explaining how open(/proc/self/fd/n) differs from from dup(n) (2 in
your example of course uses dup(2)). Unfortunately, last time I sent
a bug report to the Linux manual pages project I was ignored, so I don't
know how successful you'll be if you try.

 Until it is resolved one way or another it looks like 2 is much
 preferable to /dev/stderr. I find it quite unexpected. I actually like
 /dev/stderr better since it is less cryptic.

I remember when I learned Unix, it took me a while to understand what
the strange incantations like

something filename 21

actually did. But when I finally understood how it works (i.e., uses
dup(2)), I never had any problem with this syntax. And understanding
what these do is important, because the authors of CSH obviously didn't
and thus completely ruined that shell's redirection capabilities
(see the very first entry in
http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/ )


-- 
Nadav Har'El|  Tuesday, Jul 24 2012, 6 Av 5772
n...@math.technion.ac.il |-
Phone +972-523-790466, ICQ 13349191 |Don't accept your dog's admiration as
http://nadav.harel.org.il   |conclusive evidence that you're wonderful

___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Oleg Goldshmidt
On Tue, Jul 24, 2012 at 4:06 PM, Amos Shapira amos.shap...@gmail.comwrote:

 For the platforms which use a pipe for /dev/stderr try running fuser to
 see what else has it open. I suspect it would be something like a mail
 process initiated by cron.

 In general, /dev/stderr is not a standard, not portable and IMHO shouldn't
 be relied on.

 The shell does exactly what is expected - the special case you ask for
 is the 2 syntax and /dev/stderr is a hack to let you treat stderr as a
 regular file.


Well, I know of course that /dev/stderr is bash-specific and is not
(necessarily) portable to other shells. I did not care about that kind of
portability. The scripts are explicitly #!/bin/bash. In bash, redirecting
to /dev/stderr is well documented, and in fact man bash says

Bash handles several filenames specially when they are used in
redirections, as described in the following table:
...
  /dev/stderr
 File descriptor 2 is duplicated.

This is, in fact, not what happens, since, as I mentioned, there is a call
to open(2) before dup2(2) and permissions are checked at that stage (2
corresponds more closely to the above since it does dup2(2) directly). I
still suspect there is a bug somewhere because the process should be able
to write to its stderr even under cron (which is supposed to send whatever
was written to stderr by mail).

-- 
Oleg Goldshmidt | o...@goldshmidt.org
___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Oleg Goldshmidt
On Tue, Jul 24, 2012 at 6:50 PM, Nadav Har'El n...@math.technion.ac.ilwrote:


 This is a very interesting analysis, which I've never considered before.

 With pipes, we can perhaps argue the owner is wrong - that we're talking
 about a fake file so Linux could have invented a different owner for
 it.


Everything is a file, as we know, even a pipe. The ownership is important,
and was switched from (presumably) the euid to 0 at some point, causing the
described problem. I don't know why and I'd like to know. or maybe it's a
bug?


 However, there's an even bigger problem I think: Consider a situation
 where /proc/self/fd/2 points not to a pipe, but to an on-disk file:

 This file may belong to another user - it could have been passed to the
 current process by inheritance, or over a unix-domain socket or
 whatever. The current process *is* able to use the file descriptor, but
 it won't be able to open /proc/self/fd/2. And this can't even be fixed
 because the file this points to has certain owner and permission bits,
 and the kernel can't mess with those (like it theoretically could with the
 fake pipe file in your example).


Isn't it the same as redirecting stderr to a real file and finding out that
you don't have permissions to write to it?


 I do think this is a logic bug, and the reason why it came to be is,
 I believe, the following:

 Old versions of Unix following 8th Edition Research Unix had a similar
 feature called /dev/fd/... (see http://man.cat-v.org/unix_8th/4/fd).
 There was a small, but for your purpose very important, difference
 between how /dev/fd worked then, and how /proc/self/fd/... works in
 Linux. /dev/fd/2 wasn't a symbolic link (symbolic links were new to
 Unix at the time, and were not commonly used in any case). It was a
 special device (you had just 127 of them). When any process open()ed
 this device, the open would always succeed - the manual specified that
 open(/dev/fd/n, mode) is identical to dup(n). No additional permission
 testing would be done. /dev/fd/2 (and the identical /dev/stderr) would
 work exactly like you wanted.


[By this time I have already grabbed a copy of APUE from a colleague's desk
and found all of the above written there, including the statement that
/dev/stderr was equivalent to /dev/fd/2. In fact, if memory serves, in the
dark bygone days - possibly in the previous millennium - /dev/stderr used
to be a symlink to /dev/fd/2. My memory has been noticed to be faulty
occasionally in the past.]

This is exactly the difference - /dev/fd/2 was special and today's
/dev/stderr is not. I generally subscribe to the philosophy of having as
few special cases as possible, so treating /dev/stderr as a regular file
(with open(), etc) rather than as a special file actually appeals to my
sense of aesthetics. But then care should be taken not to fail where
failure is not expected - in this case, permissions should be right.

[There may, theoretically, be a good security reason why the pipe belongs
to root now, but I am not aware of any.]


 Linux deviated from this implementation for several reasons, one of them
 being that is a cool feature to do ls -l /proc/self/fd and see the
 names of all the open files. (there are several other important reasons
 that we can discuss if you want). This alternative implementation broke
 the correct behavior that Unix's /dev/fd/2 had - as you discovered.

 I don't know if Linux should be fixed at this point, as so much water
 has passed under the bridge since Unix implemented /dev/stderr
 correctly. I think /dev/stderr (and stdin, stdout) at least could
 easily have been fixed - even if the rest of /proc/fd is more difficult
 to fix.

 But I think it's important that this caveat is documented in proc(5),


And in bash(1), as I pointed out in my reply to Amos.



 I remember when I learned Unix, it took me a while to understand what
 the strange incantations like

 something filename 21

 actually did. But when I finally understood how it works (i.e., uses
 dup(2)), I never had any problem with this syntax.


I do not have any problem with the syntax. I do have to work with other
people and less experienced folks may - and do - have problems with the
admittedly rather arcane rules. Doing /dev/stderr is much clearer and
cleaner and readily readable and understandable (to say nothing of being
very similar to g?awk that is so often used together with shell scripts -
there /dev/stderr *is* treated specially). The desire to express myself
clearly and cause as little confusion as possible led me to prefer
/dev/stderr.


 And understanding
 what these do is important, because the authors of CSH obviously didn't
 and thus completely ruined that shell's redirection capabilities
 (see the very first entry in
 http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/ )


Don't start... ;-)


-- 
Oleg Goldshmidt | p...@goldshmidt.org o...@goldshmidt.org
___
Linux-il mailing list

Re: how to redirect in bash+crontab

2012-07-24 Thread Nadav Har'El
On Tue, Jul 24, 2012, Oleg Goldshmidt wrote about Re: how to redirect in 
bash+crontab:
 Isn't it the same as redirecting stderr to a real file and finding out that
 you don't have permissions to write to it?

No, this cannot happen. write(2) cannot fail because of permission
problems, only the open(2) can. Once a process has a file descriptor
it can write it even if it could never open the original file itself.

This is deliberate, and is often used - file descriptors are often
passed between processes belonging to different users, either from
parent to child (inheritance of file descriptors) or through UNIX-Domain
Sockets (see Ancillary Messages in unix(7)).

 This is exactly the difference - /dev/fd/2 was special and today's
 /dev/stderr is not. I generally subscribe to the philosophy of having as
 few special cases as possible, so treating /dev/stderr as a regular file
 (with open(), etc) rather than as a special file actually appeals to my
 sense of aesthetics. But then care should be taken not to fail where
 failure is not expected - in this case, permissions should be right.

Like I explained, they *can't* be done right (when right mean just like
dup(2) would work) when it comes to ordinary files (not pipes).

The only way to do this right, as far as I can see, is for /dev/stderr
and friends *not* to be symbolic links.

 [There may, theoretically, be a good security reason why the pipe belongs
 to root now, but I am not aware of any.]

I think it is meaningless security-wise, as the process already has the
file descriptor itself and can use it, no matter who /proc/self/fd/2
belongs to. But of course I could be wrong here.

  But I think it's important that this caveat is documented in proc(5),
 
 And in bash(1), as I pointed out in my reply to Amos.

Holy shit!

I just noticed that bash(1) claims that /dev/stderr doesn't actually
open a file called /dev/stderr - but just does dup(2). Either this is
not true, or you simply weren't using Bash - perhaps your crontab uses
dash or something else.

Nadav.

-- 
Nadav Har'El|  Tuesday, Jul 24 2012, 6 Av 5772
n...@math.technion.ac.il |-
Phone +972-523-790466, ICQ 13349191 |To decide or not to decide, that is the
http://nadav.harel.org.il   |question. Or is it?

___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Oleg Goldshmidt
On Tue, Jul 24, 2012 at 7:51 PM, Nadav Har'El n...@math.technion.ac.ilwrote:

 On Tue, Jul 24, 2012, Oleg Goldshmidt wrote about Re: how to redirect in
 bash+crontab:
  Isn't it the same as redirecting stderr to a real file and finding out
 that
  you don't have permissions to write to it?

 No, this cannot happen. write(2) cannot fail because of permission
 problems, only the open(2) can.


But you cannot write(2) before you open(2), can you?

Once a process has a file descriptor
 it can write it even if it could never open the original file itself.


Which s true for file descriptors (e.g., dup()), but to redirect to a file
you do need to open(2) the file, methinks.


   But I think it's important that this caveat is documented in proc(5),
 
  And in bash(1), as I pointed out in my reply to Amos.

 Holy shit!

 I just noticed that bash(1) claims that /dev/stderr doesn't actually
 open a file called /dev/stderr - but just does dup(2). Either this is
 not true, or you simply weren't using Bash - perhaps your crontab uses
 dash or something else.


Whatever crontab uses is irrelevant since all there is in crontab is the
name of a script that is explicitly #!/bin/bash (and al the scripts that
are called are explicitly bash as well).

Strictly speaking, man bash does not explicitly say it does not open()
/dev/stderr (it says it dup()s but does not say this is the only thing it
does). Nevertheless I think the documentation's intent is exactly that - no
open(), or at least ignoring mode during open(), consistent with the
/dev/fd/* behaviour as described by Stevens and everywhere else.

I would be curious to know how recent versions of
SuSE/debian/ubuntu/*BSD/Mac OS X/whatever implement /dev/stderr.

-- 
Oleg Goldshmidt | p...@goldshmidt.org o...@goldshmidt.org
___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Nadav Har'El
On Tue, Jul 24, 2012, Oleg Goldshmidt wrote about Re: how to redirect in 
bash+crontab:
 But you cannot write(2) before you open(2), can you?
...
 Which s true for file descriptors (e.g., dup()), but to redirect to a file
 you do need to open(2) the file, methinks.

To write(2) you need a file descriptor, but there are many ways to get a
file descriptor besides open(2).

One very common way is to inherit a file descriptor from the parent
process - e.g., consider that a root-owned process opens a root-owned
file, and then forks and the child setuid() to nonroot. The child now
has an open file, which it can fully use, but could have never opened
himself. This is more-or-less how your crontab script got its output file
descriptor - it never open()ed any file.

A process can also acquire an open file descriptor from a local server
(potentially running with the permissions of another user) by using a
little known (but very important) feature of Unix-Domain sockets -
again, see unix(7) for the whole story.

But the end result is that it isn't all that rare for a process to have
access to a file descriptor it couldn't have opened on its own.
A new attempt to open this file through the symbolic link in
/proc/self/fd/2 would now fail, but were /dev/fd/2 implemented as a
device, not a magic directory like in Linux, it would have worked - but
you'd have lost the ability to learn with readlink(2) what is opened on
this file descriptor.


 Whatever crontab uses is irrelevant since all there is in crontab is the
 name of a script that is explicitly #!/bin/bash (and al the scripts that
 are called are explicitly bash as well).
 
 Strictly speaking, man bash does not explicitly say it does not open()
 /dev/stderr (it says it dup()s but does not say this is the only thing it
 does). Nevertheless I think the documentation's intent is exactly that - no
 open(), or at least ignoring mode during open(), consistent with the
 /dev/fd/* behaviour as described by Stevens and everywhere else.

Then this is clearly a bash *bug* - the manual explictly said that when
it sees redirection to /dev/fd/* or /dev/stderr etc., this file is
NOT actually used, but rather, quoting the manual, File descriptor 2 is
duplicated. dup(2) can never fail with EACCES - it will succeed no
matter who opened file descriptor 2. If bash does open the real file
/dev/fd/* or /dev/stderr then this is clearly contrary to the
manual- so either the manual or implementation is wrong.

That being said, I hope they change the manual, not the implementation.
I don't see any reason why the shell needs to override /dev/stderr.
And if it overrides /dev/stderr, why stop there and not also override
writes to /dev/tty, or reads from /dev/urandom, or whatever?

 I would be curious to know how recent versions of
 SuSE/debian/ubuntu/*BSD/Mac OS X/whatever implement /dev/stderr.

Last time I checked BSD, Solaris, and other Unix variants, /dev/stderr
was a character-special device, not a symlink. Sadly, I no longer have
access to any non-Linux Unix-like operating system, so I can't check
now.

-- 
Nadav Har'El|  Tuesday, Jul 24 2012, 6 Av 5772
n...@math.technion.ac.il |-
Phone +972-523-790466, ICQ 13349191 |God is dead. - Nietzsche; Nietzsche is
http://nadav.harel.org.il   |dead - God

___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Geoff Shang

On Tue, 24 Jul 2012, Oleg Goldshmidt wrote:


I would be curious to know how recent versions of
SuSE/debian/ubuntu/*BSD/Mac OS X/whatever implement /dev/stderr.


Debian 6.0 (current stable):
lrwxrwxrwx 1 root root 15 Jun 18 16:37 /dev/stderr - /proc/self/fd/2
lrwx-- 1 root root 64 Jul 24 23:50 /proc/self/fd/2 - /dev/tty5
crw--- 1 root tty 4, 5 Jul 24 23:53 /dev/tty5

I was on tty5 at the time.

Mac OS X 10.7 (Lion):
lr-xr-xr-x  1 root  wheel  0 Jun 18 16:33 /dev/stderr - fd/2
crw--w  1 geoff  tty   16,   0 Jul 24 23:50 /dev/fd/2

I was logged in over an SSH connection for this one, so decided to look at 
a Debian (Stable) box that I was also SSH'd into:


lrwxrwxrwx 1 root root 15 Apr 28 07:46 /dev/stderr - /proc/self/fd/2
lrwx-- 1 mintfm mintfm 64 Jul 24 21:53 /proc/self/fd/2 - /dev/pts/0
crw--w 1 mintfm tty 136, 0 Jul 24 21:55 /dev/pts/0

Guess which TTY I was logged in on.

HTH,
Geoff.


___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Oleg Goldshmidt
Nadav Har'El n...@math.technion.ac.il writes:

 No, this cannot happen. write(2) cannot fail because of permission
 problems, only the open(2) can. 

Actually, if the file was not open for writing write(2) will return
EBADF. ;-)

While there are, indeed, many ways to acquire a fd the normal case,
e.g., for

echo fubar  $HOME/tmp/myfakestdout

(this is same as my redirecton, only with a real file on a disk)
involves an open() call and a dup2(3,1) (assuming open() returns 3).

If you do not have write permissions on the file open() will return
EACCESS and you will see Permission denied on your stderr stream. 

 Like I explained, they *can't* be done right (when right mean just
 like dup(2) would work) when it comes to ordinary files (not pipes).

 The only way to do this right, as far as I can see, is for
 /dev/stderr and friends *not* to be symbolic links.

Sorry, I don't really see what symlinks have to do with it. I think
/dev/stderr and friends have been symlinks since forever (even Stevens
says so, and, sadly, he passed away years ago), and everything worked
just fine when

* /dev/stderr was a symlink to /dev/fd/2
* /dev/stderr is a symlink to a tty character device
* /dev/stderr was a symlink to a pipe with appropiate ownership

The problem *only* occurs when /dev/stderr is a symlink to a pipe
owned by a different user (root, specifically), and while group
ownership is appropriate there is no group write permission.

I think the symlink and pipe parts are irrelevant, as is the
using open() part - these are just implementation details. After
all, even for the good old /dev/fd/2 there was an open() call, the
special implementation part was that the mode argument was ignored.

Incidentally, if I read Stevens right this had nothing to do with bash
- the behaviour would be the same if you opened /dev/fd/* in your
own code as well. Or if you opened /dev/stderr in your own code. As
far as I understand this special treatment was built into open(2).

I didn't immediately see anything special in the logic of, say,
do_filp_open() in the kernel's fs/namei.c. As far as I could see
symlinks are followed unil resolved (the branch labeled do_link) and
then the real work is done (the do_last label). At some point there
is a check for special_file (in do_dentry_open() in fs/open.c) but
this checks whether the file is a character device or a block device
or a pipe or a socket and seems intended for some sort of bookkeeping
rather than actively ignoring the mode (which would not sound
logical). Not sure - too tired.

As I mentioned before, doing nothing special would be, in fact,
elegant, but then it shouldn't fail... ;-)

I am inclined to suspect that the pipe that the kernel creates has
wrong ownership/permissions, and if/when that is fixed everything will
be sane again.

-- 
Oleg Goldshmidt | p...@goldshmidt.org

___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Oleg Goldshmidt
Geoff Shang ge...@quitelikely.com writes:

 On Tue, 24 Jul 2012, Oleg Goldshmidt wrote:

 I would be curious to know how recent versions of
 SuSE/debian/ubuntu/*BSD/Mac OS X/whatever implement /dev/stderr.

 Debian 6.0 (current stable):
 lrwxrwxrwx 1 root root 15 Jun 18 16:37 /dev/stderr - /proc/self/fd/2
 lrwx-- 1 root root 64 Jul 24 23:50 /proc/self/fd/2 - /dev/tty5
 crw--- 1 root tty 4, 5 Jul 24 23:53 /dev/tty5

 I was on tty5 at the time.

As root or as a regular user?

Also, this is in an interactive session. How about crontab?
 

 Mac OS X 10.7 (Lion):
 lr-xr-xr-x  1 root  wheel  0 Jun 18 16:33 /dev/stderr - fd/2
 crw--w  1 geoff  tty   16,   0 Jul 24 23:50 /dev/fd/2

Aha! A symlink to /dev/fd/2... ;-)


 I was logged in over an SSH connection for this one, so decided to
 look at a Debian (Stable) box that I was also SSH'd into:

 lrwxrwxrwx 1 root root 15 Apr 28 07:46 /dev/stderr - /proc/self/fd/2
 lrwx-- 1 mintfm mintfm 64 Jul 24 21:53 /proc/self/fd/2 - /dev/pts/0
 crw--w 1 mintfm tty 136, 0 Jul 24 21:55 /dev/pts/0

What's the difference between this Debian stable and the first one?

At least the tty group permissions seem to be a bit clearer. On a
Fedora box I am logged into right now the first 7 ttys (0...6) belong to
root:root and are 600 (consoles?), while the rest belong to root:tty
and are 620. With pseudo-terminals it *seems* that remote sessions are
620 whle local are 600:

crw--w 1 oleg tty  136, 0 Jul 23 20:52 /dev/pts/0
crw--- 1 oleg tty  136, 1 Jul 25 01:33 /dev/pts/1

Thanks,

-- 
Oleg Goldshmidt | p...@goldshmidt.org

___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il


Re: how to redirect in bash+crontab

2012-07-24 Thread Nadav Har'El
On Wed, Jul 25, 2012, Oleg Goldshmidt wrote about Re: how to redirect in 
bash+crontab:
 While there are, indeed, many ways to acquire a fd the normal case,
 e.g., for
 
 echo fubar  $HOME/tmp/myfakestdout

But this is NOT your use case!

In your use case you did

echo fubar  /dev/stderr

not to a specific file. I'm not suggesting you should change it to a
specific file. However, what I *am* suggesting, is that this /dev/stderr
may actually point not to a pipe or terminal, but to a file. I.e., your
parent process redirected standard error to a file. In that case, your
/dev/stderr will be a symlink to an ordinary file - with its ordinary
owner and permission - not to a fake pipe file like you saw.

  Like I explained, they *can't* be done right (when right mean just
  like dup(2) would work) when it comes to ordinary files (not pipes).
 
  The only way to do this right, as far as I can see, is for
  /dev/stderr and friends *not* to be symbolic links.
 
 Sorry, I don't really see what symlinks have to do with it. I think
 /dev/stderr and friends have been symlinks since forever (even Stevens
 says so, and, sadly, he passed away years ago), and everything worked

Forever is a relative term ;-) I didn't look at Stevens, but unless I
remember wrong (and it's completely possible), /dev/fd/2 is only a link
on *Linux*, and wasn't a symlink on any other Unix variant - including
Solaris to which I had acess to just a few years ago (and sadly, no
more).

I don't know why, according to your experiments, the owner of that fake
pipe file were changed recently. I don't know if this change makes any
sense. But what I'm trying to say is that even if they didn't change
this, you could have had exactly the same problem if your parent process
redirected your standard error to a file, rather than a pipe.

 just fine when
 
 * /dev/stderr was a symlink to /dev/fd/2

This is of course fine. This intermediate symlink is not your problem.

 * /dev/stderr is a symlink to a tty character device
 * /dev/stderr was a symlink to a pipe with appropiate ownership

Do you agree that /dev/stderr is not *always* a symlink to a *pipe*?
It is only a symlink to a pipe in your specific example, because the
parent process redirected your stderr to a pipe. It could have
redirected your stderr to anything else - a terminal, a pipe, etc.
The permission change which you noticed with the pipes, while very
strange (and indeed deserving explanation... did you look at the code?) 
is only part of the bigger problem.

 I think the symlink and pipe parts are irrelevant, as is the
 using open() part - these are just implementation details. After
 all, even for the good old /dev/fd/2 there was an open() call, the
 special implementation part was that the mode argument was ignored.

Right - for devices, open() is done specially. For symlinks it can't.

 Incidentally, if I read Stevens right this had nothing to do with bash
 - the behaviour would be the same if you opened /dev/fd/* in your
 own code as well. Or if you opened /dev/stderr in your own code. As
 far as I understand this special treatment was built into open(2).

Not into open(2), but rather into the device driver. Each device driver
implements open() its own way.

 I didn't immediately see anything special in the logic of, say,
 do_filp_open() in the kernel's fs/namei.c. As far as I could see
 symlinks are followed unil resolved (the branch labeled do_link) and
 then the real work is done (the do_last label). At some point there
 is a check for special_file (in do_dentry_open() in fs/open.c) but
 this checks whether the file is a character device or a block device
 or a pipe or a socket and seems intended for some sort of bookkeeping
 rather than actively ignoring the mode (which would not sound
 logical). Not sure - too tired.

There's no relation between the mode (which is basically - whether you
wanted to open the file for reading and writing) and permission check
(owner, group, etc.). Permission check was also done on /dev/fd/2
when it was a character device, but it will always succeed because this
file was simply created world-readable and world-writable. Opening it
would never fail because of permission problems, because it shouldn't
just like dup() never fails on permission problems.

 I am inclined to suspect that the pipe that the kernel creates has
 wrong ownership/permissions, and if/when that is fixed everything will
 be sane again.

Unless crontab starts directing stderr to /var/log/messages or something
instead of a pipe :-)

-- 
Nadav Har'El|Wednesday, Jul 25 2012, 6 Av 5772
n...@math.technion.ac.il |-
Phone +972-523-790466, ICQ 13349191 |Time is the best teacher. Unfortunately
http://nadav.harel.org.il   |it kills all its students.

___
Linux-il mailing list
Linux-il@cs.huji.ac.il
http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il