Write it in in C/C++! Ignoring the SIGHUP and SIGQUIT signals This assignment in
ID: 3838853 • Letter: W
Question
Write it in in C/C++!
Ignoring the SIGHUP and SIGQUIT signals
This assignment involves the writing of a simplified version of the shell utility nohup called my_nohup. The utility is used to prevent processes from being killed by the SIGHUP or SIGQUIT signals when the user logs off from a session.
First read the man pages on nohup to understand how the utility works. Also read the man pages on the function isatty().
Your code will carry out the following actions:
If the user supplies no command line arguments (other than the name of the executable) write an informative message to stderr (STDERR_FILENO) and exit with an error value.
Use the function isatty(int filedesc) to determine if the standard output file descriptor is associated with a terminal file. If it is, your code needs to redirect standard output to the file nohup.out (which may already exist.) nohup.out needs to be created or opened for writing. If you need to create the file, give it permissions such the owner has read/write permission. When this section of code is completed, if isatty() returned true, the file descriptior originally assigned to STDOUT_FILENO should be associated with nohup.out. If you are unable to open/create nohup.out, write an informative error message and exit with an error value.
If standard error, STDERR_FILENO, is associated with a terminal device, close it and associate file descriptor 2 with nohup.out.
Ignore SIGHUP and SIGQUIT. You must do this using sigaction() and the appropriate macros. If you are unable to ignore these signals, write an informative message to stderr and exit with an error value.
The new program is the first command line argument to my_nohup. exec*() this program and its arguments, e.g.
In this example, my_nohup would use exec*() to execute the program testsim with the command line arguments 5 and 10.
If the exec*() fails, write out an informative message using either perror() or strerror(). Exit with an error value.
Note: the standard output of the new program will be written to nohup.out.
Please put all your functions in a file called my_nohup.c
a code that compiles and runs with no undersirable side affects. It protects the process from both SIGHUP and SIGQUIT and successfully redirects stdout and stderr.
Explanation / Answer
#include <stdio.h>
#include <stdlib.h>
#include <signal.h> // sigaction(), sigsuspend(), sig*()
#include <unistd.h> // alarm()
void handle_signal(int signal);
void handle_sigalrm(int signal);
void do_sleep(int seconds);
/* Usage example
*
* First, compile and run this program:
* $ gcc signal.c
* $ ./a.out
*
* It will print out its pid. Use it from another terminal to send signals
* $ kill -HUP <pid>
* $ kill -USR1 <pid>
* $ kill -ALRM <pid>
*
* Exit the process with ^C ( = SIGINT) or SIGKILL, SIGTERM
*/
int main() {
struct sigaction sa;
// Print pid, so that we can send signals from other shells
printf("My pid is: %d ", getpid());
// Setup the sighub handler
sa.sa_handler = &handle_signal;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, NULL) == -1) {
perror("Error: cannot handle SIGHUP"); // Should not happen
}
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("Error: cannot handle SIGUSR1"); // Should not happen
}
// Will always fail, SIGKILL is intended to force kill your process
if (sigaction(SIGKILL, &sa, NULL) == -1) {
perror("Cannot handle SIGKILL"); // Will always happen
printf("You can never handle SIGKILL anyway... ");
}
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("Error: cannot handle SIGINT"); // Should not happen
}
for (;;) {
printf(" Sleeping for ~3 seconds ");
do_sleep(3); // Later to be replaced with a SIGALRM
}
}
void handle_signal(int signal) {
const char *signal_name;
sigset_t pending;
// Find out which signal we're handling
switch (signal) {
case SIGHUP:
signal_name = "SIGHUP";
break;
case SIGUSR1:
signal_name = "SIGUSR1";
break;
case SIGINT:
printf("Caught SIGINT, exiting now ");
exit(0);
default:
fprintf(stderr, "Caught wrong signal: %d ", signal);
return;
}
/*
* Please note that printf et al. are NOT safe to use in signal handlers.
* Look for async safe functions.
*/
printf("Caught %s, sleeping for ~3 seconds "
"Try sending another SIGHUP / SIGINT / SIGALRM "
"(or more) meanwhile ", signal_name);
/*
* Indeed, all signals are blocked during this handler
* But, at least on OSX, if you send 2 other SIGHUP,
* only one will be delivered: signals are not queued
* However, if you send HUP, INT, HUP,
* you'll see that both INT and HUP are queued
* Even more, on my system, HUP has priority over INT
*/
do_sleep(3);
printf("Done sleeping for %s ", signal_name);
// So what did you send me while I was asleep?
sigpending(&pending);
if (sigismember(&pending, SIGHUP)) {
printf("A SIGHUP is waiting ");
}
if (sigismember(&pending, SIGUSR1)) {
printf("A SIGUSR1 is waiting ");
}
printf("Done handling %s ", signal_name);
}
void handle_sigalrm(int signal) {
if (signal != SIGALRM) {
fprintf(stderr, "Caught wrong signal: %d ", signal);
}
printf("Got sigalrm, do_sleep() will end ");
}
void do_sleep(int seconds) {
struct sigaction sa;
sigset_t mask;
sa.sa_handler = &handle_sigalrm; // Intercept and ignore SIGALRM
sa.sa_flags = SA_RESETHAND; // Remove the handler after first signal
sigfillset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
// Get the current signal mask
sigprocmask(0, NULL, &mask);
// Unblock SIGALRM
sigdelset(&mask, SIGALRM);
// Wait with this mask
alarm(seconds);
sigsuspend(&mask);
printf("sigsuspend() returned ");
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.