/*
 *	Network Queueing System (NQS)
 *  This version of NQS is Copyright (C) 1992  John Roman
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*
*  PROJECT:     Network Queueing System
*  AUTHOR:      John Roman
*
*  Modification history:
*
*       Version Who     When            Description
*       -------+-------+---------------+-------------------------
*       V01.10  JRR                     Initial version.
*       V01.20  JRR     16-Jan-1992	Added support for RS6000.
*       V01.30  JRR     17-Jan-1992	Fixed reference to dir.4.2.h for 
*					the RS6000.
*	V01.40	JRR	20-Jan-1992	Fixed directory stuff for RS6000.
*	V01.5 	JRR	28-Feb-1992	Added Cosmic V2 changes.
*	V01.6	JRR	17-Jun-1992	Added header.
*	V01.7	JRR	06-Nov-1992	Added support for HPUX.
*	V01.8	JRR	06-Apr-1993	Added support for DECOSF.
*	V01.9	JRR			Placeholder
*	V01.10	JRR	28-Feb-1994	Added support for SOLARIS.
*/
/*++ getwdir.c - Network Queueing System
 *
 * $Source: /usr2/jrroma/nqs/nqs-3.35.6/lib/RCS/getwdir.c,v $
 *
 * DESCRIPTION:
 *
 *
 *	Get current working directory (that should work on both
 *	System V and Berkeley 4.2 systems).  Note that things
 *	certainly would have been easier, if we had just used the
 *	standard getcwd() call of System V.  The only problem is
 *	that the System V version of getcwd() is implemented by
 *	using popen() to pipe the output of the pwd command into
 *	a returned buffer space, and I got tired of waiting so
 *	long.
 *
 *
 *	Author:
 *	-------
 *	Brent A. Kingsbury, Sterling Software Incorporated.
 *	August 12, 1985.
 *
 *
 * STANDARDS VIOLATIONS:
 *   None.
 *
 * REVISION HISTORY: ($Revision: 1.10 $ $Date: 1994/03/30 20:32:30 $ $State: Exp $)
 * $Log: getwdir.c,v $
 * Revision 1.10  1994/03/30  20:32:30  jrroma
 * Version 3.35.6
 *
 * Revision 1.9  93/07/13  21:31:23  jrroma
 * Version 3.34
 * 
 * Revision 1.8  92/12/22  15:46:03  jrroma
 * Version 3.30
 * 
 * Revision 1.7  92/11/06  13:00:08  jrroma
 * Added support for HPUX.
 * 
 * Revision 1.6  92/06/18  13:23:53  jrroma
 * Added gnu header
 * 
 * Revision 1.5  92/02/28  14:06:24  jrroma
 * Added Cosmic V2 changes.
 * 
 * Revision 1.4  92/01/20  14:35:34  jrroma
 * Fixed up dirent reference.
 * 
 * Revision 1.3  92/01/17  11:34:16  jrroma
 * Fixed reference to dir.4.2
 * 
 * Revision 1.2  92/01/16  15:51:23  jrroma
 * Added support for RS6000.
 * 
 * Revision 1.1  92/01/16  15:50:17  jrroma
 * Initial revision
 * 
 *
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#if	SYS52 
#include "dir.4.2.h"			/* Directory walker emulations */
#else
#if 	SGI | BSD43 | ULTRIX | DECOSF | IBMRS
#include <sys/dir.h>			/* Directory walking */
#else
#if 	HPUX
#include <ndir.h>
#else
#if     SOLARIS | LINUX
#include <dirent.h>
#else
BAD SYSTEM TYPE
#endif
#endif
#endif
#endif

#define	MAXPATHLEN	1500		/* Maximum path length possible */
					/* for getworkdir()  */


/*** getwdir
 *
 *
 *	char getwdir():
 *
 *	Returns:
 *		A pointer to the fully qualified path name of the
 *.		current working directory if successful;
 *		Otherwise, NULL is returned (an error occurred).
 *
 *		WARNING:
 *			If NULL is returned indicating that we were
 *			unsuccessful in determining the current working
 *			directory, then the current working directory of
 *			the caller may, or may NOT be the same directory
 *			as when this function was invoked!!!!!
 *
 *			In other words, if this function ever returns
 *			NULL, then the caller should bail out.
 */
char *getwdir ()
{
	static char path [MAXPATHLEN + 1];
	struct stat child;
	struct stat parent;
	struct stat walkparent;
	DIR *dir;
#if	IBMRS | SOLARIS | LINUX
	struct dirent *dirent;
#else
	struct direct *dirent;
#endif
	register char *ptrpath;
	register int i;

	ptrpath = path + MAXPATHLEN;
	*ptrpath-- = '\0';			/* Null terminate */
	if (stat (".", &child) == -1) {
		/* stat() failed */
		return (NULL);
	}
	for(;;) {
		if ((dir = opendir ("..")) == NULL) {
			/* opendir() failed */
			if (*++ptrpath != '\0') chdir (++ptrpath);
			return (NULL);
		}
		if (fstat (dir->dd_fd, &parent) == -1) {
			/* fstat() failed */
			if (*++ptrpath != '\0') chdir (++ptrpath);
			return (NULL);
		}
		if (chdir ("..") == -1) {
			/*  chdir() failed. */
			if (*++ptrpath != '\0') chdir (++ptrpath);
			return (NULL);
		}
		if (child.st_dev == parent.st_dev) {
			/*
			 *  The parent directory is on the same device as
			 *  the child directory.
			 */
			if (child.st_ino == parent.st_ino) {	/* At root */
				/*
				 *  Restore to the original working directory
				 *  and return to caller.
				 */
				if (*++ptrpath == '\0') {
					/*
					 *  We were at '/'.
					 */
					*--ptrpath = '/';
				}
				else if (chdir (ptrpath) == -1) return (NULL);
				return (ptrpath);
			}
			do {	/* Loop to locate parent's name */
				if ((dirent = readdir (dir)) == NULL) {
					/* Read error */
					if (*++ptrpath != '\0') {
						chdir (++ptrpath);
					}
					return (NULL);
				}
			} while (dirent->d_ino != child.st_ino);
		}
		else {
			/*
			 *  The parent directory is on a different device
			 *  than the child directory.
			 */
			do {
				if ((dirent = readdir (dir)) == NULL) {
					/* Read error */
					if (*++ptrpath != '\0') {
						chdir (++ptrpath);
					}
					return (NULL);
				}
				stat (dirent->d_name, &walkparent);
			} while (walkparent.st_ino != child.st_ino ||
				 walkparent.st_dev != child.st_dev);
		}
		closedir (dir);
		i = strlen (dirent->d_name);
		if (ptrpath - path < i) {
			/*
			 *  The full path name is simply too long.
			 */
			if (*++ptrpath != '\0') chdir (++ptrpath);
			return (NULL);
		}
		while (i > 0) *ptrpath-- = dirent->d_name [--i];
		*ptrpath-- = '/';
		/*
		 *  We did a chdir() to the parent directory, so now
		 *  the child should be the parent here for the next
		 *  iteration of the loop.
		 */
		child = parent;
	}
}
