Single-instance daemons

J

Jeffrey Barish

As per Stevens/Rago, "file and record locking provides a convenient
mutual-exclusion mechanism". They note the convention of putting the lock
file in /var/run in a file called <name>.pid, where <name> is the name of
the daemon and content is the pid. Seems like a good suggestion as I see
pid files from many other daemons there. However, /var/run is owned by
root, so it is not possible to write in it without root permission. I
could put the pid file in /tmp, but doing so would make it harder to find.
I could write a C program to write the lock file that takes command-line
arguments for passing the name of the daemon and the pid and give the
executable suid root, but that's a lot of bother. Has anyone else dealt
with this problem?
 
J

Jeff McNeil

As per Stevens/Rago, "file and record locking provides a convenient
mutual-exclusion mechanism". They note the convention of putting the lock
file in /var/run in a file called <name>.pid, where <name> is the name of
the daemon and content is the pid. Seems like a good suggestion as I see
pid files from many other daemons there. However, /var/run is owned by
root, so it is not possible to write in it without root permission. I
could put the pid file in /tmp, but doing so would make it harder to find.
I could write a C program to write the lock file that takes command-line
arguments for passing the name of the daemon and the pid and give the
executable suid root, but that's a lot of bother. Has anyone else dealt
with this problem?

Sure, start the daemon as root, write the appropriate files, and then
drop permissions using os.setegid and then os.seteuid. You can chown
the file before priv. drop to your target user so that it can be
removed when your exit handlers run. Alternatively, you can reclaim
root at cleanup as it's stored as your saved UID.

I've stopped dealing with most of the daemon specifics (session,
process group, forking & dropping TTY, PID file locations, etc...).
Each time I need to write a daemon process these days, I usually just
fall back to writing a twistd plugin. That takes care of everything
for me.
 
J

Jeffrey Barish

Jeff said:
Sure, start the daemon as root, write the appropriate files, and then
drop permissions using os.setegid and then os.seteuid. You can chown
the file before priv. drop to your target user so that it can be
removed when your exit handlers run.  Alternatively, you can reclaim
root at cleanup as it's stored as your saved UID.

Nice. One thing: how do I get the uid and gid for the target user? In
general, I know the name of the target user, but the uid/gid assigned by
the OS to that user could be different on different systems.
 
J

Jeffrey Barish

Cameron said:
Or, more simply, get root to make an empty pid file once and chown it to
the daemon user. Then the daemon can rewrite the file as needed. You need
to move to truncating the file instead of removing it on daemon shutdown,
but that is trivial. And no mucking with privileges, like starting the
daemon as root instead of directly as the daemon user, need be done.

Although the file locking that I described is happening during boot (which I
did not make clear), so I believe that the user is root already.
Accordingly, I need to drop privileges to a user anyway. Still, I like
your suggestion, so I'll remember it for another occasion.
 
I

Irmen de Jong

Jeffrey said:
Nice. One thing: how do I get the uid and gid for the target user? In
general, I know the name of the target user, but the uid/gid assigned by
the OS to that user could be different on different systems.

pwd.getpwnam
grp.getgrnam

--irmen
 
Ð

Дамјан ГеоргиевÑки

As per Stevens/Rago, "file and record locking provides a convenient
mutual-exclusion mechanism".

On linux (at least) there's one nice trick to get a single-instance
program. Create a unix domain socket, and bind it to an address that
begins with the null character '\0'. You can bind the same address a
second time, and if the process dies the socket is automatically
destroyed. It will not leave anything on the filesystem.

def single_instance(id):
import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
s.bind('\0' + id)
return s
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top