Commit | Line | Data |
---|---|---|
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 | 18 | static int pathsize; /* pathname length */ |
9b6e6036 SL |
19 | |
20 | char * | |
90432f68 SL |
21 | getwd(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 | ||
87 | fail: | |
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 | */ | |
95 | static char * | |
96 | prepend(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 | } |