new version from nicklin -- bugs to him
[unix-history] / usr / src / lib / libc / gen / getcwd.c
CommitLineData
90432f68 1/* @(#)getcwd.c 4.6 (Berkeley) %G% */
9b6e6036
SL
2
3/*
90432f68
SL
4 * getwd() returns the pathname of the current working directory. On error
5 * an error message is copied to pathname and null pointer is returned.
9b6e6036 6 */
87dccba9
SL
7#include <sys/param.h>
8#include <sys/stat.h>
9#include <sys/dir.h>
9b6e6036 10
90432f68
SL
11#define CURDIR "."
12#define GETWDERR(s) strcpy(pathname, (s));
13#define PARENTDIR ".."
14#define PATHSEP "/"
15#define PATHSIZE 1024
16#define ROOTDIR "/"
9b6e6036 17
90432f68 18static int pathsize; /* pathname length */
9b6e6036
SL
19
20char *
90432f68
SL
21getwd(pathname)
22 char *pathname;
9b6e6036 23{
90432f68
SL
24 char pathbuf[PATHSIZE]; /* temporary pathname buffer */
25 char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
26 char *prepend(); /* prepend dirname to pathname */
27 dev_t rdev; /* root device number */
28 DIR *dirp; /* directory stream */
29 ino_t rino; /* root inode number */
30 struct direct *dir; /* directory entry struct */
31 struct stat d ,dd; /* file status struct */
9b6e6036 32
90432f68
SL
33 pathsize = 0;
34 *pnptr = '\0';
35 stat(ROOTDIR, &d);
9b6e6036
SL
36 rdev = d.st_dev;
37 rino = d.st_ino;
38 for (;;) {
90432f68
SL
39 stat(CURDIR, &d);
40 if (d.st_ino == rino && d.st_dev == rdev)
41 break; /* reached root directory */
42 if ((dirp = opendir(PARENTDIR)) == NULL) {
43 GETWDERR("getwd: can't open ..");
44 goto fail;
45 }
46 if (chdir(PARENTDIR) < 0) {
47 GETWDERR("getwd: can't chdir to ..");
48 goto fail;
49 }
50 fstat(dirp->dd_fd, &dd);
829e7c26 51 if (d.st_dev == dd.st_dev) {
90432f68
SL
52 if (d.st_ino == dd.st_ino) {
53 /* reached root directory */
54 closedir(dirp);
55 break;
56 }
07fbd99b 57 do {
90432f68
SL
58 if ((dir = readdir(dirp)) == NULL) {
59 closedir(dirp);
60 GETWDERR("getwd: read error in ..");
61 goto fail;
62 }
07fbd99b 63 } while (dir->d_ino != d.st_ino);
829e7c26
SL
64 } else
65 do {
90432f68
SL
66 if((dir = readdir(dirp)) == NULL) {
67 closedir(dirp);
68 GETWDERR("getwd: read error in ..");
69 goto fail;
70 }
9b6e6036
SL
71 stat(dir->d_name, &dd);
72 } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
90432f68
SL
73 closedir(dirp);
74 pnptr = prepend(PATHSEP, prepend(dir->d_name, pnptr));
75 }
76 if (*pnptr == '\0') /* current dir == root dir */
77 strcpy(pathname, ROOTDIR);
78 else {
79 strcpy(pathname, pnptr);
80 if (chdir(pnptr) < 0) {
81 GETWDERR("getwd: can't change back to .");
82 return (NULL);
83 }
9b6e6036 84 }
90432f68
SL
85 return (pathname);
86
87fail:
88 chdir(prepend(CURDIR, pnptr));
89 return (NULL);
9b6e6036
SL
90}
91
90432f68
SL
92/*
93 * prepend() tacks a directory name onto the front of a pathname.
94 */
95static char *
96prepend(dirname, pathname)
97 register char *dirname;
98 register char *pathname;
9b6e6036 99{
90432f68 100 register int i; /* directory name size counter */
9b6e6036 101
90432f68
SL
102 for (i = 0; *dirname != '\0'; i++, dirname++)
103 continue;
104 if ((pathsize += i) < PATHSIZE)
105 while (i-- > 0)
106 *--pathname = *--dirname;
107 return (pathname);
9b6e6036 108}