/***************************************************************************
 *                                                                         *
 * ======================================================================= *
 * Dan Alwood                                                              *
 * dalwood723@aol.com                                                      *
 *                                                                         *
 * Bug reports, questions, and suggestions should be emailed to:           *
 * mobius@mobius-soft.com                                                  *
 *                                                                         *
 * This software is provided under the terms of the GNU copyleft           *
 * (ftp://prep.ai.mit.edu/pub/gnu/COPYING-2.0), without a warranty         *
 * of any kind.  Use at your own risk.                                     *
 * ======================================================================= *
 *                                                                         *
 * Description: Wrapper for the sccs commands get, unget, delta, prs,      *
 *              sact, cdc, rmdel, and sccsdiff.  This program finds sccs   *
 *              program source files specified without directory names     *
 *              (ie. '/') on the command line by prepending path names     *
 *              found in the environment variable SCCS_PATH.  (The source  *
 *              file may or may not be specified with the "s.".)  sccs.c   *
 *              then execs one of the sccs commands (depending on          *
 *              argv[0]'s value) with full source file names.              *
 *                                                                         *
 * Notes:       Create a directory to hold the wrapped sccs commands.      *
 *              Example: mkdir /system/sccs                                *
 *              Create the sccs command files in this directory with the   *
 *              same inode (hard link).                                    *
 *              Example: cd /system/sccs                                   *
 *                       touch admin                                       *
 *                       ln admin cdc                                      *
 *                       ln admin delta                                    *
 *                       ln admin get                                      *
 *                       ln admin prs                                      *
 *                       ln admin rmdel                                    *
 *                       ln admin sact                                     *
 *                       ln admin sccsdiff                                 *
 *                       ln admin unget                                    *
 *              Compile this program to all of the sccs commands           *
 *              found in /system/sccs.  All file names in this directory   *
 *              are actually the same file (inode).                        *
 *              Example: cc -Aa -o /system/sccs/get sccs.c                 *
 *              Be sure /system/sccs (or whatever directory you have       *
 *              chosen to hold the front-end sccs commands) is in your     *
 *              path BEFORE the real sccs commands.                        *
 *                                                                         *
 *              If you want security, the directories which contain the    *
 *              sccs program source files (sccs repositories) should be    *
 *              writable only by the user 'sccs' (or whatever user you     *
 *              create to own all the sccs files).  This program is        *
 *              therefore run with its owner as 'sccs' and the SUID bit    *
 *              set (-r-sr-xr-x).                                          *
 *              Example: cd /system/sccs                                   *
 *                       chown sccs *                                      *
 *                       su sccs (or login as the sccs user)               *
 *                       chmod 4555 *                                      *
 *                                                                         *
 * Revisions:                                                              *
 *     01/19/93-Enhanced findfile() to prepend "s." to file name if it     *
 *              doesn't already have one.                                  *
 *                                                                         *
 ***************************************************************************/

static char SccsId[] = "@(#)sccs.c	1.2\t05/25/95"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Function Prototypes */
void getpaths(char *array_of_paths[]);
char *findfile(char *filename, char *path);

main(int argc, char **argv)
{
char *paths[256];            /* Up to 256 possible pointers to paths. */
short n = 0;
char **start_of_args = argv; /* Save beginning address of argv. */
char cmdstr[20];             /* Buffer for specific command (ex /usr/bin/get) */

/* TESTING	argv[0] = "get";
 * TESTING	argv[1] = "dan.c";
 * TESTING	argv[2] = "/arf2";
 * TESTING	argc = 3;*/

/*
 * Create list of individual paths from ':' delimited list.  *envp points to
 * "SCCS_PATH=...", and *paths[] will receive the array of path pointers.
 */
	getpaths(paths);

/*
 * Bypass any command line options for now, and look for file name.  Options
 * start with '-' ((*argv)[0] - the first character of each argument).  After
 * all arguments starting with '-' are exhausted, check remaining argument
 * (a filename) for any slashes.
 *
 * Bypass all options */
	while (--argc > 0 && (*++argv)[0] == '-');

/* Process remaining command line arguments; ie. the file names. */
	while (argc-- > 0)
	{
 /* If there are no slashes in file name... */
		if (!strchr(*argv, '/'))
		{

/*
 * Prepend each SCCS_PATH onto each file that does not already have a path
 * until file is found.  Leave file "pathless" if it can't be found (We'll
 * let the sccs commands do the complaining!).
 */
			n = 0;
			while (*paths[n] != NULL)
				*argv = findfile(*argv, paths[n++]);
		}
		*argv++;
	}
/*
 * All files that did not have a directory, and could be found with SCCS_PATH,
 * now have a directory.  All other file names have been left alone.  exec
 * the sccs command (argv[0]) with all options and file name arguments.
 */

	argv = start_of_args;      /* Restore original starting address of argv. */
	(void)sprintf(cmdstr, "/usr/bin/%s", argv[0]);
	if (!execv(cmdstr, argv))
	{
		(void)fprintf(stderr, "Unable to exec %s", cmdstr);
		exit (2);
	}
}



/***************************************************************************
 * Routine to look for value of "SCCS_PATH" in environment.  If found,     *
 * separate path list into an array of paths (**path_array).  Return to    *
 * main with this list.                                                    *
 ***************************************************************************/

void getpaths(char **path_array)
{
	int n;
	char *delims = ":";                   /* Delimiters for strtok function */
	char *wrk_paths;

	if ((wrk_paths = getenv("SCCS_PATH")) != NULL) /* If env variable set... */
	{
		path_array[0] = strtok(wrk_paths, delims); /* Get first path */
/*
 * Get all other paths.
 */
		for (n = 1; (path_array[n] = strtok(NULL, delims)) != NULL; n++);
	}
}



/***************************************************************************
 * Routine to create temporary full file name with passed path (trypath)  *
 * Test if this full filename exists.  If it does, return pointer to new  *
 * full file name.  Otherwise, return original pointer.                   *
 ***************************************************************************/

#define _INCLUDE_POSIX_SOURCE   /* Needed for access function */
#include <unistd.h>             /* Needed for access function */

char *findfile(char *filename, char *trypath)
{
	char *tempfile;

	/* Need 4 extra bytes for "/", null terminator, and possible "s.". */
	tempfile = malloc((strlen(filename)) + (strlen(trypath)) + 4);
	(void)strcpy(tempfile, trypath);
	(void)strcat(tempfile, "/");

	if (strncmp(filename, "s.", 2) != 0)   /* Prepend "s." to filename if not */
		(void)strcat(tempfile, "s.");      /* already present.                */

	(void)strcat(tempfile, filename);

	if (access(tempfile, F_OK) == 0)
		return tempfile;
	else
		free (tempfile);
		return filename;
}
