Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 6179 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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 "mystring.h"
56 #include "show.h"
57 #include "cd.h"
58
59 #define CD_PHYSICAL 1
60 #define CD_PRINT 2
61
62 STATIC int docd(const char *, int);
63 STATIC const char *updatepwd(const char *);
64 STATIC char *getpwd(void);
65 STATIC int cdopt(void);
66
67 STATIC char *curdir = nullstr; /* current working directory */
68 STATIC char *physdir = nullstr; /* physical working directory */
69
70 STATIC int
71 cdopt()
72 {
73 int flags = 0;
74 int i, j;
75
76 j = 'L';
77 while ((i = nextopt("LP"))) {
78 if (i != j) {
79 flags ^= CD_PHYSICAL;
80 j = i;
81 }
82 }
83
84 return flags;
85 }
86
87 int
88 cdcmd(int argc, char **argv)
89 {
90 const char *dest;
91 const char *path;
92 const char *p;
93 char c;
94 struct stat statb;
95 int flags;
96
97 flags = cdopt();
98 dest = *argptr;
99 if (!dest)
100 dest = bltinlookup(homestr);
101 else if (dest[0] == '-' && dest[1] == '\0') {
102 dest = bltinlookup("OLDPWD");
103 flags |= CD_PRINT;
104 }
105 if (!dest)
106 dest = nullstr;
107 if (*dest == '/')
108 goto step7;
109 if (*dest == '.') {
110 c = dest[1];
111 dotdot:
112 switch (c) {
113 case '\0':
114 case '/':
115 goto step6;
116 case '.':
117 c = dest[2];
118 if (c != '.')
119 goto dotdot;
120 }
121 }
122 if (!*dest)
123 dest = ".";
124 if (!(path = bltinlookup("CDPATH"))) {
125 step6:
126 step7:
127 p = dest;
128 goto docd;
129 }
130 do {
131 c = *path;
132 p = padvance(&path, dest);
133 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
134 if (c && c != ':')
135 flags |= CD_PRINT;
136 docd:
137 if (!docd(p, flags))
138 goto out;
139 break;
140 }
141 } while (path);
142 sh_error("can't cd to %s", dest);
143 /* NOTREACHED */
144 out:
145 if (flags & CD_PRINT)
146 out1fmt(snlfmt, curdir);
147 return 0;
148 }
149
150
151 /*
152 * Actually do the chdir. We also call hashcd to let the routines in exec.c
153 * know that the current directory has changed.
154 */
155
156 STATIC int
157 docd(const char *dest, int flags)
158 {
159 const char *dir = 0;
160 int err;
161
162 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
163
164 INTOFF;
165 if (!(flags & CD_PHYSICAL)) {
166 dir = updatepwd(dest);
167 if (dir)
168 dest = dir;
169 }
170 err = chdir(dest);
171 if (err)
172 goto out;
173 setpwd(dir, 1);
174 hashcd();
175 out:
176 INTON;
177 return err;
178 }
179
180
181 /*
182 * Update curdir (the name of the current directory) in response to a
183 * cd command.
184 */
185
186 STATIC const char *
187 updatepwd(const char *dir)
188 {
189 char *new;
190 char *p;
191 char *cdcomppath;
192 const char *lim;
193
194 cdcomppath = sstrdup(dir);
195 STARTSTACKSTR(new);
196 if (*dir != '/') {
197 if (curdir == nullstr)
198 return 0;
199 new = stputs(curdir, new);
200 }
201 new = makestrspace(strlen(dir) + 2, new);
202 lim = stackblock() + 1;
203 if (*dir != '/') {
204 if (new[-1] != '/')
205 USTPUTC('/', new);
206 if (new > lim && *lim == '/')
207 lim++;
208 } else {
209 USTPUTC('/', new);
210 cdcomppath++;
211 if (dir[1] == '/' && dir[2] != '/') {
212 USTPUTC('/', new);
213 cdcomppath++;
214 lim++;
215 }
216 }
217 p = strtok(cdcomppath, "/");
218 while (p) {
219 switch(*p) {
220 case '.':
221 if (p[1] == '.' && p[2] == '\0') {
222 while (new > lim) {
223 STUNPUTC(new);
224 if (new[-1] == '/')
225 break;
226 }
227 break;
228 } else if (p[1] == '\0')
229 break;
230 /* fall through */
231 default:
232 new = stputs(p, new);
233 USTPUTC('/', new);
234 }
235 p = strtok(0, "/");
236 }
237 if (new > lim)
238 STUNPUTC(new);
239 *new = 0;
240 return stackblock();
241 }
242
243
244 #define MAXPWD 256
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 char buf[PATH_MAX];
255 char *dir = getcwd(buf, sizeof(buf));
256 return dir ? savestr(dir) : nullstr;
257 }
258
259 int
260 pwdcmd(int argc, char **argv)
261 {
262 int flags;
263 const char *dir = curdir;
264
265 flags = cdopt();
266 if (flags) {
267 if (physdir == nullstr)
268 setpwd(dir, 0);
269 dir = physdir;
270 }
271 out1fmt(snlfmt, dir);
272 return 0;
273 }
274
275 void
276 setpwd(const char *val, int setold)
277 {
278 char *oldcur, *dir;
279
280 oldcur = dir = curdir;
281
282 if (setold) {
283 setvar("OLDPWD", oldcur, VEXPORT);
284 }
285 INTOFF;
286 if (physdir != nullstr) {
287 if (physdir != oldcur)
288 free(physdir);
289 physdir = nullstr;
290 }
291 if (oldcur == val || !val) {
292 char *s = getpwd();
293 physdir = s;
294 if (!val)
295 dir = s;
296 } else
297 dir = savestr(val);
298 if (oldcur != dir && oldcur != nullstr) {
299 free(oldcur);
300 }
301 curdir = dir;
302 INTON;
303 setvar("PWD", dir, VEXPORT);
304 }