File descriptor redirection stuck

The example daemon class I am implementing uses descriptor redirection.

sys.stdout.flush()                       
sys.stderr.flush()                       
si = file(self.stdin, 'r')               
so = file(self.stdout, 'a+')             
se = file(self.stderr, 'a+', 0)          
os.dup2(si.fileno(), sys.stdin.fileno()) 
os.dup2(so.fileno(), sys.stdout.fileno()) # This line doesn't work
os.dup2(se.fileno(), sys.stderr.fileno())

      

os.dup2(so.fileno(), sys.stdout.fileno())

does not work. It throws no errors. The code after this line is not executed.

I've simplified this example so that the class only contains the problem area:

class Deamon(object):
    def __init__(self, pidfile, stdout='/dev/null'):
        self.pidfile = pidfile
        self.stdout = stdout
    def get_stdout(self):
        so = file(self.stdout, 'a+')
        os.dup2(so.fileno(), sys.stdout.fileno())
        print 'executed'

      

Following the os.dup2(so.fileno(), sys.stdout.fileno())

code just got stuck. Why is this happening?

Edit (with code implementation @ C2H5OH):

    try:                                                           
        pid = os.fork()                                            
        if pid > 0:                                                
            # exit first parent                                    
            sys.exit(0)                                            
    except OSError, e:                                             
        sys.stderr.write(                                          
                'fork #1 failed: %d (%s)\n' % (e.errno, e.stderror)
                )                                                  
        sys.exit(1)                                                

    os.chdir("/")                                                  
    os.setsid()                                                    
    os.umask(0)                                                    


    try:                                                           
        pid = os.fork()                                            
        if pid > 0:                                                
            # exit from second parent                              
            sys.exit(0)                                            
    except OSError, e:                                             
        sys.stderr.write(                                          
                "fork #2 failled: %d (%s)" % (e.errno, e.strrerror)
                )                                                  
        sys.exit(1)                                                

    # redirect standart file descriptors                           
    os.setsid()                                                    
    sys.stdin.flush()                                              
    sys.stdout.flush()                                             
    sys.stderr.flush()                                             

    dev_null = os.open(os.devnull, os.O_RDWR)                      
    os.dup2(dev_null, sys.stdin.fileno())                          
    print 'executed 1'                                             
    os.dup2(dev_null, sys.stdout.fileno())                         
    print 'executed 2'                                             
    os.dup2(dev_null, sys.stderr.fileno())                         
    os.close(dev_null)    

    # write pidfile
    # FIXME: file is not writes!                     
    atexit.register(self.delpid)                
    pid = str(os.getpid())                      
    file(self.pidfile, 'w+').write("%s\n" % pid)

      

In the method stop

, I have an example from self.pidfile

existing:

def stop(self):                  
    print file(self.pidfile, 'r')

      

This throws an error:

IOError: [Errno 2] No such file or directory: '/tmp/deamon-example.pid'

The problem is still there.

+3


source to share


2 answers


You mix Python file descriptors with operating system file descriptors, this creates problems.

While you are using os.dup2()

redirection sys.stdout

(since direct assignment may not work completely if other modules are referenced to it), you must open files at the operating system level with os.open()

.

Here's the daemonization code we use in my workplace:



if os.fork() > 0:
    os._exit(0)
os.setsid()
sys.stdin.flush()
sys.stdout.flush()
sys.stderr.flush()
null = os.open(os.devnull, os.O_RDWR)
os.dup2(null, sys.stdin.fileno())
os.dup2(null, sys.stdout.fileno())
os.dup2(null, sys.stderr.fileno())
os.close(null)

      

If you want to redirect stdout to some file, just use a different filename instead of the predefined constant os.devnull

.

+4


source


http://docs.python.org/library/os.html#os.dup2

The above documentation says: os.dup2(fd, fd2) Duplicate file descriptor fd to fd2, closing the latter first if necessary.

So this line: os.dup2(so.fileno(), sys.stdout.fileno())

apparently closes sys.stdout

, which effectively disables all output. The code looks "stuck", but you just can't see anything. that is, there are no errors.



Also, you redirect stdout to /dev/null

anyway:

def __init__(self, pidfile, stdout='/dev/null'):
    #...
    self.stdout = stdout         # <--self.stdout points to /dev/null
def get_stdout(self):
    so = file(self.stdout, 'a+') # <-- opening /dev/null for append?
    # even if the next line worked, you're appending to /dev/null and you wouldn't see any output
    os.dup2(so.fileno(), sys.stdout.fileno()) 

      

+3


source







All Articles