Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/cd.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (show annotations) (download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 6287 byte(s)
-updated to klibc-1.5.19
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1997-2005
5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 /*
42 * The cd and pwd commands.
43 */
44
45 #include "shell.h"
46 #include "var.h"
47 #include "nodes.h" /* for jobs.h */
48 #include "jobs.h"
49 #include "options.h"
50 #include "output.h"
51 #include "memalloc.h"
52 #include "error.h"
53 #include "exec.h"
54 #include "redir.h"
55 #include "main.h"
56 #include "mystring.h"
57 #include "show.h"
58 #include "cd.h"
59
60 #define CD_PHYSICAL 1
61 #define CD_PRINT 2
62
63 STATIC int docd(const char *, int);
64 STATIC const char *updatepwd(const char *);
65 STATIC char *getpwd(void);
66 STATIC int cdopt(void);
67
68 STATIC char *curdir = nullstr; /* current working directory */
69 STATIC char *physdir = nullstr; /* physical working directory */
70
71 STATIC int
72 cdopt()
73 {
74 int flags = 0;
75 int i, j;
76
77 j = 'L';
78 while ((i = nextopt("LP"))) {
79 if (i != j) {
80 flags ^= CD_PHYSICAL;
81 j = i;
82 }
83 }
84
85 return flags;
86 }
87
88 int
89 cdcmd(int argc, char **argv)
90 {
91 const char *dest;
92 const char *path;
93 const char *p;
94 char c;
95 struct stat statb;
96 int flags;
97
98 flags = cdopt();
99 dest = *argptr;
100 if (!dest)
101 dest = bltinlookup(homestr);
102 else if (dest[0] == '-' && dest[1] == '\0') {
103 dest = bltinlookup("OLDPWD");
104 flags |= CD_PRINT;
105 }
106 if (!dest)
107 dest = nullstr;
108 if (*dest == '/')
109 goto step6;
110 if (*dest == '.') {
111 c = dest[1];
112 dotdot:
113 switch (c) {
114 case '\0':
115 case '/':
116 goto step6;
117 case '.':
118 c = dest[2];
119 if (c != '.')
120 goto dotdot;
121 }
122 }
123 if (!*dest)
124 dest = ".";
125 path = bltinlookup("CDPATH");
126 while (path) {
127 c = *path;
128 p = padvance(&path, dest);
129 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
130 if (c && c != ':')
131 flags |= CD_PRINT;
132 docd:
133 if (!docd(p, flags))
134 goto out;
135 goto err;
136 }
137 }
138
139 step6:
140 p = dest;
141 goto docd;
142
143 err:
144 sh_error("can't cd to %s", dest);
145 /* NOTREACHED */
146 out:
147 if (flags & CD_PRINT)
148 out1fmt(snlfmt, curdir);
149 return 0;
150 }
151
152
153 /*
154 * Actually do the chdir. We also call hashcd to let the routines in exec.c
155 * know that the current directory has changed.
156 */
157
158 STATIC int
159 docd(const char *dest, int flags)
160 {
161 const char *dir = 0;
162 int err;
163
164 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
165
166 INTOFF;
167 if (!(flags & CD_PHYSICAL)) {
168 dir = updatepwd(dest);
169 if (dir)
170 dest = dir;
171 }
172 err = chdir(dest);
173 if (err)
174 goto out;
175 setpwd(dir, 1);
176 hashcd();
177 out:
178 INTON;
179 return err;
180 }
181
182
183 /*
184 * Update curdir (the name of the current directory) in response to a
185 * cd command.
186 */
187
188 STATIC const char *
189 updatepwd(const char *dir)
190 {
191 char *new;
192 char *p;
193 char *cdcomppath;
194 const char *lim;
195
196 cdcomppath = sstrdup(dir);
197 STARTSTACKSTR(new);
198 if (*dir != '/') {
199 if (curdir == nullstr)
200 return 0;
201 new = stputs(curdir, new);
202 }
203 new = makestrspace(strlen(dir) + 2, new);
204 lim = stackblock() + 1;
205 if (*dir != '/') {
206 if (new[-1] != '/')
207 USTPUTC('/', new);
208 if (new > lim && *lim == '/')
209 lim++;
210 } else {
211 USTPUTC('/', new);
212 cdcomppath++;
213 if (dir[1] == '/' && dir[2] != '/') {
214 USTPUTC('/', new);
215 cdcomppath++;
216 lim++;
217 }
218 }
219 p = strtok(cdcomppath, "/");
220 while (p) {
221 switch(*p) {
222 case '.':
223 if (p[1] == '.' && p[2] == '\0') {
224 while (new > lim) {
225 STUNPUTC(new);
226 if (new[-1] == '/')
227 break;
228 }
229 break;
230 } else if (p[1] == '\0')
231 break;
232 /* fall through */
233 default:
234 new = stputs(p, new);
235 USTPUTC('/', new);
236 }
237 p = strtok(0, "/");
238 }
239 if (new > lim)
240 STUNPUTC(new);
241 *new = 0;
242 return stackblock();
243 }
244
245
246 /*
247 * Find out what the current directory is. If we already know the current
248 * directory, this routine returns immediately.
249 */
250 inline
251 STATIC char *
252 getpwd()
253 {
254 #ifdef __GLIBC__
255 char *dir = getcwd(0, 0);
256 if (dir)
257 return dir;
258 #else
259 char buf[PATH_MAX];
260 if(getcwd(buf, sizeof(buf)))
261 return savestr(buf);
262 #endif
263 sh_warnx("getcwd() failed: %s", strerror(errno));
264 return nullstr;
265 }
266
267 int
268 pwdcmd(int argc, char **argv)
269 {
270 int flags;
271 const char *dir = curdir;
272
273 flags = cdopt();
274 if (flags) {
275 if (physdir == nullstr)
276 setpwd(dir, 0);
277 dir = physdir;
278 }
279 out1fmt(snlfmt, dir);
280 return 0;
281 }
282
283 void
284 setpwd(const char *val, int setold)
285 {
286 char *oldcur, *dir;
287
288 oldcur = dir = curdir;
289
290 if (setold) {
291 setvar("OLDPWD", oldcur, VEXPORT);
292 }
293 INTOFF;
294 if (physdir != nullstr) {
295 if (physdir != oldcur)
296 free(physdir);
297 physdir = nullstr;
298 }
299 if (oldcur == val || !val) {
300 char *s = getpwd();
301 physdir = s;
302 if (!val)
303 dir = s;
304 } else
305 dir = savestr(val);
306 if (oldcur != dir && oldcur != nullstr) {
307 free(oldcur);
308 }
309 curdir = dir;
310 INTON;
311 setvar("PWD", dir, VEXPORT);
312 }