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