~xnox/ubuntu/trusty/gcc-arm-linux-androideabi/dima

« back to all changes in this revision

Viewing changes to android/system/core/sh/cd.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2013-07-05 10:12:24 UTC
  • Revision ID: package-import@ubuntu.com-20130705101224-6qo3e8jbz8p31aa1
Tags: upstream-0.20130705.1
ImportĀ upstreamĀ versionĀ 0.20130705.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $      */
 
2
 
 
3
/*-
 
4
 * Copyright (c) 1991, 1993
 
5
 *      The Regents of the University of California.  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/cdefs.h>
 
36
#ifndef lint
 
37
#if 0
 
38
static char sccsid[] = "@(#)cd.c        8.2 (Berkeley) 5/4/95";
 
39
#else
 
40
__RCSID("$NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $");
 
41
#endif
 
42
#endif /* not lint */
 
43
 
 
44
#include <sys/types.h>
 
45
#include <sys/stat.h>
 
46
#include <stdlib.h>
 
47
#include <string.h>
 
48
#include <unistd.h>
 
49
#include <errno.h>
 
50
 
 
51
/*
 
52
 * The cd and pwd commands.
 
53
 */
 
54
 
 
55
#include "shell.h"
 
56
#include "var.h"
 
57
#include "nodes.h"      /* for jobs.h */
 
58
#include "jobs.h"
 
59
#include "options.h"
 
60
#include "output.h"
 
61
#include "memalloc.h"
 
62
#include "error.h"
 
63
#include "exec.h"
 
64
#include "redir.h"
 
65
#include "mystring.h"
 
66
#include "show.h"
 
67
#include "cd.h"
 
68
 
 
69
STATIC int docd(char *, int);
 
70
STATIC char *getcomponent(void);
 
71
STATIC void updatepwd(char *);
 
72
STATIC void find_curdir(int noerror);
 
73
 
 
74
char *curdir = NULL;            /* current working directory */
 
75
char *prevdir;                  /* previous working directory */
 
76
STATIC char *cdcomppath;
 
77
 
 
78
int
 
79
cdcmd(int argc, char **argv)
 
80
{
 
81
        const char *dest;
 
82
        const char *path;
 
83
        char *p, *d;
 
84
        struct stat statb;
 
85
        int print = cdprint;    /* set -cdprint to enable */
 
86
 
 
87
        nextopt(nullstr);
 
88
 
 
89
        /*
 
90
         * Try (quite hard) to have 'curdir' defined, nothing has set
 
91
         * it on entry to the shell, but we want 'cd fred; cd -' to work.
 
92
         */
 
93
        getpwd(1);
 
94
        dest = *argptr;
 
95
        if (dest == NULL) {
 
96
                dest = bltinlookup("HOME", 1);
 
97
                if (dest == NULL)
 
98
                        error("HOME not set");
 
99
        } else {
 
100
                if (argptr[1]) {
 
101
                        /* Do 'ksh' style substitution */
 
102
                        if (!curdir)
 
103
                                error("PWD not set");
 
104
                        p = strstr(curdir, dest);
 
105
                        if (!p)
 
106
                                error("bad substitution");
 
107
                        d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
 
108
                        memcpy(d, curdir, p - curdir);
 
109
                        strcpy(d + (p - curdir), argptr[1]);
 
110
                        strcat(d, p + strlen(dest));
 
111
                        dest = d;
 
112
                        print = 1;
 
113
                }
 
114
        }
 
115
 
 
116
        if (dest[0] == '-' && dest[1] == '\0') {
 
117
                dest = prevdir ? prevdir : curdir;
 
118
                print = 1;
 
119
        }
 
120
        if (*dest == '\0')
 
121
                dest = ".";
 
122
        if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
 
123
                path = nullstr;
 
124
        while ((p = padvance(&path, dest)) != NULL) {
 
125
                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
 
126
                        if (!print) {
 
127
                                /*
 
128
                                 * XXX - rethink
 
129
                                 */
 
130
                                if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
 
131
                                        p += 2;
 
132
                                print = strcmp(p, dest);
 
133
                        }
 
134
                        if (docd(p, print) >= 0)
 
135
                                return 0;
 
136
 
 
137
                }
 
138
        }
 
139
        error("can't cd to %s", dest);
 
140
        /* NOTREACHED */
 
141
}
 
142
 
 
143
 
 
144
/*
 
145
 * Actually do the chdir.  In an interactive shell, print the
 
146
 * directory name if "print" is nonzero.
 
147
 */
 
148
 
 
149
STATIC int
 
150
docd(char *dest, int print)
 
