RedHat daemon function usage
To answer the question you guess that you have, is that --pidfile
is used to check whether the daemon process is already running. On RHEL (and derivates) the daemon
function won't write the pidfile.
In the case that the program stays in the foreground it has to be explicitly sent to the background by appending &
to the command and the pid has to be fetched afterwards. $!
is not usable when using daemon
.
Demon function on RHEL 7
This file is provided by the initscripts
package, which isn't included by default in the RHEL-7 image. It is however in the RHEL6 image.
In el6, it's brought in as a dependency for iproute and iputils, where in el7, systemd meet this need.
Call to daemon in a /etc/init.d script is blocking, not running in background
I finally re-wrote the start function in the bash init script, and I am not using daemon
anymore.
start() {
echo -n "Starting $pname : "
#daemon ${exe} # Not working ...
if [ -s ${pidfile} ]; then
RETVAL=1
echo -n "Already running !" && warning
echo
else
nohup ${exe} >/dev/null 2>&1 &
RETVAL=$?
PID=$!
[ $RETVAL -eq 0 ] && touch ${lockfile} && success || failure
echo
echo $PID > ${pidfile}
fi
}
I check that the pid file is not existing already (if so, just write a warning). If not, I use
nohup ${exe} >/dev/null 2>&1 &
to start the script.
I don't know if it is safe this way (?) but it works.
Creating a daemon in Linux
In Linux i want to add a daemon that cannot be stopped and which monitors filesystem changes. If any changes would be detected it should write the path to the console where it was started + a newline.
Daemons work in the background and (usually...) don't belong to a TTY that's why you can't use stdout/stderr in the way you probably want.
Usually a syslog daemon (syslogd) is used for logging messages to files (debug, error,...).
Besides that, there are a few required steps to daemonize a process.
If I remember correctly these steps are:
- fork off the parent process & let it terminate if forking was successful. -> Because the parent process has terminated, the child process now runs in the background.
- setsid - Create a new session. The calling process becomes the leader of the new session and the process group leader of the new process group. The process is now detached from its controlling terminal (CTTY).
- Catch signals - Ignore and/or handle signals.
- fork again & let the parent process terminate to ensure that you get rid of the session leading process. (Only session leaders may get a TTY again.)
- chdir - Change the working directory of the daemon.
- umask - Change the file mode mask according to the needs of the daemon.
- close - Close all open file descriptors that may be inherited from the parent process.
To give you a starting point: Look at this skeleton code that shows the basic steps. This code can now also be forked on GitHub: Basic skeleton of a linux daemon
/*
* daemonize.c
* This example daemonizes a process, writes a few log messages,
* sleeps 20 seconds and terminates afterwards.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
static void skeleton_daemon()
{
pid_t pid;
/* Fork off the parent process */
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* On success: The child process becomes session leader */
if (setsid() < 0)
exit(EXIT_FAILURE);
/* Catch, ignore and handle signals */
//TODO: Implement a working signal handler */
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
/* Fork off for the second time*/
pid = fork();
/* An error occurred */
if (pid < 0)
exit(EXIT_FAILURE);
/* Success: Let the parent terminate */
if (pid > 0)
exit(EXIT_SUCCESS);
/* Set new file permissions */
umask(0);
/* Change the working directory to the root directory */
/* or another appropriated directory */
chdir("/");
/* Close all open file descriptors */
int x;
for (x = sysconf(_SC_OPEN_MAX); x>=0; x--)
{
close (x);
}
/* Open the log file */
openlog ("firstdaemon", LOG_PID, LOG_DAEMON);
}
int main()
{
skeleton_daemon();
while (1)
{
//TODO: Insert daemon code here.
syslog (LOG_NOTICE, "First daemon started.");
sleep (20);
break;
}
syslog (LOG_NOTICE, "First daemon terminated.");
closelog();
return EXIT_SUCCESS;
}
- Compile the code:
gcc -o firstdaemon daemonize.c
- Start the daemon:
./firstdaemon
Check if everything is working properly:
ps -xj | grep firstdaemon
The output should be similar to this one:
+------+------+------+------+-----+-------+------+------+------+-----+
| PPID | PID | PGID | SID | TTY | TPGID | STAT | UID | TIME | CMD |
+------+------+------+------+-----+-------+------+------+------+-----+
| 1 | 3387 | 3386 | 3386 | ? | -1 | S | 1000 | 0:00 | ./ |
+------+------+------+------+-----+-------+------+------+------+-----+
What you should see here is:
- The daemon has no controlling terminal (TTY = ?)
- The parent process ID (PPID) is 1 (The init process)
- The PID != SID which means that our process is NOT the session leader
(because of the second fork()) - Because PID != SID our process can't take control of a TTY again
Reading the syslog:
- Locate your syslog file. Mine is here:
/var/log/syslog
Do a:
grep firstdaemon /var/log/syslog
The output should be similar to this one:
firstdaemon[3387]: First daemon started.
firstdaemon[3387]: First daemon terminated.
A note:
In reality you would also want to implement a signal handler and set up the logging properly (Files, log levels...).
Further reading:
- Linux-UNIX-Programmierung - German
- Unix Daemon Server Programming
Linux daemon start up
Put 2 comments into your script:
# chkconfig: - 90 10
# description: description of your service
As root, run :
chkconfig --add my_service
How to run a command as a specific user in an init script?
On RHEL systems, the /etc/rc.d/init.d/functions
script is intended to provide similar to what you want. If you source that at the top of your init script, all of it's functions become available.
The specific function provided to help with this is daemon
. If you are intending to use it to start a daemon-like program, a simple usage would be:
daemon --user=username command
If that is too heavy-handed for what you need, there is runuser
(see man runuser
for full info; some versions may need -u
prior to the username):
/sbin/runuser username -s /bin/bash -c "command(s) to run as user username"
Related Topics
Lowest Latency Notification Method Between Process Under Linux
Coreos - Get Docker Container Name by Pid
Which Stack Is Used by Interrupt Handler - Linux
How to Make Sure the Floating Point Arithmetic Result the Same in Both Linux and Windows
Changing the PHPmyadmin Default Url
Cannot Sudo Su Anymore, "No Tty Present and No Askpass Program Specified"
Grep String Inside Double Quotes
Null Modem Emulator (Com0Com) for Linux
How to Identify Multiple Usb-Serial Adapters Under Ubuntu 10.1
Searching Multiple Patterns (Words) with Ack
Git Bash Is Displaying Strange Characters on Windows 7
What's the Best Way to Find a String/Regex Match in Files Recursively? (Unix)
Running Shell Script Using .Env File
Command to Zip a Directory Using a Specific Directory as the Root
Automatically Kill Process That Consume Too Much Memory or Stall on Linux
Bash And/Or .Bashrc Not Working Properly After Su or Ssh Login Unless Run "Bash" Command