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