xref: /illumos-gate/usr/src/cmd/sh/pwd.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.14.6.1	*/
27 /*
28  *	UNIX shell
29  */
30 
31 #include	"mac.h"
32 #include	<errno.h>
33 #include	<sys/types.h>
34 #include	<sys/stat.h>
35 #include	<limits.h>
36 
37 #define	DOT		'.'
38 #define	NULL	0
39 #define	SLASH	'/'
40 #define PARTLY	2
41 
42 static void rmslash();
43 #ifdef __STDC__
44 extern const char	longpwd[];
45 #else
46 extern char	longpwd[];
47 #endif
48 extern char *getcwd();
49 
50 unsigned char cwdname[PATH_MAX+1];
51 
52 static int 	didpwd = FALSE;
53 
54 cwd(dir)
55 	register unsigned char *dir;
56 {
57 	register unsigned char *pcwd;
58 	register unsigned char *pdir;
59 
60 	/* First remove extra /'s */
61 
62 	rmslash(dir);
63 
64 	/* Now remove any .'s */
65 
66 	pdir = dir;
67 	if(*dir == SLASH)
68 		pdir++;
69 	while(*pdir) 			/* remove /./ by itself */
70 	{
71 		if((*pdir==DOT) && (*(pdir+1)==SLASH))
72 		{
73 			movstr(pdir+2, pdir);
74 			continue;
75 		}
76 		pdir++;
77 		while ((*pdir) && (*pdir != SLASH))
78 			pdir++;
79 		if (*pdir)
80 			pdir++;
81 	}
82 	/* take care of trailing /. */
83 	if(*(--pdir)==DOT && pdir > dir && *(--pdir)==SLASH) {
84 		if(pdir > dir) {
85 			*pdir = NULL;
86 		} else {
87 			*(pdir+1) = NULL;
88 		}
89 
90 	}
91 
92 	/* Remove extra /'s */
93 
94 	rmslash(dir);
95 
96 	/* Now that the dir is canonicalized, process it */
97 
98 	if(*dir==DOT && *(dir+1)==NULL)
99 	{
100 		return;
101 	}
102 
103 
104 	if(*dir==SLASH)
105 	{
106 		/* Absolute path */
107 
108 		pcwd = cwdname;
109 		*pcwd++ = *dir++;
110 		didpwd = PARTLY;
111 	}
112 	else
113 	{
114 		/* Relative path */
115 
116 		if (didpwd == FALSE)
117 			return;
118 		didpwd = PARTLY;
119 		pcwd = cwdname + length(cwdname) - 1;
120 		if(pcwd != cwdname+1)
121 			*pcwd++ = SLASH;
122 	}
123 	while(*dir)
124 	{
125 		if(*dir==DOT &&
126 		   *(dir+1)==DOT &&
127 		   (*(dir+2)==SLASH || *(dir+2)==NULL))
128 		{
129 			/* Parent directory, so backup one */
130 
131 			if( pcwd > cwdname+2 )
132 				--pcwd;
133 			while(*(--pcwd) != SLASH)
134 				;
135 			pcwd++;
136 			dir += 2;
137 			if(*dir==SLASH)
138 			{
139 				dir++;
140 			}
141 			continue;
142 		}
143 	 	if (pcwd >= &cwdname[PATH_MAX+1])
144 		{
145 			didpwd=FALSE;
146 			return;
147 		}
148 		*pcwd++ = *dir++;
149 		while((*dir) && (*dir != SLASH))
150 		{
151 	 		if (pcwd >= &cwdname[PATH_MAX+1])
152 			{
153 				didpwd=FALSE;
154 				return;
155 			}
156 			*pcwd++ = *dir++;
157 		}
158 		if (*dir)
159 		{
160 	 		if (pcwd >= &cwdname[PATH_MAX+1])
161 			{
162 				didpwd=FALSE;
163 				return;
164 			}
165 			*pcwd++ = *dir++;
166 		}
167 	}
168 	if (pcwd >= &cwdname[PATH_MAX+1])
169 	{
170 		didpwd=FALSE;
171 		return;
172 	}
173 	*pcwd = NULL;
174 
175 	--pcwd;
176 	if(pcwd>cwdname && *pcwd==SLASH)
177 	{
178 		/* Remove trailing / */
179 
180 		*pcwd = NULL;
181 	}
182 	return;
183 }
184 
185 void
186 cwd2()
187 {
188 	struct stat stat1, stat2;
189 	unsigned char *pcwd;
190 	/* check if there are any symbolic links in pathname */
191 
192 	if(didpwd == FALSE)
193 		return;
194 	pcwd = cwdname + 1;
195 	if(didpwd == PARTLY) {
196 		while (*pcwd)
197 		{
198 			char c;
199 			while((c = *pcwd++) != SLASH && c != '\0');
200 			*--pcwd = '\0';
201 			if (lstat((char *)cwdname, &stat1) == -1
202 		    	|| (stat1.st_mode & S_IFMT) == S_IFLNK) {
203 				didpwd = FALSE;
204 				*pcwd = c;
205 				return;
206 			}
207 			*pcwd = c;
208 			if(c)
209 				pcwd++;
210 		}
211 		didpwd = TRUE;
212 	} else
213 		if (stat((char *)cwdname, &stat1) == -1) {
214 			didpwd = FALSE;
215 			return;
216 		}
217 	/*
218 	 * check if ino's and dev's match; pathname could
219 	 * consist of symbolic links with ".."
220 	 */
221 
222 	if (stat(".", &stat2) == -1
223 	    || stat1.st_dev != stat2.st_dev
224 	    || stat1.st_ino != stat2.st_ino)
225 		didpwd = FALSE;
226 	return;
227 }
228 
229 unsigned char *
230 cwdget()
231 {
232 	cwd2();
233 	if (didpwd == FALSE) {
234 		if(getcwd(cwdname, PATH_MAX+1) == (char *)0)
235 			*cwdname = 0;
236 		didpwd = TRUE;
237 	}
238 	return (cwdname);
239 }
240 
241 /*
242  *	Print the current working directory.
243  */
244 
245 cwdprint()
246 {
247 	register unsigned char *cp;
248 
249 	cwd2();
250 	if (didpwd == FALSE) {
251 		if(getcwd(cwdname, PATH_MAX+1) == (char *)0) {
252 			if(errno && errno != ERANGE)
253 				error("cannot determine current directory");
254 			else
255 				error(longpwd);
256 		}
257 		didpwd = TRUE;
258 	}
259 
260 	for (cp = cwdname; *cp; cp++) {
261 	  prc_buff(*cp);
262 	}
263 
264 	prc_buff(NL);
265 	return;
266 }
267 
268 /*
269  *	This routine will remove repeated slashes from string.
270  */
271 
272 static void
273 rmslash(string)
274 	unsigned char *string;
275 {
276 	register unsigned char *pstring;
277 
278 	pstring = string;
279 	while(*pstring)
280 	{
281 		if(*pstring==SLASH && *(pstring+1)==SLASH)
282 		{
283 			/* Remove repeated SLASH's */
284 
285 			movstr(pstring+1, pstring);
286 			continue;
287 		}
288 		pstring++;
289 	}
290 
291 	--pstring;
292 	if(pstring>string && *pstring==SLASH)
293 	{
294 		/* Remove trailing / */
295 
296 		*pstring = NULL;
297 	}
298 	return;
299 }
300