Question

In the daemon class example, which I implement, is used descriptors redirecting.

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()) is not working. It doesn't raise errors. The code after this line is not executed.

I simplified this example to the class contains only 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'

After os.dup2(so.fileno(), sys.stdout.fileno()) code just stuck. Why is it happening?

Edit (with @C2H5OH code implementation):

    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 stop method I have try-out of self.pidfile existing:

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

This is raise an error:

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

The problem is still in there.

Was it helpful?

Solution

You are mixing Python file handles with the operating system file descriptors, this is asking for trouble.

While you are correct on using os.dup2() to redirect sys.stdout (because direct assignment may not completely work, if other modules acquired a reference to it), you should open files at the operating system level with os.open().

Here's the daemonization code we use at 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 file name instead of the predefined constant os.devnull.

OTHER TIPS

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

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()) is apparently closing sys.stdout which effectively shuts down all output. The code appears 'stuck', but you're just not seeing any output. i.e., there are no errors.

On top of that, you're redirecting 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()) 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top