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  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
27  *
28  * Sccsid @(#)pwd.c	1.6 (gritter) 6/15/05
29  */
30 
31 /* from OpenSolaris "pwd.c	1.10	05/06/08 SMI"	 SVr4.0 1.14.6.1 */
32 /*
33  *	UNIX shell
34  */
35 
36 #include	"mac.h"
37 #include	"defs.h"
38 #include	<errno.h>
39 #include	<sys/types.h>
40 #include	<sys/stat.h>
41 #include	<limits.h>
42 
43 #define	DOT		'.'
44 #define	SLASH	'/'
45 #define PARTLY	2
46 
47 static void rmslash(unsigned char *);
48 extern const char	longpwd[];
49 
50 unsigned char cwdname[PATH_MAX+1];
51 
52 static int 	didpwd = FALSE;
53 
54 void
cwd(register unsigned char * dir)55 cwd(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 = '\0';
86 		} else {
87 			*(pdir+1) = '\0';
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)=='\0')
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)=='\0'))
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 = '\0';
174 
175 	--pcwd;
176 	if(pcwd>cwdname && *pcwd==SLASH)
177 	{
178 		/* Remove trailing / */
179 
180 		*pcwd = '\0';
181 	}
182 	return;
183 }
184 
185 void
cwd2(void)186 cwd2(void)
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 *
cwdget(void)230 cwdget(void)
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 void
cwdprint(void)246 cwdprint(void)
247 {
248 	register unsigned char *cp;
249 
250 	cwd2();
251 	if (didpwd == FALSE) {
252 		if(getcwd(cwdname, PATH_MAX+1) == (char *)0) {
253 			if(errno && errno != ERANGE)
254 				error("cannot determine current directory");
255 			else
256 				error(longpwd);
257 		}
258 		didpwd = TRUE;
259 	}
260 
261 	for (cp = cwdname; *cp; cp++) {
262 	  prc_buff(*cp);
263 	}
264 
265 	prc_buff(NL);
266 	return;
267 }
268 
269 /*
270  *	This routine will remove repeated slashes from string.
271  */
272 
273 static void
rmslash(unsigned char * string)274 rmslash(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 = '\0';
297 	}
298 	return;
299 }
300