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