Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide 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 niro 532 /*-
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     }