Re: how to redirect in bash+crontab
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
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
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
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
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
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
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
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
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
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
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