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