Files

111 lines
3.2 KiB
C
Raw Permalink Normal View History

2026-05-31 14:34:00 -04:00
#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));
}