/* Operating Systems Spring 2005
   Sample FIFO (named pipe) code

   This program can run in one of two modes:
     1. as a server that creates a named pipe and
        waits for input from the pipe. 
        everything it reads from the pipe is 
        printed to stdout. when EOF is reached
		(the writer has closed the pipe), the
		server removes the fifo from the filesystem.

		To run this program as a server:
		  > ./fifoplay -s nameoffifo

     2. as a client. The client opens the named
        pipe (which must already exist) created by
        the server and sends it whatever the user
		enters on the command line.

		To run this program as a client:
		  > ./fifoplay -c nameoffifo

     The server() and client() functions defined in the file common.c
     are called to do the actual work of transferring data between
     processes, the code here just sets up the fifo descriptor before
     calling one of those functions.

*/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "common.h"  /* client() and server() functions */


#define FIFO_PERMS 0755

/* this is the code to crete the named pipe (fifo).
   Note that it is possible for a server to attach itself
   to an existing fifo (it doesn't have to create it).
*/

void create_fifo(const char *name) {
  if (mkfifo(name, FIFO_PERMS)<0) {
	perror("Error making fifo ");
	exit(1);
  }
}

/* when acting as the server, this function is called.
   fifo_server just reads everything sent to the fifo and
   prints it out (sends to stdout).
*/

void fifo_server(char *fifo) {
  int fd;

  /* open the fifo for reading only 
	 Note that this will block until someone opens it
	 for writing!
  */
  fd = open(fifo,O_RDONLY);

  if (fd<0) {
	perror("Error opening fifo\n");
	exit(1);
  }

  /* call the server function - this will read from the fifo
     and print to stdout */

  server(fd);

  /* server will clean up by deleting the fifo */
  if (unlink(fifo) !=0) {
	perror("Error deleting the fifo");
	exit(1);
  }

}

/* ======================================================
   fifo_client is called if this is run as a client.
*/

void fifo_client(char *fifo) {
  int fd;

  /* open the fifo for writing */
  fd = open(fifo,O_WRONLY);
  if (fd<0) {
	perror("Error opening fifo\n");
	exit(1);
  }

  /* call the client function - it reads from stdin and
     writes to the fifo */
  client(fd);
  close(fd);
}


enum {NONE=0,CLIENT, SERVER};

int main(int argc, char **argv) {
  int mode = NONE;
  char *fifoname=NULL;
  char c;

  while ((c=getopt(argc,argv,"c:s:"))>=0) {
    switch(c) {
    case 'c':
	  mode = CLIENT; 
	  fifoname=optarg;
	  break;
    case 's':
	  mode = SERVER; 
	  fifoname=optarg;
	  break;
    case '?':  /* invalid option - getopt returns a '?' */
      exit(1);
    }
  }

  if ((mode==NONE) || (fifoname==NULL)) {
	printf("Invalid command line. Usage: %s (-s fifo | -c fifo)\n",argv[0]);
	exit(0);
  }

  if (mode==SERVER) {
	/* server creates the fifo (or quits if it can't) */
	create_fifo(fifoname);
	fifo_server(fifoname);
  } else {
	fifo_client(fifoname);
  }

  return(1);
}

