/*	THIS IS THE UNPUBLISHED SOURCE CODE OF REMBO		*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/
/*	So, use it if you like, but give me credit.		*/


/* 	Usage: plan [-f file_name] program_name			*/


/*	Description:					*/

/* 	This program takes the full pathname of an	*/
/* 	executable and runs it on a fifo in the 	*/
/*	user's home directory named .plan.  This	*/
/* 	way, when finger is executed, the output	*/
/* 	of the program goes to the fifo.		*/
	
/*	Written by:  Tony Rems 				*/

/* 	Send bugs and flames to /dev/null or 		*/
/* 	rembo@unisoft.com 				*/

/*	Modifications:					*/

/*	September 1991					*/
/*           (by Geoff Loker geoff@mdms.moore.com)	*/
/*	Modified the program so that the path to the    */
/*	.plan file is not hardcoded in.  Now any number	*/
/*	of users can use the program at the same time.	*/
/*	I also modified the program to use an optional	*/
/*	argument to specify which file to use.  The	*/
/*	default file used is still the user's .plan,	*/
/*	but this can now also be used to set up		*/
/*	.signatures or any other file the user wants.	*/

/*	Even more modifications				*/

/*	January 1992					*/
/*	      (by Karen Bruner napalm@ugcs.caltech.edu) */
/*	Added pid_deal function, so people can stick	*/
/* 	the program in their .login, and then have it	*/
/*	killed by their .logout.  Program will not	*/
/*	run if a .planpid file, the file with the PID	*/
/*	for plan, already exists in the user's home	*/
/*	directory.					*/

/*      Yet still more modifications                    */

/*      January 1992                                    */
/*      (by Dan Gezelter gezelter@lithium.cchem.berkeley.edu) */
/*      Modified pid_deal function to put the pid       */
/*      files in a subdirectory called .planpid/        */
/*      The pid files then take on the name of the      */
/*      host that plan is running on.   This was        */
/*      necessary to have plan working on a cluster     */
/*      of diskless workstations.                       */

#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>

/* Defines */
#define PERMS 0666
#define USAGE "%s [-f file_name] program_name\n"

/* Function prototypes */
void sig_handler();
int pid_deal();	

main (argc, argv)
int argc;
char *argv[];
{
        int c, fflg;
	char *file;
        extern char *optarg;
	extern int optind;
	int fd;
	int pid;
	int status;
	char *getenv(), *home, plan[256], *strcat(), *strcpy();
	int pid_check;
	
	fflg = c = 0;
	while ((c = getopt(argc, argv, "f:")) != EOF) {
	  file = optarg;
	  fflg++;
	}

/* Comment out the next line if you don't want to have PID recorded
   to file .planpid */

	pid_check = pid_deal(); /* check for .planpid, if none, write
				   .planpid */

/* Uncomment next line if you commented out previous line */

/*  pid_check = 1; */

  if (pid_check == 1)  /* execute remaining part of program if .planpid
			  does not exist, i.e., no other plan process is
			  running */
    {
	if (fflg)
	  strcpy(plan, file);
	else {
	  home = getenv("HOME");
	  strcpy(plan, home);
	  strcat(plan, "/.plan");
	}
/*	setenv("PLAN", plan, 1); */

	if ( argc != optind + 1 ) {
		fprintf (stderr, USAGE, argv[0]);
		exit(1);
	}  /* if */

/* Catch interrupts for cleanup */
	signal(SIGTERM, sig_handler);
	signal(SIGINT, sig_handler);
	signal(SIGHUP, sig_handler);

	unlink (plan);

/* Make the fifo */
	if ((mkfifo(plan, S_IFIFO | PERMS)) < 0 ) {
		perror("mkfifo");
		exit(2);
	}  /* if */

	while (1) {
		if ((fd = open(plan, O_WRONLY)) < 0 ) {
			perror("open");
			exit(3);
		} /* if */

/* Once our open completes we know that someone else has
 * opened the FIFO for reading, so we can know run our 
 * program on it.  So, we fork, exec our program and
 * wait for the child to complete.
 */
		switch (pid = fork()) {
			case -1:
				perror("fork");
				exit(4);
				break;
			case 0:
/* If we're in the child, we copy our fifo to stdout */
/* and exec the program given */
				dup2(fd, 1);
				execlp(argv[optind],argv[optind],(void *)NULL);
				perror("child returned");
				exit(5);
				break;
			default:
/* If we're in the parent, we close the pipe and wait */
				close(fd);
				while (wait(&status) != pid)
					;
				break;
		} /* switch */
		sleep(2);
		close(fd);
	} /* while */
    }  /* end of my if (pid_check... */

  else
    printf("plan already running\n");

} /* main */

void sig_handler()  /* cleanup */
{
	char *plan, *getenv();
	
	plan = getenv("PLAN");

	unlink(plan);
	exit(0);
}

int pid_deal()	/* function for recording pid and making sure process
		   isn't already running */
{
  char savepid[100];	/* string for file name */
  FILE *sp;
  int checker;		/* return value:  0 if .planpid exists, and
			   program shouldn't be run, 1 if not */
  char *home;
  char *host[64];
  int namelen;
  namelen = 64;

  home = getenv("HOME");		/* put save name for file */
  gethostname(host,namelen);            /* and host id */
  strcpy(savepid, home);		/* in savepid */
  strcat(savepid, "/.planpid/");
  strcat(savepid, (const char *)host);

  /* test for existence of .planpid by trying to open the file for reading 
   * return a zero if read was successful, i.e., file already exists 
  */

  if ((sp = fopen(savepid, "r")) != NULL) {
	checker = 0; 	
	fclose(sp);
  } else {
    	/* file doesn't exist, return a 1 to execute the rest of the program */
    checker = 1;
  }

  if (checker == 1) {
	if(( sp = fopen(savepid, "w")) != NULL) {
      		fprintf(sp, "%d", getpid());	/* puts PID for plan in file */
      		fclose(sp);
	}
    }

  return checker;
} 
