xref: /csrg-svn/lib/libc/gen/getcwd.c (revision 26565)
121345Sdist /*
221345Sdist  * Copyright (c) 1980 Regents of the University of California.
321345Sdist  * All rights reserved.  The Berkeley software License Agreement
421345Sdist  * specifies the terms and conditions for redistribution.
521345Sdist  */
69986Ssam 
7*26565Sdonn #if defined(LIBC_SCCS) && !defined(lint)
8*26565Sdonn static char sccsid[] = "@(#)getcwd.c	5.2 (Berkeley) 03/09/86";
9*26565Sdonn #endif LIBC_SCCS and not lint
1021345Sdist 
119986Ssam /*
1210155Ssam  * getwd() returns the pathname of the current working directory. On error
1310155Ssam  * an error message is copied to pathname and null pointer is returned.
149986Ssam  */
1510088Ssam #include <sys/param.h>
1610088Ssam #include <sys/stat.h>
1710088Ssam #include <sys/dir.h>
189986Ssam 
1910155Ssam #define GETWDERR(s)	strcpy(pathname, (s));
209986Ssam 
2111370Snicklin char *strcpy();
2210155Ssam static int pathsize;			/* pathname length */
2310127Ssam 
249986Ssam char *
2510155Ssam getwd(pathname)
2610155Ssam 	char *pathname;
279986Ssam {
2810156Ssam 	char pathbuf[MAXPATHLEN];		/* temporary pathname buffer */
2910155Ssam 	char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
3017867Sralph 	char curdir[MAXPATHLEN];	/* current directory buffer */
3117867Sralph 	char *dptr = curdir;		/* directory pointer */
3210155Ssam 	char *prepend();		/* prepend dirname to pathname */
3317867Sralph 	dev_t cdev, rdev;		/* current & root device number */
3417867Sralph 	ino_t cino, rino;		/* current & root inode number */
3510155Ssam 	DIR *dirp;			/* directory stream */
3610155Ssam 	struct direct *dir;		/* directory entry struct */
3717867Sralph 	struct stat d, dd;		/* file status struct */
389986Ssam 
3910155Ssam 	pathsize = 0;
4010155Ssam 	*pnptr = '\0';
4117867Sralph 	if (stat("/", &d) < 0) {
4217867Sralph 		GETWDERR("getwd: can't stat /");
4317867Sralph 		return (NULL);
4417867Sralph 	}
459986Ssam 	rdev = d.st_dev;
469986Ssam 	rino = d.st_ino;
4717867Sralph 	strcpy(dptr, "./");
4817867Sralph 	dptr += 2;
4917867Sralph 	if (stat(curdir, &d) < 0) {
5017867Sralph 		GETWDERR("getwd: can't stat .");
5117867Sralph 		return (NULL);
5217867Sralph 	}
539986Ssam 	for (;;) {
5410155Ssam 		if (d.st_ino == rino && d.st_dev == rdev)
5510155Ssam 			break;		/* reached root directory */
5617867Sralph 		cino = d.st_ino;
5717867Sralph 		cdev = d.st_dev;
5817867Sralph 		strcpy(dptr, "../");
5917867Sralph 		dptr += 3;
6017867Sralph 		if ((dirp = opendir(curdir)) == NULL) {
6110155Ssam 			GETWDERR("getwd: can't open ..");
6217867Sralph 			return (NULL);
6310155Ssam 		}
6417867Sralph 		fstat(dirp->dd_fd, &d);
6517867Sralph 		if (cdev == d.st_dev) {
6617867Sralph 			if (cino == d.st_ino) {
6710155Ssam 				/* reached root directory */
6810155Ssam 				closedir(dirp);
6910155Ssam 				break;
7010155Ssam 			}
7110140Ssam 			do {
7210155Ssam 				if ((dir = readdir(dirp)) == NULL) {
7310155Ssam 					closedir(dirp);
7410155Ssam 					GETWDERR("getwd: read error in ..");
7517867Sralph 					return (NULL);
7610155Ssam 				}
7717867Sralph 			} while (dir->d_ino != cino);
7810126Ssam 		} else
7910126Ssam 			do {
8017867Sralph 				if ((dir = readdir(dirp)) == NULL) {
8110155Ssam 					closedir(dirp);
8210155Ssam 					GETWDERR("getwd: read error in ..");
8317867Sralph 					return (NULL);
8410155Ssam 				}
8517867Sralph 				strcpy(dptr, dir->d_name);
8617867Sralph 				lstat(curdir, &dd);
8717867Sralph 			} while(dd.st_ino != cino || dd.st_dev != cdev);
8810155Ssam 		closedir(dirp);
8917867Sralph 		pnptr = prepend("/", prepend(dir->d_name, pnptr));
909986Ssam 	}
9110155Ssam 	if (*pnptr == '\0')		/* current dir == root dir */
9217867Sralph 		strcpy(pathname, "/");
9317867Sralph 	else
9410155Ssam 		strcpy(pathname, pnptr);
9510155Ssam 	return (pathname);
969986Ssam }
979986Ssam 
9810155Ssam /*
9910155Ssam  * prepend() tacks a directory name onto the front of a pathname.
10010155Ssam  */
10110155Ssam static char *
10210155Ssam prepend(dirname, pathname)
10310155Ssam 	register char *dirname;
10410155Ssam 	register char *pathname;
1059986Ssam {
10610155Ssam 	register int i;			/* directory name size counter */
1079986Ssam 
10810155Ssam 	for (i = 0; *dirname != '\0'; i++, dirname++)
10910155Ssam 		continue;
11010156Ssam 	if ((pathsize += i) < MAXPATHLEN)
11110155Ssam 		while (i-- > 0)
11210155Ssam 			*--pathname = *--dirname;
11310155Ssam 	return (pathname);
1149986Ssam }
115