151
{
 
152
        char *p;
 
153
        char *q;
 
154
        char *component;
 
155
        struct stat statb;
 
156
        int first;
 
157
        int badstat;
 
158
 
 
159
        TRACE(("docd(\"%s\", %d) called\n", dest, print));
 
160
 
 
161
        /*
 
162
         *  Check each component of the path. If we find a symlink or
 
163
         *  something we can't stat, clear curdir to force a getcwd()
 
164
         *  next time we get the value of the current directory.
 
165
         */
 
166
        badstat = 0;
 
167
        cdcomppath = stalloc(strlen(dest) + 1);
 
168
        scopy(dest, cdcomppath);
 
169
        STARTSTACKSTR(p);
 
170
        if (*dest == '/') {
 
171
                STPUTC('/', p);
 
172
                cdcomppath++;
 
173
        }
 
174
        first = 1;
 
175
        while ((q = getcomponent()) != NULL) {
 
176
                if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
 
177
                        continue;
 
178
                if (! first)
 
179
                        STPUTC('/', p);
 
180
                first = 0;
 
181
                component = q;
 
182
                while (*q)
 
183
                        STPUTC(*q++, p);
 
184
                if (equal(component, ".."))
 
185
                        continue;
 
186
                STACKSTRNUL(p);
 
187
                if ((lstat(stackblock(), &statb) < 0)
 
188
                    || (S_ISLNK(statb.st_mode)))  {
 
189
                        /* print = 1; */
 
190
                        badstat = 1;
 
191
                        break;
 
192
                }
 
193
        }
 
194
 
 
195
        INTOFF;
 
196
        if (chdir(dest) < 0) {
 
197
                INTON;
 
198
                return -1;
 
199
        }
 
200
        updatepwd(badstat ? NULL : dest);
 
201
        INTON;
 
202
        if (print && iflag && curdir)
 
203
                out1fmt("%s\n", curdir);
 
204
        return 0;
 
205
}
 
206
 
 
207
 
 
208
/*
 
209
 * Get the next component of the path name pointed to by cdcomppath.
 
210
 * This routine overwrites the string pointed to by cdcomppath.
 
211
 */
 
212
 
 
213
STATIC char *
 
214
getcomponent()
 
215
{
 
216
        char *p;
 
217
        char *start;
 
218
 
 
219
        if ((p = cdcomppath) == NULL)
 
220
                return NULL;
 
221
        start = cdcomppath;
 
222
        while (*p != '/' && *p != '\0')
 
223
                p++;
 
224
        if (*p == '\0') {
 
225
                cdcomppath = NULL;
 
226
        } else {
 
227
                *p++ = '\0';
 
228
                cdcomppath = p;
 
229
        }
 
230
        return start;
 
231
}
 
232
 
 
233
 
 
234
 
 
235
/*
 
236
 * Update curdir (the name of the current directory) in response to a
 
237
 * cd command.  We also call hashcd to let the routines in exec.c know
 
238
 * that the current directory has changed.
 
239
 */
 
240
 
 
241
STATIC void
 
242
updatepwd(char *dir)
 
243
{
 
244
        char *new;
 
245
        char *p;
 
246
 
 
247
        hashcd();                               /* update command hash table */
 
248
 
 
249
        /*
 
250
         * If our argument is NULL, we don't know the current directory
 
251
         * any more because we traversed a symbolic link or something
 
252
         * we couldn't stat().
 
253
         */
 
254
        if (dir == NULL || curdir == NULL)  {
 
255
                if (prevdir)
 
256
                        ckfree(prevdir);
 
257
                INTOFF;
 
258
                prevdir = curdir;
 
259
                curdir = NULL;
 
260
                getpwd(1);
 
261
                INTON;
 
262
                if (curdir)
 
263
                        setvar("PWD", curdir, VEXPORT);
 
264
                else
 
265
                        unsetvar("PWD", 0);
 
266
                return;
 
267
        }
 
268
        cdcomppath = stalloc(strlen(dir) + 1);
 
269
        scopy(dir, cdcomppath);
 
270
        STARTSTACKSTR(new);
 
271
        if (*dir != '/') {
 
272
                p = curdir;
 
273
                while (*p)
 
274
                        STPUTC(*p++, new);
 
275
                if (p[-1] == '/')
 
276
                        STUNPUTC(new);
 
277
        }
 
278
        while ((p = getcomponent()) != NULL) {
 
279
                if (equal(p, "..")) {
 
280
                        while (new > stackblock() && (STUNPUTC(new), *new) != '/');
 
281
                } else if (*p != '\0' && ! equal(p, ".")) {
 
282
                        STPUTC('/', new);
 
283
                        while (*p)
 
284
                                STPUTC(*p++, new);
 
285
                }
 
286
        }
 
287
        if (new == stackblock())
 
288
                STPUTC('/', new);
 
289
        STACKSTRNUL(new);
 
290
        INTOFF;
 
291
        if (prevdir)
 
292
                ckfree(prevdir);
 
293
        prevdir = curdir;
 
294
        curdir = savestr(stackblock());
 
295
        setvar("PWD", curdir, VEXPORT);
 
296
        INTON;
 
297
}
 
298
 
 
299
/*
 
300
 * Posix says the default should be 'pwd -L' (as below), however
 
301
 * the 'cd' command (above) does something much nearer to the
 
302
 * posix 'cd -P' (not the posix default of 'cd -L').
 
303
 * If 'cd' is changed to support -P/L then the default here
 
304
 * needs to be revisited if the historic behaviour is to be kept.
 
305
 */
 
