Download | Plain Text | No Line Numbers
- /*
- * Name: calculator
- * Author: Manuel Mausz, 0728348
- * Description: upon start calculator forks a child. the parent reads messages
- * from stdin, forwards the messages to the child, which does the
- * calculation. the result is forwarded to the parent and dumped
- * to stdout.
- * Created: 24.05.2009
- * Exercise: 3c
- */
-
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include "error.h"
-
- /* maximal input length */
- #define MAX_LEN 15
-
- /* install signal handler macro */
- #define INSTALL_SIGNAL(signum, act, oldact) \
- sigaction(signum, NULL, &oldact); \
- if (oldact.sa_handler != SIG_IGN) \
- sigaction(signum, &act, NULL);
-
- /* global variables */
- static int pipew[2]; /* fds for write to child/read from parent */
- static int piper[2]; /* fds for read from child/write to parent */
- static FILE *streamw = NULL; /* stream for writing to child */
- static FILE *streamr = NULL; /* stream for reading from child */
-
- /*
- * NAME: sigpipe_handler
- * PURPOSE:
- * signal handler for SIGPIPE
- * sets global error flag to 1
- *
- * PARAMETERS:
- * int signum ... signal number
- *
- * RETURN VALUE:
- * void
- *
- * GLOBAL VARS:
- * error, child
- */
- static void sigpipe_handler(int signum)
- {
- #ifdef DEBUG
- #endif
- error = 1;
- }
-
- /*
- * NAME: usage
- * PURPOSE:
- * prints program usage to stderr and terminates with EXIT_FAILURE
- *
- * PARAMETERS:
- * void
- *
- * RETURN VALUE:
- * void
- *
- * GLOBAL VARS:
- * me
- */
- static void usage()
- {
- (void) bailout(0, NULL);
- }
-
- /*
- * NAME: allocate_resources
- * PURPOSE:
- * allocate resources
- *
- * PARAMETERS:
- * void
- *
- * RETURN VALUE:
- * void
- *
- * GLOBAL VARS:
- * pipew, piper
- */
- void allocate_resources(void)
- {
- #ifdef DEBUG
- #endif
- if (pipe(pipew) == -1)
- (void) bailout(1, "Unable to create write pipe!");
- if (pipe(piper) == -1)
- (void) bailout(1, "Unable to create read pipe!");
- }
-
- /*
- * NAME: free_resources
- * PURPOSE:
- * frees allocated resources
- *
- * PARAMETERS:
- * void
- *
- * RETURN VALUE:
- * void
- *
- * GLOBAL VARS:
- * error, child, streamw, streamr
- */
- void free_resources(void)
- {
- #ifdef DEBUG
- #endif
- /* close write stream */
- if (streamw != NULL)
- {
- {
- streamw = NULL;
- (void) bailout(1, "Unable to close write stream!");
- }
- streamw = NULL;
- }
-
- /* close read stream */
- if (streamr != NULL)
- {
- {
- streamr = NULL;
- (void) bailout(1, "Unable to close read stream!");
- }
- streamr = NULL;
- }
- }
-
- /*
- * NAME: exec_parent
- * PURPOSE:
- * code block for parent process
- * prepares pipes and streams, forwards messages read from stdin to child,
- * and dumps responses from child to stdout
- *
- * PARAMETERS:
- * void
- *
- * RETURN VALUE:
- * void
- *
- * GLOBAL VARS:
- * error, pipew, piper, streamw, streamr
- */
- void exec_parent(void)
- {
- char buffer[MAX_LEN + 1];
-
- /* write pipe: close unused read end */
- if (close(pipew[0]) == -1)
- (void) bailout(1, "Unable to close read end of write pipe!");
- /* read pipe: close unused write end */
- if (close(piper[1]) == -1)
- (void) bailout(1, "Unable to close write end of read pipe!");
-
- /* create write + read stream */
- (void) bailout(1, "Unable to open write pipe for writing!");
- (void) bailout(1, "Unable to open read pipe for reading!");
-
- /* read data from stdin */
- {
- /* write data to child */
- (void) bailout(1, "Unable to write to pipe!");
- (void) bailout(1, "Unable to flush write stream!");
-
- /* read result from child */
- {
- (void) bailout(1, "Unable to write to stdout!");
- (void) bailout(1, "Unable to flush stdout!");
- }
- (void) bailout(1, "Unable to read from pipe!");
- }
-
- /* close write stream so the child can terminate */
- {
- streamw = NULL;
- (void) bailout(1, "Unable to close write stream!");
- }
- streamw = NULL;
- }
-
- /*
- * NAME: exec_parent
- * PURPOSE:
- * code block for child process
- * prepares pipes and streams, reads messages from parent, parses the messages
- * and forwards the calculated result to the parent back
- *
- * PARAMETERS:
- * void
- *
- * RETURN VALUE:
- * void
- *
- * GLOBAL VARS:
- * error, pipew, piper, streamw, streamr
- */
- void exec_child(void)
- {
- char buffer[MAX_LEN + 1];
- int num1, num2, result = -1;
- char op;
-
- /* write pipe: close unused write end */
- if (close(pipew[1]) == -1)
- (void) bailout(1, "Unable to close write end of write pipe!");
- /* read pipe: close unused read end */
- if (close(piper[0]) == -1)
- (void) bailout(1, "Unable to close read end of read pipe!");
-
- /* create write + read stream (note: swapped the two pipes) */
- (void) bailout(1, "Unable to open write pipe for writing!");
- (void) bailout(1, "Unable to open read pipe for reading!");
-
- /* read data from parent */
- {
- /* parse line */
- (void) bailout(0, "Syntax error!");
-
- /* calculate */
- switch(op)
- {
- case '+':
- result = num1 + num2;
- break;
- case '-':
- result = num1 - num2;
- break;
- case '*':
- result = num1 * num2;
- break;
- case '/':
- result = (num2 == 0) ? 0 : num1 / num2;
- break;
- default:
- (void) bailout(0, "Unsupported operation!");
- break;
- }
-
- /* write result to parent */
- (void) bailout(1, "Unable to write to pipe!");
- (void) bailout(1, "Unable to flush write stream!");
- }
- (void) bailout(1, "Unable to read from pipe!");
- }
-
- /*
- * NAME: main
- * PURPOSE:
- * install signal handler, allocate resources, fork process,
- * call the corresponding methods and wait for child before terminating
- *
- * PARAMETERS:
- * standard parameters of main
- *
- * RETURN VALUE:
- * int ... 0 on success, 1 on error
- *
- * GLOBAL VARS:
- * me, error, child
- */
- int main(int argc, char *argv[])
- {
- struct sigaction new_action, old_action;
- pid_t pid, wpid;
- int status;
-
- /* save me */
- me = argv[0];
-
- /* install signal handler */
- new_action.sa_handler = sigpipe_handler;
- sigemptyset(&new_action.sa_mask);
- new_action.sa_flags = 0; /* to avoid restart of blocking syscalls */
- INSTALL_SIGNAL(SIGPIPE, new_action, old_action)
-
- /* check cmdline options */
- if (argc > 1)
- (void) usage();
-
- /* allocate resources */
- (void) allocate_resources();
-
- switch(pid = fork())
- {
- case -1:
- (void) bailout(1, "Unable to fork!");
- break;
- case 0: /* child */
- #if DEBUG
- #endif
- child = 1;
- (void) exec_child();
- break;
- default: /* parent */
- #if DEBUG
- #endif
- (void) exec_parent();
-
- #if DEBUG
- #endif
- do
- {
- wpid = waitpid(pid, &status, 0);
- if (wpid == -1)
- (void) bailout(1, "Error while waiting for child!");
- else if (WIFEXITED(status))
- error += WEXITSTATUS(status);
- else if (WIFSIGNALED(status))
- error += WTERMSIG(status);
- }
- while(!WIFEXITED(status) && !WIFSIGNALED(status));
- }
-
- /* free resources */
- (void) free_resources();
-
- return (error) ? 1 : 0;
- }
-
- /* vim: set et sw=2 ts=2: */
-