init
This commit is contained in:
18
.clang-format
Normal file
18
.clang-format
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 79
|
||||
IndentWidth: 4
|
||||
ContinuationIndentWidth: 8
|
||||
UseTab: Never
|
||||
|
||||
PointerAlignment: Right
|
||||
DerivePointerAlignment: false
|
||||
BreakBeforeBraces: Attach
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignTrailingComments: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
---
|
||||
19
Makefile
Normal file
19
Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
CC=gcc
|
||||
CFLAGS=-std=gnu99 -Wall -pedantic -I/local/courses/csse2310/include
|
||||
LDFLAGS=-L/local/courses/csse2310/lib -lcsse2310a3
|
||||
|
||||
.PHONY: all debug profile clean
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: sigcat hq
|
||||
|
||||
debug: CFLAGS += -g
|
||||
debug: all
|
||||
|
||||
profile: CFLAGS += -pg -fprofile-arcs -ftest-coverage
|
||||
profile: all
|
||||
|
||||
hq: hq.o job.o
|
||||
|
||||
clean:
|
||||
rm -f sigcat hq *.o
|
||||
349
hq.c
Normal file
349
hq.c
Normal file
@@ -0,0 +1,349 @@
|
||||
#include "hq.h"
|
||||
|
||||
int get_valid_number(char *rawNumber) {
|
||||
if (strlen(rawNumber) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < strlen(rawNumber); i++) {
|
||||
if (!isdigit(rawNumber[i]) && !isspace(rawNumber[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return atoi(rawNumber);
|
||||
}
|
||||
|
||||
// Not in job.c as requires get_valid_number
|
||||
struct Job *get_job_from_raw_id(char *rawJobId) {
|
||||
int jobId = get_valid_number(rawJobId);
|
||||
struct Job *job = get_job_from_id(jobId);
|
||||
return job;
|
||||
}
|
||||
|
||||
char **prepare_args_for_exec(char **arguments, int numberArgs) {
|
||||
char **newArguments = malloc(sizeof(char *) * (numberArgs + 1));
|
||||
|
||||
for (int i = 0; i < numberArgs; i++) {
|
||||
newArguments[i] = arguments[i];
|
||||
}
|
||||
newArguments[numberArgs] = '\0';
|
||||
|
||||
return newArguments;
|
||||
}
|
||||
|
||||
void handle_child_fds(struct Job *job) {
|
||||
// close unused filedescriptors
|
||||
close(job->readFd[0]);
|
||||
close(job->writeFd[1]);
|
||||
|
||||
// redirect process stdin and stdout to pipe
|
||||
dup2(job->writeFd[0], STDIN_FILENO);
|
||||
dup2(job->readFd[1], STDOUT_FILENO);
|
||||
|
||||
// close fds
|
||||
close(job->readFd[1]);
|
||||
close(job->writeFd[0]);
|
||||
}
|
||||
|
||||
int execute_command(char *command, char **arguments, int numberArgs) {
|
||||
char **nullpArguments = NULL;
|
||||
int value = 0;
|
||||
|
||||
nullpArguments = prepare_args_for_exec(arguments, numberArgs);
|
||||
value = execvp(command, nullpArguments);
|
||||
free(nullpArguments);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void handle_spawn(char **arguments, int numberArgs) {
|
||||
struct Job *job = (struct Job *)malloc(sizeof(struct Job));
|
||||
memset(job, 0, sizeof(struct Job));
|
||||
|
||||
if (numberArgs < 1) {
|
||||
printf("Error: Insufficient arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set command name and command status
|
||||
job->command = strdup(arguments[0]);
|
||||
job->status = (char *)malloc(sizeof(char) * (strlen("running") + 1));
|
||||
strcpy(job->status, "running");
|
||||
|
||||
// Setup pipes
|
||||
if (pipe(job->readFd) || pipe(job->writeFd)) {
|
||||
perror("Pipe:");
|
||||
}
|
||||
|
||||
int pid = fork();
|
||||
if (!pid) {
|
||||
handle_child_fds(job);
|
||||
|
||||
if (execute_command(job->command, arguments, numberArgs) == -1) {
|
||||
exit(EXIT_CHLD_ERR);
|
||||
}
|
||||
exit(EXIT_OK);
|
||||
} else {
|
||||
// close unused filedescriptors
|
||||
close(job->readFd[1]);
|
||||
close(job->writeFd[0]);
|
||||
|
||||
job->pid = pid;
|
||||
job->jobId = add_job(job);
|
||||
printf("New Job ID [%d] created\n", job->jobId);
|
||||
}
|
||||
}
|
||||
|
||||
void report_job(struct Job *job) {
|
||||
printf("[%d] %s:%s\n", job->jobId, job->command, job->status);
|
||||
}
|
||||
|
||||
void handle_report(char **arguments, int numberArgs) {
|
||||
if (numberArgs > 0) {
|
||||
struct Job *job = get_job_from_raw_id(arguments[0]);
|
||||
|
||||
if (!job) {
|
||||
printf("Error: Invalid job\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[Job] cmd:status\n");
|
||||
report_job(job);
|
||||
} else {
|
||||
printf("[Job] cmd:status\n");
|
||||
for (int i = 0; i < programJobs.length; i++) {
|
||||
struct Job *currentJob = programJobs.jobs[i];
|
||||
report_job(currentJob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_signal(char **arguments, int numberArgs) {
|
||||
if (numberArgs < 2) {
|
||||
printf("Error: Insufficient arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct Job *job = get_job_from_raw_id(arguments[0]);
|
||||
if (!job) {
|
||||
printf("Error: Invalid job\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int signal = get_valid_number(arguments[1]);
|
||||
if (signal < 1 || signal > 31) {
|
||||
printf("Error: Invalid signal\n");
|
||||
return;
|
||||
}
|
||||
|
||||
kill(job->pid, signal);
|
||||
}
|
||||
|
||||
void handle_sleep(char **arguments, int numberArgs) {
|
||||
char *endPtr;
|
||||
struct timespec sleepTime;
|
||||
memset(&sleepTime, 0, sizeof(struct timespec));
|
||||
|
||||
if (numberArgs < 1) {
|
||||
printf("Error: Insufficient arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int errno = 0;
|
||||
sleepTime.tv_sec = strtod(arguments[0], &endPtr);
|
||||
if (errno != 0 || strlen(arguments[0]) == 0 || strcmp(endPtr, "") != 0) {
|
||||
printf("Error: Invalid sleep time\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// sleep is interrupted by sigchld
|
||||
// https://stackoverflow.com/questions/17118105
|
||||
while (nanosleep(&sleepTime, &sleepTime)) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_send(char **arguments, int numberArgs) {
|
||||
if (numberArgs < 2) {
|
||||
printf("Error: Insufficient arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct Job *job = get_job_from_raw_id(arguments[0]);
|
||||
if (!job) {
|
||||
printf("Error: Invalid job\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dprintf(job->writeFd[1], "%s\n", arguments[1]);
|
||||
}
|
||||
|
||||
void handle_recieve(char **arguments, int numberArgs) {
|
||||
if (numberArgs < 1) {
|
||||
printf("Error: Insufficient arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct Job *job = get_job_from_raw_id(arguments[0]);
|
||||
if (!job) {
|
||||
printf("Error: Invalid job\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_ready(job->readFd[0])) {
|
||||
FILE *input = NULL;
|
||||
char *line = NULL;
|
||||
|
||||
if ((input = fdopen(job->readFd[0], "r")) == NULL) {
|
||||
printf("<EOF>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((line = read_line(input)) != NULL) {
|
||||
printf("%s\n", line);
|
||||
} else {
|
||||
printf("<EOF>\n");
|
||||
}
|
||||
|
||||
free(line);
|
||||
fclose(input);
|
||||
} else {
|
||||
printf("<no input>\n");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_eof(char **arguments, int numberArgs) {
|
||||
if (numberArgs < 1) {
|
||||
printf("Error: Insufficient arguments\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct Job *job = get_job_from_raw_id(arguments[0]);
|
||||
if (!job) {
|
||||
printf("Error: Invalid job\n");
|
||||
return;
|
||||
}
|
||||
|
||||
close(job->writeFd[1]);
|
||||
}
|
||||
|
||||
void handle_cleanup(void) {
|
||||
for (int i = 0; i < programJobs.length; i++) {
|
||||
struct Job *currentJob = programJobs.jobs[i];
|
||||
|
||||
// Close all pipes and kill
|
||||
close(currentJob->writeFd[1]);
|
||||
close(currentJob->readFd[0]);
|
||||
kill(currentJob->pid, SIGKILL);
|
||||
}
|
||||
// Don't need to wait, done in update_status signal handler
|
||||
// If I wait here then the status does not get updated
|
||||
}
|
||||
|
||||
void handle_commands(char *command, char **arguments, int numberArgs) {
|
||||
// I really don't like using so many if statements but I don't know of
|
||||
// another way
|
||||
|
||||
if (strcmp(command, "spawn") == 0) {
|
||||
handle_spawn(arguments, numberArgs);
|
||||
} else if (strcmp(command, "report") == 0) {
|
||||
handle_report(arguments, numberArgs);
|
||||
} else if (strcmp(command, "signal") == 0) {
|
||||
handle_signal(arguments, numberArgs);
|
||||
} else if (strcmp(command, "sleep") == 0) {
|
||||
handle_sleep(arguments, numberArgs);
|
||||
} else if (strcmp(command, "send") == 0) {
|
||||
handle_send(arguments, numberArgs);
|
||||
} else if (strcmp(command, "rcv") == 0) {
|
||||
handle_recieve(arguments, numberArgs);
|
||||
} else if (strcmp(command, "eof") == 0) {
|
||||
handle_eof(arguments, numberArgs);
|
||||
} else if (strcmp(command, "cleanup") == 0) {
|
||||
handle_cleanup();
|
||||
} else {
|
||||
printf("Error: Invalid command\n");
|
||||
}
|
||||
}
|
||||
|
||||
void process_input(char *input) {
|
||||
int numberTokens = 0;
|
||||
char *foo = strdup(input);
|
||||
char **tokens = split_space_not_quote(foo, &numberTokens);
|
||||
|
||||
// Check if empty command
|
||||
if (numberTokens == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get command and it's arguments
|
||||
char *command = strdup(tokens[0]);
|
||||
char **arguments = NULL;
|
||||
if (numberTokens > 1) {
|
||||
arguments = &tokens[1];
|
||||
}
|
||||
|
||||
handle_commands(command, arguments, numberTokens - 1);
|
||||
|
||||
free(tokens);
|
||||
free(foo);
|
||||
free(command);
|
||||
}
|
||||
|
||||
void build_status(char **dest, char *prefix, int state) {
|
||||
size_t needed_size = snprintf(NULL, 0, "%s(%d)", prefix, state);
|
||||
*dest = (char *)realloc(*dest, needed_size + sizeof(char));
|
||||
sprintf(*dest, "%s(%d)", prefix, state);
|
||||
}
|
||||
|
||||
void update_status(int s) {
|
||||
int pid;
|
||||
int state;
|
||||
while ((pid = waitpid(-1, &state, WNOHANG)) > 0) {
|
||||
struct Job *job = get_job_from_pid(pid);
|
||||
if (!job) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (WIFSIGNALED(state)) {
|
||||
build_status(&(job->status), "signalled", WTERMSIG(state));
|
||||
} else {
|
||||
build_status(&(job->status), "exited", WEXITSTATUS(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup_signal_handlers(void) {
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = update_status;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
sigaction(SIGCHLD, &sa, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
setup_signal_handlers();
|
||||
|
||||
programJobs.jobs = NULL;
|
||||
programJobs.length = 0;
|
||||
|
||||
printf("> ");
|
||||
fflush(stdout);
|
||||
|
||||
char *line = NULL;
|
||||
while ((line = read_line(stdin)) != NULL) {
|
||||
process_input(line);
|
||||
|
||||
printf("> ");
|
||||
fflush(stdout);
|
||||
free(line);
|
||||
}
|
||||
|
||||
handle_cleanup();
|
||||
deinit_jobs();
|
||||
return EXIT_OK;
|
||||
}
|
||||
207
hq.h
Normal file
207
hq.h
Normal file
@@ -0,0 +1,207 @@
|
||||
#ifndef HQ_H
|
||||
#define HQ_H
|
||||
#include <csse2310a3.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "job.h"
|
||||
|
||||
// Program exit codes
|
||||
enum ExitCodes {
|
||||
EXIT_OK = 0,
|
||||
EXIT_CHLD_ERR = 99
|
||||
};
|
||||
|
||||
/* get_valid_number()
|
||||
* ------------------
|
||||
* Gets a number from the given string
|
||||
*
|
||||
* Example:
|
||||
* "1" -> 1
|
||||
* "a" -> -1
|
||||
* "1a" -> -1
|
||||
* "-2" -> -1
|
||||
*
|
||||
* rawNumber: the raw number to convert to an integer
|
||||
*
|
||||
* Returns: the integer representation of the raw number, if the raw number
|
||||
* is not a number, returns -1
|
||||
*/
|
||||
int get_valid_number(char *rawNumber);
|
||||
|
||||
/* get_job_from_raw_id()
|
||||
* ---------------------
|
||||
* Similar to get_kob_from_id, however also checks if the given raw id is a
|
||||
* valid number
|
||||
*
|
||||
* rawId: the raw id for the job
|
||||
*
|
||||
* Returns: the job if the job id exists, otherwise NULL
|
||||
*/
|
||||
struct Job *get_job_from_raw_id(char *rawId);
|
||||
|
||||
/* prepare_args_for_exec()
|
||||
* -----------------------
|
||||
* NULL terminates the list of arguments so it can be used for execvp
|
||||
*
|
||||
* arguments: the list of arguments
|
||||
* numberArgs: the number of arguments passed
|
||||
*
|
||||
* Returns: the null terminated array
|
||||
*/
|
||||
char **prepare_args_for_exec(char **arguments, int numberArgs);
|
||||
|
||||
/* handle_child_fds()
|
||||
* ------------------
|
||||
* Handles opening, duplicating and closing fds for use in child fork
|
||||
*
|
||||
* job: the job in which the fds are stored
|
||||
*/
|
||||
void handle_child_fds(struct Job *job);
|
||||
|
||||
/* execute_command()
|
||||
* -----------------
|
||||
* Executes the given command with the given arguments, adds a null terminator
|
||||
* to the list of arguments before executing
|
||||
*
|
||||
* arguments: the list of arguments
|
||||
* numberArgs: the number of arguments passed
|
||||
*
|
||||
* Returns: the return status of the command
|
||||
*/
|
||||
int execute_command(char *command, char **arguments, int numberArgs);
|
||||
|
||||
/* handle_spawn()
|
||||
* --------------
|
||||
* Handles the spawn command
|
||||
*
|
||||
* arguments: the arguments to give to the command
|
||||
* number_args: the number of arguments passed
|
||||
*/
|
||||
void handle_spawn(char **arguments, int numberArgs);
|
||||
|
||||
/* report_job()
|
||||
* ------------
|
||||
* Prints the job information to stdout
|
||||
*
|
||||
* job: the job to report on
|
||||
*/
|
||||
void report_job(struct Job *job);
|
||||
|
||||
/* handle_report()
|
||||
* ---------------
|
||||
* Handles the report command
|
||||
* Prints a brief description of the status of each job
|
||||
*
|
||||
* arguments: should only be one argument containing the job id
|
||||
* number_args: the number of arguments passed
|
||||
*/
|
||||
void handle_report(char **arguments, int numberArgs);
|
||||
|
||||
/* handle_signal()
|
||||
* ---------------
|
||||
* Handles the signal command
|
||||
* Sends a signal to a job given a job id and signal number
|
||||
*
|
||||
* arguments: the array of arguments for the command
|
||||
* numberArgs: the number of arguments passed
|
||||
*/
|
||||
void handle_signal(char **arguments, int numberArgs);
|
||||
|
||||
/* handle_sleep()
|
||||
* --------------
|
||||
* Handles the sleep command
|
||||
* Puts this program to sleep for the specified seconds
|
||||
*
|
||||
* arguments: the array of arguments for the command
|
||||
* numberArgs: the number of arguments passed
|
||||
*/
|
||||
void handle_sleep(char **arguments, int numberArgs);
|
||||
|
||||
/* handle_send()
|
||||
* -------------
|
||||
* Handles the send command
|
||||
* Sends the given message to the given job id's stdin
|
||||
*
|
||||
* arguments: the array of arguments for the command
|
||||
* numberArgs: the number of arguments passed
|
||||
*/
|
||||
void handle_send(char **arguments, int numberArgs);
|
||||
|
||||
/* handle_recieve()
|
||||
* -------------
|
||||
* Handles the rcv command
|
||||
* Reads next line in the given job id's stdout
|
||||
*
|
||||
* arguments: the array of arguments for the command
|
||||
* numberArgs: the number of arguments passed
|
||||
*/
|
||||
void handle_recieve(char **arguments, int numberArgs);
|
||||
|
||||
/* handle_eof()
|
||||
* -------------
|
||||
* Handles the eof command
|
||||
* Closes the write end of the programs pipe
|
||||
*
|
||||
* arguments: the array of arguments for the command
|
||||
* numberArgs: the number of arguments passed
|
||||
*/
|
||||
void handle_eof(char **arguments, int numberArgs);
|
||||
|
||||
/* handle_cleanup()
|
||||
* ----------------
|
||||
* Handles the cleanup commands
|
||||
* Sends a SIGKILL to all running jobs
|
||||
*/
|
||||
void handle_cleanup(void);
|
||||
|
||||
/* handle_commands()
|
||||
* -----------------
|
||||
* Function to coordinate what each command does
|
||||
*
|
||||
* command: the command string
|
||||
* arguments: the arguments for the given command
|
||||
* number_args: the amount of arguments passed
|
||||
*/
|
||||
void handle_commands(char *command, char **arguments, int numberArgs);
|
||||
|
||||
/* build_status()
|
||||
* --------------
|
||||
* Builds the status for a job and outputs it to the dest
|
||||
* Builds in the form of "<prefix>(<state>)"
|
||||
*
|
||||
* dest: the character array to output to
|
||||
* prefix: the prefix for the status
|
||||
* state: the exit number / signal number of the status
|
||||
*/
|
||||
void build_status(char **dest, char *prefix, int state);
|
||||
|
||||
/* update_status()
|
||||
* ---------------
|
||||
* Updates all job status' if they have changed, called for handling of
|
||||
* SIGCHLD
|
||||
*
|
||||
* signal: unused but required for a signal handler
|
||||
*/
|
||||
void update_status(int signal);
|
||||
|
||||
/* setup_signal_handlers()
|
||||
* -----------------------
|
||||
* Sets up the required signal handlers
|
||||
* Ignores SIGINT, handles SIGCHLD with update_status
|
||||
*/
|
||||
void setup_signal_handlers(void);
|
||||
|
||||
/* process_input()
|
||||
* ---------------
|
||||
* Processes the input from the interactive cli
|
||||
*
|
||||
* input: the input from the interactive cli
|
||||
*/
|
||||
void process_input(char *input);
|
||||
#endif
|
||||
45
job.c
Normal file
45
job.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "job.h"
|
||||
|
||||
struct Job *get_job_from_pid(int pid) {
|
||||
for (int i = 0; i < programJobs.length; i++) {
|
||||
struct Job *job = programJobs.jobs[i];
|
||||
if (job->pid == pid) {
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct Job *get_job_from_id(int id) {
|
||||
for (int i = 0; i < programJobs.length; i++) {
|
||||
struct Job *job = programJobs.jobs[i];
|
||||
if (job->jobId == id) {
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int add_job(struct Job *job) {
|
||||
programJobs.jobs = (struct Job **)realloc(
|
||||
programJobs.jobs, sizeof(struct Job *) * (programJobs.length + 1));
|
||||
|
||||
programJobs.jobs[programJobs.length] = job;
|
||||
programJobs.length++;
|
||||
|
||||
return programJobs.length - 1;
|
||||
}
|
||||
|
||||
void deinit_jobs(void) {
|
||||
for (int i = 0; i < programJobs.length; i++) {
|
||||
struct Job *job = programJobs.jobs[i];
|
||||
free(job->command);
|
||||
free(job->status);
|
||||
free(programJobs.jobs[i]);
|
||||
}
|
||||
|
||||
free(programJobs.jobs);
|
||||
}
|
||||
|
||||
59
job.h
Normal file
59
job.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef JOB_H
|
||||
#define JOB_H
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* A job */
|
||||
struct Job {
|
||||
int jobId;
|
||||
int pid;
|
||||
int writeFd[2];
|
||||
int readFd[2];
|
||||
char *command;
|
||||
char *status;
|
||||
};
|
||||
|
||||
/* List of jobs including the length */
|
||||
struct Jobs {
|
||||
struct Job **jobs;
|
||||
int length;
|
||||
};
|
||||
|
||||
// TODO: remove this as global
|
||||
struct Jobs programJobs;
|
||||
|
||||
/* get_job_from_pid()
|
||||
* ------------------
|
||||
* Gets a job given by the pid of the job
|
||||
*
|
||||
* pid: the process id of the job
|
||||
*
|
||||
* Returns: the job if the pid exists, otherwise NULL
|
||||
*/
|
||||
struct Job *get_job_from_pid(int pid);
|
||||
|
||||
/* get_job_from_id()
|
||||
* ------------------
|
||||
* Gets a job given by the job id
|
||||
*
|
||||
* id: the id of the job
|
||||
*
|
||||
* Returns: the job if the job id exists, otherwise NULL
|
||||
*/
|
||||
struct Job *get_job_from_id(int id);
|
||||
|
||||
/* add_job()
|
||||
* Adds the given job to the list of current jobs
|
||||
*
|
||||
* job: the pointer to the job to add
|
||||
*
|
||||
* Returns: the job id of the given job
|
||||
*/
|
||||
int add_job(struct Job *job);
|
||||
|
||||
/* deinit_jobs()
|
||||
* -------------
|
||||
* Deinitialises all jobs and frees memory
|
||||
*/
|
||||
void deinit_jobs(void);
|
||||
#endif
|
||||
52
sigcat.c
Normal file
52
sigcat.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "sigcat.h"
|
||||
|
||||
void setup_default_handlers(void) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = default_signal_handler;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
for (int i = SIGMIN; i <= SIGMAX; i++) {
|
||||
// Cannot process SIGKILL or SIGSTOP
|
||||
if (i == SIGKILL || i == SIGSTOP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sigaction(i, &sa, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void default_signal_handler(int s) {
|
||||
fprintf(outputStream, "sigcat received %s\n", strsignal(s));
|
||||
fflush(outputStream);
|
||||
|
||||
if (s == SIGUSR1 || s == SIGUSR2) {
|
||||
usr_signal_handler(s);
|
||||
}
|
||||
}
|
||||
|
||||
void usr_signal_handler(int s) {
|
||||
if (s == SIGUSR1) {
|
||||
outputStream = stdout;
|
||||
} else if (s == SIGUSR2) {
|
||||
outputStream = stderr;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Defined in header
|
||||
outputStream = stdout;
|
||||
|
||||
setup_default_handlers();
|
||||
|
||||
// Forever loop input until recieve EOF
|
||||
char *line;
|
||||
while ((line = read_line(stdin)) != NULL) {
|
||||
strcat(line, "\n");
|
||||
fprintf(outputStream, line);
|
||||
fflush(outputStream);
|
||||
free(line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
41
sigcat.h
Normal file
41
sigcat.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef SIGCAT_H
|
||||
#define SIGCAT_H
|
||||
#include <csse2310a3.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SIGMIN 1
|
||||
#define SIGMAX 31
|
||||
|
||||
// Holds the current output stream
|
||||
FILE *outputStream;
|
||||
|
||||
/* setup_default_handlers()
|
||||
* ------------------------
|
||||
* Sets up handlers for signals 1-31 excluding 9, 19, 10 and 12
|
||||
*/
|
||||
void setup_default_handlers(void);
|
||||
|
||||
/* default_signal_handler()
|
||||
* ------------------------
|
||||
* The default handler for signals, prints to the current output_stream
|
||||
* For example: sigcat recieved Hangup
|
||||
*
|
||||
* s: the signal number
|
||||
*/
|
||||
void default_signal_handler(int s);
|
||||
|
||||
/* usr_signal_handler()
|
||||
* ------------------------
|
||||
* The USR handler for signals, changes the output_stream based on the signal
|
||||
* recieved. SIGUSR1 sets the output_stream to stdout and SIGUSR2 sets the
|
||||
* output_stream to stderr
|
||||
*
|
||||
* s: the signal number
|
||||
*/
|
||||
void usr_signal_handler(int s);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user