306
 
 
307
int
 
308
pwdcmd(int argc, char **argv)
 
309
{
 
310
        int i;
 
311
        char opt = 'L';
 
312
 
 
313
        while ((i = nextopt("LP")) != '\0')
 
314
                opt = i;
 
315
        if (*argptr)
 
316
                error("unexpected argument");
 
317
 
 
318
        if (opt == 'L')
 
319
                getpwd(0);
 
320
        else
 
321
                find_curdir(0);
 
322
 
 
323
        setvar("PWD", curdir, VEXPORT);
 
324
        out1str(curdir);
 
325
        out1c('\n');
 
326
        return 0;
 
327
}
 
328
 
 
329
 
 
330
 
 
331
 
 
332
#define MAXPWD 256
 
333
 
 
334
/*
 
335
 * Find out what the current directory is. If we already know the current
 
336
 * directory, this routine returns immediately.
 
337
 */
 
338
void
 
339
getpwd(int noerror)
 
340
{
 
341
        char *pwd;
 
342
        struct stat stdot, stpwd;
 
343
        static int first = 1;
 
344
 
 
345
        if (curdir)
 
346
                return;
 
347
 
 
348
        if (first) {
 
349
                first = 0;
 
350
                pwd = getenv("PWD");
 
351
                if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
 
352
                    stat(pwd, &stpwd) != -1 &&
 
353
                    stdot.st_dev == stpwd.st_dev &&
 
354
                    stdot.st_ino == stpwd.st_ino) {
 
355
                        curdir = savestr(pwd);
 
356
                        return;
 
357
                }
 
358
        }
 
359
 
 
360
        find_curdir(noerror);
 
361
 
 
362
        return;
 
363
}
 
364
 
 
365
STATIC void
 
366
find_curdir(int noerror)
 
367
{
 
368
        int i;
 
369
        char *pwd;
 
370
 
 
371
        /*
 
372
         * Things are a bit complicated here; we could have just used
 
373
         * getcwd, but traditionally getcwd is implemented using popen
 
374
         * to /bin/pwd. This creates a problem for us, since we cannot
 
375
         * keep track of the job if it is being ran behind our backs.
 
376
         * So we re-implement getcwd(), and we suppress interrupts
 
377
         * throughout the process. This is not completely safe, since
 
378
         * the user can still break out of it by killing the pwd program.
 
379
         * We still try to use getcwd for systems that we know have a
 
380
         * c implementation of getcwd, that does not open a pipe to
 
381
         * /bin/pwd.
 
382
         */
 
383
#if defined(__NetBSD__) || defined(__SVR4) || defined(__linux__)
 
384
        for (i = MAXPWD;; i *= 2) {
 
385
                pwd = stalloc(i);
 
386
                if (getcwd(pwd, i) != NULL) {
 
387
                        curdir = savestr(pwd);
 
388
                        return;
 
389
                }
 
390
                stunalloc(pwd);
 
391
                if (errno == ERANGE)
 
392
                        continue;
 
393
                if (!noerror)
 
394
                        error("getcwd() failed: %s", strerror(errno));
 
395
                return;
 
396
        }
 
397
#else
 
398
        {
 
399
                char *p;
 
400
                int status;
 
401
                struct job *jp;
 
402
                int pip[2];
 
403
 
 
404
                pwd = stalloc(MAXPWD);
 
405
                INTOFF;
 
406
                if (pipe(pip) < 0)
 
407
                        error("Pipe call failed");
 
408
                jp = makejob((union node *)NULL, 1);
 
409
                if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
 
410
                        (void) close(pip[0]);
 
411
                        if (pip[1] != 1) {
 
412
                                close(1);
 
413
                                copyfd(pip[1], 1);
 
414
                                close(pip[1]);
 
415
                        }
 
416
                        (void) execl("/bin/pwd", "pwd", (char *)0);
 
417
                        sh_warn("Cannot exec /bin/pwd");
 
418
                        exit(1);
 
419
                }
 
420
                (void) close(pip[1]);
 
421
                pip[1] = -1;
 
422
                p = pwd;
 
423
                while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0
 
424
                     || (i == -1 && errno == EINTR)) {
 
425
                        if (i > 0)
 
426
                                p += i;
 
427
                }
 
428
                (void) close(pip[0]);
 
429
                pip[0] = -1;
 
430
                status = waitforjob(jp);
 
431
                if (status != 0)
 
432
                        error((char *)0);
 
433
                if (i < 0 || p == pwd || p[-1] != '\n') {
 
434
                        if (noerror) {
 
435
                                INTON;
 
436
                                return;
 
437
                        }
 
438
                        error("pwd command failed");
 
439
                }
 
440
                p[-1] = '\0';
 
441
                INTON;
 
442
                curdir = savestr(pwd);
 
443
                return;
 
444
        }
 
445
#endif
 
446
}