111 lines
3.2 KiB
C
111 lines
3.2 KiB
C
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
#include "signals.h"
|
|
|
|
static void catch_loop (int);
|
|
|
|
/* Convert the short signal name (NNN part of SIGNNN) to its number.
|
|
Consult /usr/include/asm/signal.h for the number mappings. For
|
|
this lab, hard-code the numbers; do not use the numeric constants.
|
|
Return -1 if the name isn't one you need to look up. */
|
|
int
|
|
signal_lookup (char *name)
|
|
{
|
|
// TODO: Look up the numbers for INT, SEGV, KILL, and TSTP
|
|
if (strcmp (name, "INT") == 0)
|
|
return 2;
|
|
if (strcmp (name, "SEGV") == 0)
|
|
return 11;
|
|
if (strcmp (name, "KILL") == 0)
|
|
return 9;
|
|
if (strcmp (name, "TSTP") == 0)
|
|
return 20;
|
|
return -1;
|
|
}
|
|
|
|
// Entry point for overriding a signal handler in this lab.
|
|
void
|
|
override (char *signal)
|
|
{
|
|
int sig = signal_lookup (signal);
|
|
if (sig == SIGKILL)
|
|
printf ("Received bad signal name: %s\n", signal);
|
|
else
|
|
catch_loop (sig);
|
|
}
|
|
|
|
// Generic signal handler. This function doesn't use the signal number
|
|
// in the provided distribution.
|
|
void
|
|
sig_handler (int signum __attribute__ ((unused)))
|
|
{
|
|
// TODO: Complete this signal handler so that it writes the message
|
|
// "Breaking out with signal %d\n" with the signal number that was
|
|
// passed. Note that you cannot use printf() in a signal handler.
|
|
// You must use write(). After writing the message, exit with return
|
|
// code 37.
|
|
//
|
|
// HINT: If you fail integration tests and get a message that the
|
|
// binary files are different, you may be writing an extra byte (the
|
|
// null byte). You can make sure you avoid this by using strlen()
|
|
// instead of trying to hard-code a length.
|
|
char buf[128];
|
|
snprintf (buf, 128, "Breaking out with signal %d\n", signum);
|
|
write (STDOUT_FILENO, buf, strlen (buf));
|
|
exit (37);
|
|
}
|
|
|
|
void
|
|
catch_loop (int signum)
|
|
{
|
|
// sigaction(signum)
|
|
// TODO: Override the signal handler for the signal number passed.
|
|
// Then create a child that runs the following code:
|
|
// prctl (PR_SET_PDEATHSIG, SIGKILL);
|
|
// printf ("Child has started\n");
|
|
// fflush (stdout);
|
|
// while (1) ;
|
|
|
|
struct sigaction sa = { 0 };
|
|
sa.sa_handler = sig_handler;
|
|
|
|
sigaction (signum, &sa, NULL);
|
|
|
|
pid_t pid = fork ();
|
|
|
|
if (pid == 0)
|
|
{
|
|
prctl (PR_SET_PDEATHSIG, SIGKILL);
|
|
printf ("Child has started\n");
|
|
fflush (stdout);
|
|
while (1)
|
|
pause ();
|
|
}
|
|
|
|
// HINT: You will NOT call sig_handler() directly here. Instead,
|
|
// you must use sigaction() to modify the signal's interrupt handler
|
|
// so that sig_handler() will be called later when the signal occurs.
|
|
|
|
// After starting the child, the parent will call sleep (1) to wait
|
|
// for 1 second before sending the signal to the child. The parent
|
|
// must wait for the child to run (and exit), then print
|
|
// "Child was stopped with status %d\n" with the child process's exit
|
|
// status code, retrieved with waitpid(). Note that you will need to
|
|
// call WEXITSTATUS() on the retrieved status code.
|
|
|
|
sleep (1);
|
|
|
|
int status = 0;
|
|
kill (pid, signum);
|
|
waitpid (pid, &status, 0);
|
|
printf ("Child was stopped with status %d\n", WEXITSTATUS (status));
|
|
}
|