Bcs515c Module 5
Bcs515c Module 5
MODULE 5
Signals and Daemon Processes
SIGNALS
➢ Signals are software interrupts.
➢ Signals provide a way of handling asynchronous events.
➢ When a signal is sent to a process, it is pending on the process to handle it. The process
can react to pending signals in one of three ways:
1. Accept the default action of the signal, which for most signals will terminate the
process.
2. Ignore the signal. The signal will be discarded and it has no affect whatsoever
on the recipient process.
3. Invoke a user-defined function. The function is known as a signal handler
routine and the signal is said to be caught when this function is called.
BIT, Mangalore 1
Unix System Programming BCS515C
user-defined signal Terminate
SIGUSR1
The following example attempts to catch the SIGINT signal and accepts the default action of
the SIGINT signal.
#include<stdio.h>
#include<iostream.h> #include<signal.h>
/*signal handler function*/ void catch_sig(int sig_num) {
BIT, Mangalore 2
Unix System Programming BCS515C
Printf(“I got signal no.:%d\n”,sig_num);
//cout<<”I got signal no.:”<<sig_num<<endl; signal
(SIGINT,SIG_DFL);
} int main() /*main
function*/
{
signal(SIGINT,catch_sig);
While(1);
}
#include<stdio.h> #include<signal.h>
/*signal handler function*/ static void sig_usr(int signo)
/* arg is signal number */
{ if (signo == SIGUSR1) printf("received SIGUSR1\n");
else if (signo == SIGUSR2) printf("received
SIGUSR2\n"); else printf("received signal %d\n", signo);
}
int main(void)
{ if (signal(SIGUSR1, sig_usr) == SIG_ERR) perror("can't catch
SIGUSR1"); if (signal(SIGUSR2, sig_usr) == SIG_ERR) perror("can't catch
SIGUSR2"); for ( ; ; ) pause();
}
$ ./[Link] &
[1] 7216
$ kill -USR1 7216 received SIGUSR1
$ kill -USR2 7216 received
SIGUSR2
$ kill 7216 start process in background job-control shell prints job
number and process ID send it SIGUSR1 send it SIGUSR2 now
send it SIGTERM now send it SIGTERM
When we send the SIGTERM signal, the process is terminated, since it doesn't catch the signal,
and the default action for the signal is termination.
BIT, Mangalore 3
Unix System Programming BCS515C
• The raise function allows a process to send a signal to itself. #include
<signal.h> int kill(pid_t pid, int signo); int raise(int signo);
Both return: 0 if OK, –1 on error
The call raise(signo); is equivalent to the call kill(getpid(),signo);
#include <signal.h> int
kill(pid_t pid, int signo);
There are four different conditions for the pid argument to kill.
Pid Meaning
value
Pid > 0 The signal is sent to the process whose process ID is pid.
Pid==-1 The signal is sent to all processes on the system for which the
sender has permission to send the signal.
Kill:
#include<iostream.h> #include<signal.h>
/*signal handler function*/ void catch_sig(int sig_num)
{
cout<<”catch_sig:”<<sig_num<<endl;
} int main() /*main
function*/
{ signal (SIGINT,catch_sig); cout<<“from
main\n”; kill(getpid(), SIGINT);
}
raise:
#include<iostream.h> #include<signal.h>
/*signal handler function*/ void catch_sig(int sig_num)
{
BIT, Mangalore 4
Unix System Programming BCS515C
cout<<”catch_sig:”<<sig_num<<endl;
} int main() /*main
function*/
{
signal (SIGQUIT,catch_sig); cout<<“from main\n”; raise(SIGQUIT); }
Pause():
The pause function suspends the calling process until a signal is caught.
#include <unistd.h>
int pause(void);
Returns: –1 with errno set to EINTR
The only time pause returns is if a signal handler is executed and that handler returns.
In that case, pause returns –1 with errno set to EINTR.
Using alarm and pause, we can put a process to sleep for a specified amount of time. The
sleep() can be implemented using alarm() and pause().
#include <signal.h> #include <unistd.h>
BIT, Mangalore 5
Unix System Programming BCS515C
}
SIGNAL SETS
• We need a data type to represent multiple signals—a signal set
POSIX.1 defines the data type sigset_t to contain a signal set and the following five
functions to manipulate signal sets. #include <signal.h> int sigemptyset(sigset_t*sigmask);
int sigfillset(sigset_t* sigmask); int sigaddset(sigset_t *sigmask, int signal_num ); int
sigdelset(sigset_t * sigmask, int signal_num ); Returns: 0 if OK, -1 on error.
int sigismember(const sigset_t*sigmask, int signal_num );
Returns: 1 if true, 0 if false, –1 on error int
sigemptyset(sigset_t*sigmask); int sigfillset(sigset_t*
sigmask);
int sigaddset(sigset_t *sigmask, int signal_num ); int
sigdelset(sigset_t * sigmask, int signal_num ); int
sigismember(const sigset_t *sigmask, int signal_num );
• The sigemptyset API clears all signal flags in the sigmask argument.
• The sigaddset API sets the flag corresponding to the signal_num signal in the sigmask
argument.
• The sigdelset API clears the flag corresponding to the signal_num signal in the sigmask
argument.
• The sigfillset API sets all the signal flags in the sigmask argument
• The sigismember will test a certain bit,API returns 1 if flag is set, 0 if not set
and -1 if the call fails.
SIGNAL MASK
• A process initially inherits the parent’s signal mask when it is created, but any pending
signals for the parent process are not passed on.
• A process may query or set its signal mask via the sigprocmask API: #include
<signal.h>
BIT, Mangalore 6
Unix System Programming BCS515C
int sigprocmask(int cmd,const sigset_t *new_mask,sigset_t *old_mask);
Returns: 0 if OK, -1 on error
• The new_mask argument defines a set of signals to be set or reset in a calling process
signal mask, and the cmd argument specifies how the new_mask value is to be used by
the API.
• The possible values of cmd and the corresponding use of the new_mask value are:
The following example checks whether the SIGINT signal is present in a process signal
mask and adds it to the mask if it is not there. Then clears the SIGSEGV signal from the
process signal mask.
The program prints the names of the signals in the signal mask of the calling
process
#include <stdio.h> #include <signal.h>
int main()
{ sigset_t sigset; sigemptyset(&sigset);
/*initialize set*/ if (sigprocmask(0, NULL, &sigset) < 0)
perror("sigprocmask error"); if (sigismember(&sigset,
SIGINT)) printf("SIGINT "); if (sigismember(&sigset,
SIGQUIT)) printf("SIGQUIT "); if (sigismember(&sigset,
BIT, Mangalore 7
Unix System Programming BCS515C
SIGUSR1)) printf("SIGUSR1 "); if (sigismember(&sigset,
SIGALRM)) printf("SIGALRM ");
}
SIGPENDING FUNCTION
The sigpending function returns the set of signals that are blocked from delivery and currently
pending for the calling process.
The set of signals is returned through the set argument
#include <signal.h> int
sigpending(sigset_t *set);
Returns: 0 if OK, –1 on error.
The program reports to the console whether the SIGTERM signal is pending for the
process
#include <stdio.h> #include <signal.h> int main()
{
int i;
sigset_t sigset; sigemptyset(&sigset);
/*initialize set*/ if (sigprocmask(0,
NULL, &sigset) < 0)
perror("sigprocmask error"); if
(sigispending(&sigset)==-1)
perror(“sigpending”); else
i=sigismemeber(&sigset,SIGTERM) ?1:0;
If(i==1) printf(“SIGTERM is set”); else
printf(“SIGTERM is not set”);
Sigaction() Function
➢ The sigaction() function allows us to examine or modify (or both) the action associated
with a particular signal.
➢ The sigaction API is a replacement for the signal API in the latest UNIX and POSIX
systems.
➢ The sigaction API is called by a process to set up a signal handling method for each
signal it wants to deal with.
➢ sigaction API returns the previous signal handling method for a given signal.
#include <signal.h>
BIT, Mangalore 8
Unix System Programming BCS515C
int sigaction(int signo, const struct sigaction *action, struct sigaction *oldaction); Returns:
0 if OK, –1 on error
➢ The signo argument designates which signal handling action is defined in the action
argument.
➢ The previous signal handling method for signo will be returned via the oldaction
argument if it is not a NULL pointer.
➢ If action argument is a NULL pointer, the calling
process‘s existing signal handling method for signo will be unchanged.
➢ The sa_handler field can be set to SIG_IGN, SIG_DFL, or a user defined signal
handler function.
➢ The sa_mask field specifies additional signals that process wishes to block when it is
handling signo signal.
#include <signal.h> #include <iostream.h> void callme ( int sig_num )
{
cout <<“catch signal:”<<sig_num<< endl;
} int
main(void)
{
sigset_t sigmask; struct sigaction action, old_action;
sigemptyset(&sigmask); if ( sigaddset( &sigmask,
SIGTERM) == -1 || sigprocmask( SIG_SETMASK,
&sigmask, 0) == -1)
➢ API will return the child’s exit status and process ID to the parent.
➢ Kernel will clear up the Process Table slot allocated for the child process.
➢ Parent process can call the waitpid API repeatedly to wait for each child it
created.
2. Parent ignores the SIGCHLD signal:
➢ SIGCHLD signal will be discarded.
➢ Parent will not be disturbed even if it is executing the waitpid system call.
➢ If the parent calls the waitpid API, the API will suspend the parent until all its
child processes have terminated.
➢ Child process table slots will be cleared up by the kernel.
➢ API will return a -1 value to the parent process.
3. Process catches the SIGCHLD signal:
➢ The signal handler function will be called in the parent process whenever a child
process terminates.
BIT, Mangalore 10
Unix System Programming BCS515C
➢ If the SIGCHLD arrives while the parent process is executing the waitpid
system call, the waitpid API may be restarted to collect the child exit status and
clear its process table slots.
➢ Depending on parent setup, the API may be aborted and child process table slot
not freed.
sigsetjmp AND siglongjmp APIs:
The function prototypes of the APIs are:
#include <setjmp.h> int
sigsetjmp(sigjmp_buf env, int savemask);
int siglongjmp(sigjmp_buf env, int val);
• The sigsetjmp and siglongjmp are created to support signal mask processing.
• The only difference between these functions and the setjmp and longjmp functions is
that sigsetjmp has an additional argument. If savemask is nonzero, then sigsetjmp also
saves the current signal mask of the process in env. When siglongjmp is called, if the
env argument was saved by a call to sigsetjmp with a nonzero savemask, then
siglongjmp restores the saved signal mask.
• The siglongjmp API is usually called from user-defined signal handling functions. This
is because a process signal mask is modified when a signal handler is called, and
siglongjmp should be called to ensure the process signal mask is restored properly when
“jumping out” from a signal handling function.
#include <signal.h>
#include <iostream.h>
#include<unistd.h>
#include<signal.h>
#include<setjmp.h>
sigjmp_buf env; void
callme ( int sig_num )
{ cout <<“catch signal:”<<sig_num<<
endl; siglongjump(env, 2);
} int
main(void)
{
sigset_t sigmask; struct sigaction action, old_action; sigemptyset(&sigmask); if ( sigaddset(
&sigmask, SIGTERM) == -1 || sigprocmask( SIG_SETMASK, &sigmask, 0)
== -1)
perror(“Set signal mask”); sigemptyset(
&action.sa_mask); sigaddset( &action.sa_mask,
BIT, Mangalore 11
Unix System Programming BCS515C
SIGSEGV); action.sa_handler = callme;
action.sa_flags = 0; if (sigaction (SIGINT, &action,
&old_action) == -1) perror(“sigaction”); if
(sigsetjmp(env,1)!=0) printf(“return from signal
interruption”); else printf(“return from first time
sigsetjmp is called”); pause(); /* wait for signal
interruption*/ return 0;
}
Execution:
$cc -o jmp sigsetlongjmp.c
$ jmp & [1]
499
return from first time sigsetjmp is called
$kill -INT 499 Catch
signal: 2
return from signal interruption
[1] Done
$
sigsuspend Function
sigset_t newmask, oldmask;
sigemptyset(&newmask); sigaddset(&newmask,
SIGINT);
/* block SIGINT and save current signal mask */ if
(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys("SIG_BLOCK error");
/* critical region of code */
/* reset signal mask, which unblocks SIGINT */ if
(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("SIG_SETMASK error");
/* window is open */ pause(); /* wait
for signal to occur */
/* continue processing */
BIT, Mangalore 12
Unix System Programming BCS515C
sigsuspend Function
• If the signal is sent to the process while it is blocked, the signal delivery will be deferred
until the signal is unblocked.
• What if the signal occurs between the unblocking and the pause If this happens, or if
the signal does occur between the unblocking and the pause, we have a problem. Any
occurrence of the signal in this window of time is lost in the sense that we might not
see the signal again, in which case the pause will block indefinitely.
• This is another problem with the earlier unreliable signals.
• To correct this problem, we need a way to both reset the signal mask and put the process
to sleep in a single atomic operation. This feature is provided by the sigsuspend
function.
• Normally, at the beginning of a critical code section, a specified set of signals is blocked
using the sigprocmask() function. When the thread has completed the critical section
and needs to wait for the previously blocked signal(s), it pauses by calling sigsuspend()
with the mask that was returned by the sigprocmask() call.
sigsuspend Function
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
Returns: 1 with errno set to EINTR
• sigsuspend() function shall replace the current signal mask of the calling thread with
the set of signals pointed to by sigmask and then suspend the thread until delivery of a
signal whose action is either to execute a signal-catching function or to terminate the
process.
• This shall not cause any other signals that may have been pending on the process to
become pending on the thread.
• If the action is to terminate the process then sigsuspend() shall never return. If the action
is to execute a signal-catching function, then sigsuspend() shall return after the
signalcatching function returns, with the signal mask restored to the set that existed
prior to the sigsuspend() call.
BIT, Mangalore 13
Unix System Programming BCS515C
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
/* Block SIGINT and save current signal mask.*/ if
(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys("SIG_BLOCK error"); /*Critical region of code.*/
pr_mask("in critical region: ");
/*Pause, allowing all signals except SIGUSR1.*/ if
(sigsuspend(&waitmask) != -1) err_sys("sigsuspend
error"); pr_mask("after return from sigsuspend: ");
/*Reset signal mask which unblocks SIGINT.*/ if
(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("SIG_SETMASK error"); /*And continue
processing ...*/ pr_mask("program exit: "); exit(0);
Abort Function
#include <stdlib.h> void
abort(void);
This function never returns
• abort function causes abnormal program termination.
• This function sends the SIGABRT signal to the caller. (Processes should not
ignore this signal.)
• ISO C states that calling abort will deliver an unsuccessful termination
notification to the host environment by calling raise(SIGABRT).
• But unlike the exit() function, abort() may not close files that are open. It may
also not delete temporary files and may not flush the stream buffer. Also, it does
not call functions registered with atexit().
Abort()Function
#include <stdio.h>
#include <stdlib.h> int
main()
{
FILE* fp = fopen("C:\\[Link]", "w");
if (fp == NULL) { printf("\n could
BIT, Mangalore 14
Unix System Programming BCS515C
not open file "); getchar();
exit(1);
}
fprintf(fp, "%s", “Hello ");
/* ....... */
/* ....... */
/* Something went wrong so terminate here */
abort(); return 0;
}
System Function
#include<stdlib.h> int system(const char *string)
Returns: This function returns 0 if the command is executed successfully. Otherwise, it returns
a non-zero value.
• Used to execute an operating system command specified by the string 'command' from
a c/c++ program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main() { // char
command[50];
//strcpy(command, “ls"); // Set the command to “ls" (list files and directories)
//system(command); //use the system fucntion to execute the command. system(“ls”);
Sleep Function
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
Returns: 0 or number of unslept seconds
• sleep() function in C allows the users to wait/suspend for a current thread for a specific
time in seconds.
• The sleep() function in C returns 0 if the requested time has elapsed.
#include <stdio.h>
#include <unistd.h>
void main()
{ printf("Program to sleep for 10 second in
Linux.\n"); sleep(10);
BIT, Mangalore 15
Unix System Programming BCS515C
// after 10 seconds this next line will be executed.
printf("This line will be executed after 10 second.");
}
Sleep Function
sleep function causes the calling process to be suspended until either
1. The amount of wall clock time specified by seconds has elapsed.
2. A signal is caught by the process and the signal handler returns.
• As with an alarm signal, the actual return may be at a time later than requested, because
of other system activity.
• In case 1, the return value is 0. When sleep returns early, because of some signal being
caught (case 2), the return value is the number of unslept seconds (the requested time
minus the actual time slept).
Nanosleep Function
#include <time.h>
int nanosleep(const struct timespec *t1, struct timespec *t2) Return
values: On successful execution, it returns the value 0 else it returns -1.
• tv_sec, which is the number of seconds.
• tv_nsec, which is the number of nanoseconds.
• It is used to suspend the execution of the program for a specific amount of time for
nanoseconds (1,000,000,000 or 1e+9 nanoseconds in a second).
#include <stdio.h>
#include <time.h> int
main()
{ struct timespec request, remaining = { 5, 100 };
printf("Taking a nap...\n"); int response = nanosleep(&request,
&remaining); if (response == 0) { printf("Nap was
Successful .\n"); } else { printf("Nap was
Interrupted.\n"); }
}
clock_nanosleep
#include <time.h>
BIT, Mangalore 16
Unix System Programming BCS515C
Like nanosleep(2), clock_nanosleep() allows the calling thread to sleep for an interval
specified with nanosecond precision. It differs in allowing the caller to select the clock against
which the sleep interval is to be measured, and in allowing the sleep interval to be specified as
either an absolute or a relative value.
The time values passed to and returned by this call are specified using timespec(3) structures.
The clockid argument specifies the clock against which the sleep interval is to be measured.
This argument can have one of the following values:
CLOCK_REALTIME
A settable system-wide real-time clock.
CLOCK_TAI (since Linux 3.10)
A system-wide clock derived from wall-clock time but counting leap seconds.
CLOCK_MONOTONIC
A nonsettable, monotonically increasing clock tha measures time since some unspecified
point in the pass that does not change after system startup.
CLOCK_BOOTTIME (since Linux 2.6.39)
Identical to CLOCK_MONOTONIC, except that it also includes any time that the system
is suspended.
CLOCK_PROCESS_CPUTIME_ID
A settable per-process clock that measures CPU time consumed by all threads in the process
If flags is 0, then the value specified in t is interpreted as an interval relative to the current value
of the clock specified by clockid.
If flags is TIMER_ABSTIME, then t is interpreted as an absolute time as measured by the
clock, clockid. If t is less than or equal to the current value of the clock, then clock_nanosleep()
returns immediately without suspending the calling thread.
clock_nanosleep() suspends the execution of the calling thread until either at least the time
specified by t has elapsed, or a signal is delivered that causes a signal handler to be called orthat
terminates the process. If the call is interrupted by a signal handler, clock_nanosleep() fails
with the error EINTR. In addition, if remain is not NULL and flags was not
TIMER_ABSTIME, it returns the remaining unslept time in remain. This value can then be
used to call clock_nanosleep() again and complete a (relative) sleep.
RETURN VALUE
On successfully sleeping for the requested interval, clock_nanosleep() returns 0. If the call is
interrupted by a signal handler or encounters an error, then it returns one of the positive error
number listed in ERRORS.
BIT, Mangalore 17
Unix System Programming BCS515C
ERRORS
EFAULT t or remain specified an invalid address.
EINTR The sleep was interrupted by a signal handler; see
. EINVAL The value in the tv_nsec field was not in the range [0,999999999] or tv_sec was
negative.
EINVAL clockid was invalid. (CLOCK_THREAD_CPUTIME_ID is not a
permitted value for clockid.)
ENOTSUP
The kernel does not support sleeping against this clockid.
Job-Control Signals
• Job control signals are used to control processes, such as suspending or stopping them,
and resuming them later
• POSIX.1 considers six to be job-control signals:
• SIGCONT: Used to continue a stopped process
BIT, Mangalore 18
Unix System Programming BCS515C
checking is performed but no signal is actually sent. The null signal can be used to
check the validity of pid.
#include<sys/types.h> #include
<signal.h>
int sigqueue(pid_t pid, int signo, const union sigval value)
Return value: 0 on success, -1 on failure Here's
how sigqueue() works:
Sends signal: If the resources are available and SA_SIGINFO is set for the signal, the signal is
queued and sent to the receiving process.
Checks for permission: The sending and receiving processes must have the same real or
effective user ID.
Error checking: If signo is zero, error checking is performed but no signal is sent.
Returns: sigqueue() returns immediately
DAEMON PROCESSES
➢ Daemons are processes that live for a long time.
➢ They are often started when the system is bootstrapped and terminate only when the
system is shut down.
➢ Because they don't have a controlling terminal, we say that they run in the background.
➢ UNIX systems have numerous daemons that perform day-to-day activities.
Deamon Characteristics
➢ $ps –axj
Deamon Characteristics
➢ Daemons run in background.
➢ Daemons have super-user privilege.
➢ Daemons don’t have controlling terminal.
➢ Daemons are session and group leaders.
➢ Anything with a parent process ID of 0 is usually a kernel process started as part of the
system bootstrap procedure.
➢ Kernel processes are special and generally exist for the entire lifetime of the system.
BIT, Mangalore 19
Unix System Programming BCS515C
➢ They run with superuser privileges and have no controlling terminal and no command
line.
➢ Process ID of 1 is usually init.
➢ It is a system daemon responsible for, among other things, starting system services
specific to various run levels.
CODING RULES
1. Call umask to set the file mode creation mask to 0. The file mode creation mask
that's inherited could be set to deny certain permissions. If the daemon process is going
to create files, it may want to set specific permissions.
2. Call fork and have the parent exit. This does several things. First, if the daemon was
started as a simple shell command, having the parent terminate makes the shell think
that the command is done. Second, the child inherits the process group ID of the parent
but gets a new process ID, so we're guaranteed that the child is not a process group
leader.
3. Call setsid to create a new session. The process (a) becomes a session leader of a new
session, (b) becomes the process group leader of a new process group, and (c) has no
controlling terminal.
4. Change the current working directory to the root directory. The current working
directory inherited from the parent could be on a mounted file system. Since daemons
normally exist until the system is rebooted, if the daemon stays on a mounted file
system, that file system cannot be unmounted.
5. Unneeded file descriptors should be closed. This prevents the daemon from holding
open any descriptors that it may have inherited from its parent.
6. 6. Some daemons open file descriptors 0, 1, and 2 to /dev/null so that any library
routines that try to read from standard input or write to standard output or
standard error will have no effect. Since the daemon is not associated with a terminal
device, there is nowhere for output to be displayed; nor is there anywhere to receive
input from an interactive user. Even if the daemon was started from an interactive
session, the daemon runs in the background, and the login session can terminate
without affecting the daemon. If other users log in on the same terminal device, we
wouldn't want output from the daemon showing up on the terminal, and the users
wouldn't expect their input to be read by the daemon.
Example Program:
#include <unistd,h> #include <sys/types.h> #include <fcntl.h> int
daemon_initialise( )
{ pid_t
pid;
if (( pid = fork() ) < 0) return –1;
else if ( pid != 0) exit(0); /*
parent exits */ /* child
BIT, Mangalore 20
Unix System Programming BCS515C
continues */ setsid( );
chdir(“/”); umask(0); return 0;
}
Error Logging
➢ One problem a daemon has is how to handle error messages.
➢ It can't simply write to standard error, since it shouldn't have a controlling terminal.
➢ We don't want all the daemons writing to the console device, since on ➢ many
workstations, the console device runs a windowing system.
➢ We also don't want each daemon writing its own error messages into a separate file.
➢ A central daemon errorlogging facility is required.
Error Logging
Normally, the syslogd daemon reads all three forms of log messages. On start-up, this daemon
reads a configuration file, usually /etc/[Link], which determines where different classes of
messages are to be sent. For example, urgent messages can be sent to the system administrator
BIT, Mangalore 21
Unix System Programming BCS515C
(if logged in) and printed on the console, whereas warnings may be logged to a file. Our
interface to this facility is through the syslog function.
#include <syslog.h> void openlog(const char *ident, int
option, int facility); void syslog(int priority, const char
*format, ...); void closelog(void); int setlogmask(int
maskpri);
SINGLE-INSTANCE DAEMONS:
• Some daemons are implemented so that only a single copy of the daemon should be
running at a time for proper operation. The file and record-locking mechanism provides
the basis for one way to ensure that only one copy of a daemon is running. If each
daemon creates a file and places a write lock on the entire file, only one such write lock
will be allowed to be created. Successive attempts to create write locks will fail, serving
as an indication to successive copies of the daemon that another instance is already
running.
• File and record locking provides a convenient mutual-exclusion mechanism. If the
daemon obtains a write-lock on an entire file, the lock will be removed automatically if
the daemon exits. This simplifies recovery, removing the need for us to clean up from
the previous instance of the daemon.
PROGRAM:Ensure that only one copy of a daemon is running
BIT, Mangalore 22
Unix System Programming BCS515C
DAEMON CONVENTIONS:
If the daemon uses a lock file, the file is usually stored in /var/run. Note, however, that the
daemon might need superuser permissions to create a file here. The name of the file is usually
[Link], where name is the name of the daemon or the service. For example, the name
of the cron daemon's lock file is /var/run/[Link].
• If the daemon supports configuration options, they are usually stored in /etc. The
configuration file is named [Link], where name is the name of the daemon or the
name of the service. For example, the configuration for the syslogd daemon is
/etc/[Link].
• If a daemon has a configuration file, the daemon reads it when it starts, but usually
won't look at it again. If an administrator changes the configuration, the daemon would
need to be stopped and restarted to account for the configuration changes. To avoid this,
some daemons will catch SIGHUP and reread their configuration files when they
receive the signal. Since they aren't associated with terminals and are either session
leaders without controlling terminals or members of orphaned process groups, daemons
have no reason to expect to receive SIGHUP. Thus, they can safely reuse it.
CLIENT-SERVER MODEL:
In general, a server is a process that waits for a client to contact it, requesting some type of
service. The service being provided by the syslogd server is the logging of an error message.
The communication between the client and the server is one-way. The client sends its service
request to the server; the server sends nothing back to the client. In the upcoming chapters,
we'll see numerous examples of two-way communication between a client and a server. The
client sends a request to the server, and the server sends a reply back to the client.
BIT, Mangalore 23