You are not logged in.
I finally adopted my first AUR package (mediatomb) and am looking for advice with regards to some packaging best practices.
First: creating users and groups
Other distributions create a mediatomb user and group for use with MediaTomb's daemon mode (and the MediaTomb developers appear to recommend this practice). However, I could find no guideline with respect to user creation. Yes, I understand how I would go about calling groupadd and useradd in an .install script, but what UID and GID should be assigned to the new user and group? The majority of daemons use IDs in the 100s range, whilst regular users are found in the 1000s. How is one to select an appropriate ID and avoid conflict?
I am aware of DeveloperWiki:UID / GID Database, but it seems largely incomplete. What is the general consensus? (I was considering claiming ID 151.)
Second: daemon scripts
The best resource I could find was Writing rc.d scripts, but I would appreciate some clarification. The rc.d script I inherited from the previous maintainer included a check to ensure it was run as root, whereas I see no "official" daemons follow this practice. Is there any particular reason to avoid such checks, or is this simply another KISS idea?
Also, the majority of scripts determine the process ID by calling "pidof" whereas a small minority use "cat $PIDFILE". I opted for a mix of the two: "pidof" will report whether any mediatomb instances are running on the system, whereas "cat $PIDFILE" is specific to the daemon. I imagine some users may run both a daemon instance and another instance as another user. Is there any reason to use one method over another, or simply "whatever works?"
Finally, a minor consistency issue: the majority of daemon scripts "exit 0" at the end, but a handful do not. Should they?
Third: FHS
The sample MediaTomb daemon scripts provided by the developers (for Fedora and Optware) use /etc/mediatomb as the default config directory (which is where the database is created). I opted to use /var/lib/mediatomb instead, but the default configuration will then create both the database and configuration file under /var/lib/mediatomb. Which is the lesser evil (database in /etc or config in /var)?
Thanks in advance for any wisdom you care to share.
Last edited by pointone (2010-04-09 15:04:49)
M*cr*s*ft: Who needs quality when you have marketing?
Offline
Also, the majority of scripts determine the process ID by calling "pidof" whereas a small minority use "cat $PIDFILE". I opted for a mix of the two: "pidof" will report whether any mediatomb instances are running on the system, whereas "cat $PIDFILE" is specific to the daemon. I imagine some users may run both a daemon instance and another instance as another user. Is there any reason to use one method over another, or simply "whatever works?"
This is a can of worms. Either method may work most of the time in practice, but neither counts as best practice.
Finally, a minor consistency issue: the majority of daemon scripts "exit 0" at the end, but a handful do not. Should they?
Without that, they'll finish with the exit code of the most-recently executed command, which will normally also be 0. If it might be non-zero, but you want the script to exit 0 anyway, say so explicitly. I bet in a lot of scripts the "exit 0" is not strictly necessary.
The sample MediaTomb daemon scripts provided by the developers (for Fedora and Optware) use /etc/mediatomb as the default config directory (which is where the database is created). I opted to use /var/lib/mediatomb instead, but the default configuration will then create both the database and configuration file under /var/lib/mediatomb. Which is the lesser evil (database in /etc or config in /var)?
I think the least evil is to change the sample scripts to put things in their right place. The "don't touch upstream!" pressure seems weaker for daemon scripts and config files.
Offline
Thanks for responding; that's essentially what I expected.
The developers don't provide a default configuration file, which is why I didn't include one in /etc. Instead, the software generates a config file (and database) on first run, but only in the specified cfg directory. Hence, either both config and db in /etc or /var. Thinking about it, I believe it will probably be cleaner if I simply generate a config file on my system and include _that_ in the package instead. Problem solved.
Any comment with respect to UIDs/GIDs? That is what I'm most concerned about.
M*cr*s*ft: Who needs quality when you have marketing?
Offline
I don't know. I'd guess that just adding the uids/gids you want to claim to that wiki page would be the way to go.
Offline
I have a question and instead of creating a new thread I'll just use this one because it's relevant to the topic.
The question is - How would you go about creating a daemon script that executes a shell script, php script or a python script?
This is what I have got so far:
#!/bin/bash
. /etc/rc.conf
. /etc/rc.d/functions
case "$1" in
start)
stat_busy "Starting socket bootstrap"
su -c 'sh /srv/sockets/socket-bootstrap.sh' root
add_daemon socket-bootstrap
stat_done
;;
stop)
stat_busy "Stopping socket bootstrap"
/usr/bin/killall su -c 'sh /srv/sockets/socket-bootstrap.sh' root
if [ $? -gt 0 ]; then
stat_fail
else
rm_daemon socket-bootstrap
stat_done
fi
;;
*)
echo "usage: $0 {start|stop}"
esac
exit 0
What happens is that the socket-bootstrap.sh (which contains a loop which keeps some sockets opened) gets runned like if I ran the sh command in the terminal. What I mean by that is that once the start command is sent to the daemon it starts the file but instead of "daemonizing" it, the file gets runned like if I just wrote "sh /srv/sockets/socket-bootstrap.sh". And then obviously the killall command doesn't work on stop either.
Any ideas?
Offline
What happens is that the socket-bootstrap.sh (which contains a loop which keeps some sockets opened) gets runned like if I ran the sh command in the terminal. What I mean by that is that once the start command is sent to the daemon it starts the file but instead of "daemonizing" it, the file gets runned like if I just wrote "sh /srv/sockets/socket-bootstrap.sh". And then obviously the killall command doesn't work on stop either.
Any ideas?
Don't use su here, it's pointless. Just assume the script is run by root. If it's run by a normal user, it'll just fail, and the user should notice his error.
If the daemon does not daemonize by itself, send it to the background by appending &, just like you would on the terminal. But in this case you won't know whether it has started successfully... see below.
You're trying to killall su, see killall(1). And you can't just killall sh, either... that'll likely kill a lot more processes than you intend.
You should base your rc scripts on /usr/share/pacman/rc-script.proto. The problem is that this proto is not suited for running scripts (sh, ruby, python) as daemons.
Here's a script for a ruby daemon, based on the proto and adjusted as commented:
#!/bin/bash
daemon_name=beepd
. /etc/rc.conf
. /etc/rc.d/functions
get_pid() {
# we can't use pidof here, since the command is 'ruby' and not $daemon_name.
# using pgrep with an exact match on the complete commandline, see pgrep(1)
pgrep -u root -x -f 'ruby /sbin/beepd'
}
case "$1" in
start)
stat_busy "Starting $daemon_name daemon"
PID=$(get_pid)
if [[ -z "$PID" ]]; then
[ -f /var/run/$daemon_name.pid ] && rm -f /var/run/$daemon_name.pid
# RUN
# instead of just running and checking the return value in $?, we send
# the script to the background to "daemonize" it:
$daemon_name &
#
# and then use get_pid instead of $? to check if it has started successfully...
if ! get_pid &>/dev/null; then
stat_fail
exit 1
else
echo $(get_pid) > /var/run/$daemon_name.pid
add_daemon $daemon_name
stat_done
fi
else
stat_fail
exit 1
fi
;;
stop)
stat_busy "Stopping $daemon_name daemon"
PID=$(get_pid)
# KILL
[ ! -z "$PID" ] && kill $PID &> /dev/null
#
if [ $? -gt 0 ]; then
stat_fail
exit 1
else
rm -f /var/run/$daemon_name.pid &> /dev/null
rm_daemon $daemon_name
stat_done
fi
;;
restart)
$0 stop
sleep 3
$0 start
;;
status)
stat_busy "Checking $daemon_name status";
ck_status $daemon_name
;;
*)
echo "usage: $0 {start|stop|restart|status}"
esac
exit 0
Offline
text
Thank you for explaining! I adapted your example, but I got an error saying "/etc/rc.d/socket-bootstrap: rad 23: socket-bootstrap: command doesn't exist". I guess it tries to start a command named socket-bootstrap just because I used that as daemon_name. I guess I have to link socket-bootstrap to run "sh /srv/sockets/sockets-bootstrap.sh" or something like that?
#!/bin/bash
daemon_name=socket-bootstrap
. /etc/rc.conf
. /etc/rc.d/functions
get_pid() {
# we can't use pidof here, since the command is 'ruby' and not $daemon_name.
# using pgrep with an exact match on the complete commandline, see pgrep(1)
pgrep -u root -x -f 'sh /srv/sockets/socket-bootstrap.sh'
}
case "$1" in
start)
stat_busy "Starting $daemon_name daemon"
PID=$(get_pid)
if [[ -z "$PID" ]]; then
[ -f /var/run/$daemon_name.pid ] && rm -f /var/run/$daemon_name.pid
# RUN
# instead of just running and checking the return value in $?, we send
# the script to the background to "daemonize" it:
$daemon_name &
#
# and then use get_pid instead of $? to check if it has started successfully...
if ! get_pid &>/dev/null; then
stat_fail
exit 1
else
echo $(get_pid) > /var/run/$daemon_name.pid
add_daemon $daemon_name
stat_done
fi
else
stat_fail
exit 1
fi
;;
etc etc etc
Last edited by ancide (2010-05-21 11:36:28)
Offline
Basically, yes. Note that my script assumes that a) daemon_name == script filename and b) the script is chmod'ed +x and on PATH. I.e. it can be run by typing beepd & in a terminal.
In your case, I'd just run your script with
sh /srv/sockets/socket-bootstrap.sh &
instead of
$daemon_name &
in the start) section.
Last edited by hbekel (2010-05-21 12:50:54)
Offline
Basically, yes. Note that my script assumes that a) daemon_name == script filename and b) the script is chmod'ed +x and on PATH. I.e. it can be run by typing beepd & in a terminal.
In your case, I'd just run your script with
sh /srv/sockets/socket-bootstrap.sh &
instead of
$daemon_name &
in the start) section.
Alright, that makes sense.
And then how would I stop that background process? Could I use
kill `pgrep sh /srv/sockets/socket-bootstrap.sh &`
or something like that?
Offline
Please read the script. All's well once get_pid works.
Offline
Any comment with respect to UIDs/GIDs? That is what I'm most concerned about.
On the developerwiki there is a list of those, with what they should be used for. But I'm not sure how it works for packages in community/aur, etc
< Daenyth> and he works prolifically
4 8 15 16 23 42
Offline
Please read the script. All's well once get_pid works.
Yes, I've read the script. The reason I asked is because it doesn't work. The process is still running in the background after stop. If I do start, then stop and then start again I get a error saying "[Errno 98] Address already in use" since my socket script is already running in the background.
Offline
Does "stop" report fail? Have you checked whether the pgrep command retrieves the right pid? If so, have you tried to kill that pid from the commandline? Does that work?
Your line:
kill `pgrep sh /srv/sockets/socket-bootstrap.sh &`
is wrong. & is not part of the commandline as seen by ps. Have you read man pgrep? There's a reason it needs those options in get_pid.
Offline
Does "stop" report fail? Have you checked whether the pgrep command retrieves the right pid? If so, have you tried to kill that pid from the commandline? Does that work?
Your line:kill `pgrep sh /srv/sockets/socket-bootstrap.sh &`
is wrong. & is not part of the commandline as seen by ps. Have you read man pgrep? There's a reason it needs those options in get_pid.
Stop seems to report fail and pgrep doesn't get the right pid.
The thing is that I just want to run one python file which has a loop where it listens to socket connections. And I want to run that in the background as a daemon. I'm notfamiliar with bash and best practises in terms of creating daemons, packages and what not. So maybe it's easier if I just show you my three files.
Here's my rc.d file (/etc/rc.d/chaos-service):
#!/bin/bash
daemon_name=chaos-service
. /etc/rc.conf
. /etc/rc.d/functions
get_pid() {
pgrep -u root -x -f 'python /usr/lib/chaos-service/bootstrap.py'
}
case "$1" in
start)
stat_busy "Starting $daemon_name daemon"
PID=$(get_pid)
if [[ -z "$PID" ]]; then
[ -f /var/run/$daemon_name.pid ] && rm -f /var/run/$daemon_name.pid
$daemon_name &
if ! get_pid &>/dev/null; then
stat_fail
exit 1
else
echo $(get_pid) > /var/run/$daemon_name.pid
add_daemon $daemon_name
stat_done
fi
else
stat_fail
exit 1
fi
;;
stop)
stat_busy "Stopping $daemon_name daemon"
PID=$(get_pid)
[ ! -z "$PID" ] && kill $PID &> /dev/null
if [ $? -gt 0 ]; then
stat_fail
exit 1
else
rm -f /var/run/$daemon_name.pid &> /dev/null
rm_daemon $daemon_name
stat_done
fi
;;
restart)
$0 stop
sleep 3
$0 start
;;
status)
stat_busy "Checking $daemon_name status";
ck_status $daemon_name
;;
*)
echo "usage: $0 {start|stop|restart|status}"
esac
exit 0
Here's my python file (/usr/lib/chaos-service/bootstrap.py):
#!/usr/bin/python
while True:
print 'Parsing socket'
Then I have /usr/bin/chaos-service which is just empty because I wasn't sure what to do with it. If I was going to invoke the python command in that file or inte rc.d file.
Right now when I do /etc/rc.d/chaos-service start I get fail.
I really appreciate your help, because I am totally lost.
Last edited by ancide (2010-05-22 11:56:15)
Offline
Replace "$daemon_name &" on line 17 of the rc-script with "python /usr/lib/chaos-service/bootstrap.py &".
This will give you a "daemon" that prints "Parsing socket" forever... (hint)
I suggest you try to read and understand the rc script... As a python programmer, you should be able to guess, or find out by reading a bash tutorial, googling, etc. You won't get this to work if you lack the most basic understanding of bash, daemons, pgrep, etc... I've given you more than enough information and help already... You'll get better help if you ask smart questions. Don't be a help vampire. No offense, but it's getting tedious...:)
Offline
Replace "$daemon_name &" on line 17 of the rc-script with "python /usr/lib/chaos-service/bootstrap.py &".
This will give you a "daemon" that prints "Parsing socket" forever... (hint)
I suggest you try to read and understand the rc script... As a python programmer, you should be able to guess, or find out by reading a bash tutorial, googling, etc. You won't get this to work if you lack the most basic understanding of bash, daemons, pgrep, etc... I've given you more than enough information and help already... You'll get better help if you ask smart questions. Don't be a help vampire. No offense, but it's getting tedious...:)
Thanks.
Why I wrote in this thread is because I didn't find any information about creating a daemon for archlinux except for this thread and the wiki-page. Basically this was my last resort after many trial and errors and trying to find more information. I thought that the forum was created for this reason, to get help when you have tried your best and gotten stuck.
Anyway, thanks for your feedback, I'll try harder next time.
Offline