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