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
cwd(unsigned char * dir)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
cwd2()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 *
cwdget()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
cwdprint(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
rmslash(string)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