Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

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 ");

}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote