Redirect stdout & stderr (similar to a daemon)

T

Tsai Li Ming

Dear all,

I have a problem with a redirecting stdout and stderr. I am a top level
module and has no control over the imported modules that are making
system calls such as os.system or popen2.* . I have tried the simplest
method of capturing stdout, stderr via:

saveout = sys.stdout
sys.stdout = file_obj

print 1 # works
os.system('w') # Doesn't work

sys.stdout = saveout
print 1 # Restored

------------------------------------------------

Therefore, I changed to the following method, similar
to a daemon. However, I couldn't find a way to restore back stdout and
stderr.

import os
import sys

stdin = '/dev/null'
stdout = '/tmp/out.txt'
stderr = stdout

# Doesn't work
saveout = sys.stdout

si = file(stdin, 'r')
so = file(stdout, 'a+')
se = file(stderr, 'a+', 0)

# Redirect standard file descriptors.
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())

# Gets written to /tmp/out.txt
os.system('no_such_command')
os.system('w')


# How to do restoration of stdout and stderr
os.system('w')
print "Hello there"

Many thanks
Liming
 
M

Mel Wilson

I have a problem with a redirecting stdout and stderr. I am a top level
module and has no control over the imported modules that are making
system calls such as os.system or popen2.* . I have tried the simplest
method of capturing stdout, stderr via:

saveout = sys.stdout
sys.stdout = file_obj

print 1 # works
os.system('w') # Doesn't work

I think the problem here is that os.system runs a
shell with its own new set of process parameters,
including its own stdin, stdout, etc.

I would try one of the os.exec's or os.spawn's here
instead.
[ ... ]
# Redirect standard file descriptors.
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())

These modify the actual file objects represented by
'sys.stdin', etc. There's no coming back from that.

Regards. Mel.
 
T

Tsai Li Ming

Mel said:
Tsai Li Ming said:
I have a problem with a redirecting stdout and stderr. I am a top level
module and has no control over the imported modules that are making
system calls such as os.system or popen2.* . I have tried the simplest
method of capturing stdout, stderr via:

saveout = sys.stdout
sys.stdout = file_obj

print 1 # works
os.system('w') # Doesn't work


I think the problem here is that os.system runs a
shell with its own new set of process parameters,
including its own stdin, stdout, etc.

I would try one of the os.exec's or os.spawn's here
instead.

[ ... ]
# Redirect standard file descriptors.
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())


These modify the actual file objects represented by
'sys.stdin', etc. There's no coming back from that.

Regards. Mel.

I would think so too. Sadly, I can't use other system calls because I
will be importing other modules that I have no control of.

Liming
 
E

Eric S. Johansson

Tsai said:
Dear all,

I have a problem with a redirecting stdout and stderr. I am a top level
module and has no control over the imported modules that are making
system calls such as os.system or popen2.* . I have tried the simplest
method of capturing stdout, stderr via:

saveout = sys.stdout
sys.stdout = file_obj

print 1 # works
os.system('w') # Doesn't work

sys.stdout = saveout
print 1 # Restored

------------------------------------------------

Therefore, I changed to the following method, similar
to a daemon. However, I couldn't find a way to restore back stdout and
stderr.

if I understand what you're looking to do, I solved a similar problem by
pushing the redirection of standard out and standard error into the
command that I executed.

baseline_command ="somecommand 2> <temporary filename> 1> /dev/null"

and then on executing the command, standard I/O is redirected in the
child process which eliminates the need to manipulate it in your
program. The program fragment below should get you started. As you can
see, it executes the command and then if the error file is non zero
length, you retrieve the data and do something with it. The same
technique can be applied to standard out just as easily.

command_pipe = os.popen(command, "w")
command_pipe.write(trapped_message.as_string(1))
result = command_pipe.close()

if os.path.getsize(error_path) != 0:
for line in file(error_path).readlines():
log("command error %s"% line)
os.remove(error_path)

hope this is close to what you need
 
D

Donn Cave

Quoth (e-mail address removed) (Mel Wilson):
| In article <[email protected]>,
....
|> # Redirect standard file descriptors.
|> os.dup2(si.fileno(), sys.stdin.fileno())
|> os.dup2(so.fileno(), sys.stdout.fileno())
|> os.dup2(se.fileno(), sys.stderr.fileno())
|
| These modify the actual file objects represented by
| 'sys.stdin', etc. There's no coming back from that.

There is, if I understand what you meant by that. Consider

old0 = os.dup(0)
os.dup2(si.fileno(), 0)

The original input stream is held open on some arbitrary
unit, which you may use at any point to restore it to standard
input.

os.dup2(old0, 0)
os.close(old0)

Donn Cave, (e-mail address removed)
 
T

Tsai Li Ming

Donn said:
Quoth (e-mail address removed) (Mel Wilson):
| In article <[email protected]>,
...
|> # Redirect standard file descriptors.
|> os.dup2(si.fileno(), sys.stdin.fileno())
|> os.dup2(so.fileno(), sys.stdout.fileno())
|> os.dup2(se.fileno(), sys.stderr.fileno())
|
| These modify the actual file objects represented by
| 'sys.stdin', etc. There's no coming back from that.

There is, if I understand what you meant by that. Consider

old0 = os.dup(0)
os.dup2(si.fileno(), 0)

The original input stream is held open on some arbitrary
unit, which you may use at any point to restore it to standard
input.

os.dup2(old0, 0)
os.close(old0)

Donn Cave, (e-mail address removed)

Thanks Donn,

Why is there a need to close old0? Because of the extra file handle?

Liming
 
D

Donn Cave

Quoth Tsai Li Ming <[email protected]>:
| Donn Cave wrote:

| > There is, if I understand what you meant by that. Consider
| >
| > old0 = os.dup(0)
| > os.dup2(si.fileno(), 0)
| >
| > The original input stream is held open on some arbitrary
| > unit, which you may use at any point to restore it to standard
| > input.
| >
| > os.dup2(old0, 0)
| > os.close(old0)
| >
| > Donn Cave, (e-mail address removed)
|
| Thanks Donn,
|
| Why is there a need to close old0? Because of the extra file handle?

Good question. It's just barely conceivable that it could cause a
problem - say, where a child process redirects 0 but doesn't account
for the dup'd version, the parent exits, the file stays open when
it should have closed on exit, and something else has been depending
on that. To start with, most normal ways to fork a child process
will close all the extra files anyway, so this is highly improbable.

I would still do it, but it's more style than function.

Donn Cave, (e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top