From owner-freebsd-bugs@FreeBSD.ORG Wed Mar 31 04:50:02 2004 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 93A3316A4CE for ; Wed, 31 Mar 2004 04:50:02 -0800 (PST) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8454E43D55 for ; Wed, 31 Mar 2004 04:50:02 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) i2VCo2bv075742 for ; Wed, 31 Mar 2004 04:50:02 -0800 (PST) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.10/8.12.10/Submit) id i2VCo2RM075741; Wed, 31 Mar 2004 04:50:02 -0800 (PST) (envelope-from gnats) Resent-Date: Wed, 31 Mar 2004 04:50:02 -0800 (PST) Resent-Message-Id: <200403311250.i2VCo2RM075741@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, "mitrohin a.s." Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C083E16A4CE for ; Wed, 31 Mar 2004 04:46:37 -0800 (PST) Received: from swp.bspu.secna.ru (swp.bspu.secna.ru [212.192.2.73]) by mx1.FreeBSD.org (Postfix) with ESMTP id B0E5A43D39 for ; Wed, 31 Mar 2004 04:46:23 -0800 (PST) (envelope-from swp@swp.bspu.secna.ru) Received: from swp.bspu.secna.ru (localhost [127.0.0.1]) by swp.bspu.secna.ru (8.12.11/8.12.11) with ESMTP id i2VCkCop037170 for ; Wed, 31 Mar 2004 19:46:12 +0700 (OMSST) (envelope-from swp@swp.bspu.secna.ru) Received: (from root@localhost) by swp.bspu.secna.ru (8.12.11/8.12.11/Submit) id i2VCkC0i037169; Wed, 31 Mar 2004 19:46:12 +0700 (OMSST) (envelope-from swp) Message-Id: <200403311246.i2VCkC0i037169@swp.bspu.secna.ru> Date: Wed, 31 Mar 2004 19:46:12 +0700 (OMSST) From: swp@uni-altai.ru To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: bin/64990: /bin/sh unable to change directory but current dir grow anyway X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: "mitrohin a.s." List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 31 Mar 2004 12:50:02 -0000 >Number: 64990 >Category: bin >Synopsis: /bin/sh unable to change directory but current dir grow anyway >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Mar 31 04:50:00 PST 2004 >Closed-Date: >Last-Modified: >Originator: mitrohin a.s. >Release: FreeBSD 5.2-CURRENT i386 >Organization: Barnaul State Pedagogical University >Environment: System: FreeBSD swp.bspu.secna.ru 5.2-CURRENT FreeBSD 5.2-CURRENT #1: Fri Mar 26 17:56:09 OMST 2004 swp@swp.bspu.secna.ru:/usr/obj/usr/src/sys/ag_kernel i386 >Description: builtin cd unable to change work directory but curdir grow anyway. >How-To-Repeat: # mkdir -p /tmp/1/2 # chmod 770 /tmp/1/2 # cd /tmp/1 # touch 1.txt # pwd /tmp/1 # ls -l total 1 drwxrwx--- 2 root wheel 512 22 อมา 11:22 2 -rw-r--r-- 1 root wheel 0 22 อมา 11:22 1.txt # su -m cyrus $ pwd /tmp/1 $ cd 2 cd: can't cd to 2 $ pwd /tmp/1/2 $ ls -l total 1 drwxrwx--- 2 root wheel 512 22 อมา 11:22 2 -rw-r--r-- 1 root wheel 0 22 อมา 11:22 1.txt $ cd 2 cd: can't cd to 2 $ pwd /tmp/1/2/2 $ ls -l total 1 drwxrwx--- 2 root wheel 512 22 อมา 11:22 2 -rw-r--r-- 1 root wheel 0 22 อมา 11:22 1.txt $ cd 2 cd: can't cd to 2 $ pwd /tmp/1/2/2/2 $ ls -l total 1 drwxrwx--- 2 root wheel 512 22 อมา 11:22 2 -rw-r--r-- 1 root wheel 0 22 อมา 11:22 1.txt $ cd . $ pwd /tmp/1 $ ^D >Fix: Index: bin/sh/cd.c =================================================================== RCS file: /usr/cvs/freebsd/ncvs/src/bin/sh/cd.c,v retrieving revision 1.33 diff -u -r1.33 cd.c --- bin/sh/cd.c 5 Jul 2003 15:18:44 -0000 1.33 +++ bin/sh/cd.c 31 Mar 2004 12:35:06 -0000 @@ -42,13 +42,18 @@ #include __FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.33 2003/07/05 15:18:44 dds Exp $"); +#include +#include +#include #include #include +#include #include #include #include #include #include +#include /* * The cd and pwd commands. @@ -68,15 +73,305 @@ #include "show.h" #include "cd.h" -STATIC int cdlogical(char *); -STATIC int cdphysical(char *); -STATIC int docd(char *, int, int); -STATIC char *getcomponent(void); -STATIC int updatepwd(char *); - -STATIC char *curdir = NULL; /* current working directory */ -STATIC char *prevdir; /* previous working directory */ -STATIC char *cdcomppath; +/* + * Get the next component of the path name pointed to by path. + * This routine overwrites the string pointed to by path. + */ +static inline +char * +getcomponent(char **path) +{ + char *p; + + while ((p = strsep(path, "/")) != 0 && !*p) + continue; + return p; +} + + +struct mblkcore { + int clnk; + int realsz; + int n; + char d[1]; +}; +typedef struct mblkcore *mblk_t; + +#define BLKSZ 0x1000 +#define MBLK_GETMEMSIZE(n) \ + ((n)?(((n)-1)/BLKSZ+1)*BLKSZ + offsetof(struct mblkcore, d) : 0) + +static inline int mblk_init(mblk_t *); +static inline int mblk_uninit(mblk_t *); +static inline int mblk_clear(mblk_t *); +static inline int mblk_attach(mblk_t *, mblk_t *); +static inline int mblk_getn(mblk_t *); +static inline char *mblk_getp(mblk_t *); +static inline int mblk_realloc(mblk_t *, int); +static inline int mblk_write(mblk_t *, int, void *, int); + +#define mblk_resize mblk_realloc + +static inline +int +mblk_init(mblk_t *b) +{ + *b = 0; + return 0; +} + +static inline +int +mblk_uninit(mblk_t *b) +{ + return mblk_clear(b); +} + +static inline +int +mblk_clear(mblk_t *b) +{ + if (*b) { + if (!--(*b)->clnk) + free(*b); + *b = 0; + } + return 0; +} + +static inline +int +mblk_attach(mblk_t *a, mblk_t *b) +{ + mblk_uninit(a); + if (*b) { + (*b)->clnk++; + *a = *b; + } + return 0; +} + +static inline +int +mblk_getn(mblk_t *b) +{ + return (*b) ? (*b)->n : 0; +} +static inline +char * +mblk_getp(mblk_t *b) +{ + return (*b) ? (*b)->d : 0; +} + +static +int +mblk_realloc(mblk_t *b, int n) +{ + int clnk, realsz, new_realsz; + struct mblkcore *q; + + if (n == -1) + n = mblk_getn(b); + + if (!n) + return mblk_clear(b); + + if (!*b) { + clnk = 1; + realsz = 0; + } else { + clnk = (*b)->clnk; + realsz = (*b)->realsz; + assert(realsz > 0); + } + + new_realsz = MBLK_GETMEMSIZE(n); + if (clnk > 1) { + if (!(q = malloc(new_realsz))) + return -1; + memcpy(q->d, (*b)->d, (*b)->n < n ? (*b)->n : n); + (*b)->clnk--; + *b = q; + } else if (new_realsz != realsz) { + if (!(q = realloc(*b, new_realsz))) + return -1; + *b = q; + } + (*b)->clnk = 1; + (*b)->realsz = new_realsz; + (*b)->n = n; + + return 0; +} + +static inline +int +mblk_write(mblk_t *b, int off, void *buf, int bufn) +{ + int clnk, realsz, bn, n; + + if (!buf || !bufn) + return 0; + + if (!*b) { + clnk = 1; + realsz = 0; + bn = 0; + } else { + clnk = (*b)->clnk; + realsz = (*b)->realsz; + bn = (*b)->n; + } + + if (off <= realsz) { + if (off == -1) + off = bn; + n = off + bufn; + if (n < bn) + n = bn; + if (mblk_realloc(b, n)) + return -1; + memcpy((*b)->d + off, buf, bufn); + } + return 0; +} + + + +static +void +mblk_dump(mblk_t *b) +{ + int i; + + printf("blk = %p", *b); + if (*b) { + printf("clnk: %d, realsz: %d, n: %d,\n d: ", + (*b)->clnk, (*b)->realsz, (*b)->n); + for (i = 0; i < (*b)->n; i++) + printf("%d:%c ", i, (*b)->d[i]); + } + printf("\n"); +} + + +static +int +mblk_mkcdpath(mblk_t *b, char *dir, int phys) +{ + int rc, off, n; + char *p, *d, cdir[MAXPATHLEN]; + mblk_t a[1]; + + if (phys) { + if (dir && *dir) + if (chdir(dir)) + return -1; + if (!getcwd(cdir, sizeof cdir)) + return -1; + n = strlen(cdir) + 1; + if (mblk_write(b, 0, cdir, n) || mblk_resize(b, n)) + return -1; + return 0; + } + + if (!*b) { + if (!getcwd(cdir, sizeof cdir)) { + cdir[0] = '/'; cdir[1] = 0; + chdir(cdir); + } + n = strlen(cdir) + 1; + if (mblk_write(b, 0, cdir, n) || mblk_resize(b, n)) + return -1; + } + + if (!dir || !*dir) + return 0; + + assert(*b); + assert((*b)->n == 2 || ((*b)->n > 2 && (*b)->d[(*b)->n - 2] != '/')); + assert(*(*b)->d == '/'); + assert(!(*b)->d[(*b)->n - 1]); + + if (*dir && *dir == '/') { + if (mblk_write(b, 0, "/", 2) || mblk_resize(b, 2)) + return -1; + dir++; + } + + mblk_init(a); + mblk_attach(a, b); + + rc = 0; + while ((p = getcomponent(&dir)) != 0) { + if (*p == '.') { + if (!p[1]) + continue; + if (p[1] == '.' && !p[2]) { + for (p = (*b)->d + (*b)->n - 1;;) + if (p-1 == (*b)->d || *--p == '/') + break; + if ((rc = mblk_resize(b, p-(*b)->d+1)) != 0) + break; + if ((rc = mblk_write(b,(*b)->n-1,"",1)) != 0) + break; + continue; + } + } + + off = 1; + if ((*b)->n != 2) { + off = (*b)->n; + if ((rc = mblk_write(b, off-1, "/", 1)) != 0) + break; + } + if ((rc = mblk_write(b, off, p, strlen(p)+1)) != 0) + break; + } + + if (rc) + mblk_attach(b, a); + mblk_uninit(a); + + return rc; +} + +/* + * Actually change the directory. In an interactive shell, print the + * directory name if "print" is nonzero. + */ +static +int +docd(mblk_t *curdir, mblk_t *prevdir, char *dest, int print, int phys) +{ + int rc; + mblk_t old_curdir[1]; + + TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys)); + + rc = -1; + mblk_init(old_curdir); + mblk_attach(old_curdir, curdir); + if (!mblk_mkcdpath(curdir, dest, phys)) { + INTOFF; + if (chdir((*curdir)->d) < 0) + mblk_attach(curdir, old_curdir); + else { + mblk_attach(prevdir, old_curdir); + if (print && iflag) + out1fmt("%s\n", (*curdir)->d); + rc = 0; + } + INTON; + } + mblk_uninit(old_curdir); + + return rc; +} + +static mblk_t cdir[1] = { 0 }; +static mblk_t pdir[1] = { 0 }; int cdcmd(int argc, char **argv) @@ -113,7 +408,7 @@ if (*dest == '\0') dest = "."; if (dest[0] == '-' && dest[1] == '\0') { - dest = prevdir ? prevdir : curdir; + dest = *pdir ? (*pdir)->d : (*cdir)->d; if (dest) print = 1; else @@ -131,7 +426,7 @@ p += 2; print = strcmp(p, dest); } - if (docd(p, print, phys) >= 0) + if (!docd(cdir, pdir, p, print, phys)) return 0; } } @@ -141,189 +436,13 @@ } -/* - * Actually change the directory. In an interactive shell, print the - * directory name if "print" is nonzero. - */ -STATIC int -docd(char *dest, int print, int phys) -{ - - TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys)); - - /* If logical cd fails, fall back to physical. */ - if ((phys || cdlogical(dest) < 0) && cdphysical(dest) < 0) - return (-1); - - if (print && iflag && curdir) - out1fmt("%s\n", curdir); - - return 0; -} - -STATIC int -cdlogical(char *dest) -{ - char *p; - char *q; - char *component; - struct stat statb; - int first; - int badstat; - - /* - * Check each component of the path. If we find a symlink or - * something we can't stat, clear curdir to force a getcwd() - * next time we get the value of the current directory. - */ - badstat = 0; - cdcomppath = stalloc(strlen(dest) + 1); - scopy(dest, cdcomppath); - STARTSTACKSTR(p); - if (*dest == '/') { - STPUTC('/', p); - cdcomppath++; - } - first = 1; - while ((q = getcomponent()) != NULL) { - if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) - continue; - if (! first) - STPUTC('/', p); - first = 0; - component = q; - while (*q) - STPUTC(*q++, p); - if (equal(component, "..")) - continue; - STACKSTRNUL(p); - if (lstat(stackblock(), &statb) < 0) { - badstat = 1; - break; - } - } - - INTOFF; - if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) { - INTON; - return (-1); - } - INTON; - return (0); -} - -STATIC int -cdphysical(char *dest) -{ - - INTOFF; - if (chdir(dest) < 0 || updatepwd(NULL) < 0) { - INTON; - return (-1); - } - INTON; - return (0); -} - -/* - * Get the next component of the path name pointed to by cdcomppath. - * This routine overwrites the string pointed to by cdcomppath. - */ -STATIC char * -getcomponent(void) -{ - char *p; - char *start; - - if ((p = cdcomppath) == NULL) - return NULL; - start = cdcomppath; - while (*p != '/' && *p != '\0') - p++; - if (*p == '\0') { - cdcomppath = NULL; - } else { - *p++ = '\0'; - cdcomppath = p; - } - return start; -} - - -/* - * Update curdir (the name of the current directory) in response to a - * cd command. We also call hashcd to let the routines in exec.c know - * that the current directory has changed. - */ -STATIC int -updatepwd(char *dir) -{ - char *new; - char *p; - - hashcd(); /* update command hash table */ - - /* - * If our argument is NULL, we don't know the current directory - * any more because we traversed a symbolic link or something - * we couldn't stat(). - */ - if (dir == NULL || curdir == NULL) { - if (prevdir) - ckfree(prevdir); - INTOFF; - prevdir = curdir; - curdir = NULL; - if (getpwd() == NULL) { - INTON; - return (-1); - } - setvar("PWD", curdir, VEXPORT); - setvar("OLDPWD", prevdir, VEXPORT); - INTON; - return (0); - } - cdcomppath = stalloc(strlen(dir) + 1); - scopy(dir, cdcomppath); - STARTSTACKSTR(new); - if (*dir != '/') { - p = curdir; - while (*p) - STPUTC(*p++, new); - if (p[-1] == '/') - STUNPUTC(new); - } - while ((p = getcomponent()) != NULL) { - if (equal(p, "..")) { - while (new > stackblock() && (STUNPUTC(new), *new) != '/'); - } else if (*p != '\0' && ! equal(p, ".")) { - STPUTC('/', new); - while (*p) - STPUTC(*p++, new); - } - } - if (new == stackblock()) - STPUTC('/', new); - STACKSTRNUL(new); - INTOFF; - if (prevdir) - ckfree(prevdir); - prevdir = curdir; - curdir = savestr(stackblock()); - setvar("PWD", curdir, VEXPORT); - setvar("OLDPWD", prevdir, VEXPORT); - INTON; - - return (0); -} - int pwdcmd(int argc, char **argv) { char buf[PATH_MAX]; int ch, phys; - optreset = 1; optind = 1; opterr = 0; /* initialize getopt */ + optreset = optind = 1; opterr = 0; /* initialize getopt */ phys = Pflag; while ((ch = getopt(argc, argv, "LP")) != -1) { switch (ch) { @@ -344,15 +463,12 @@ if (argc != 0) error("too many arguments"); - if (!phys && getpwd()) { - out1str(curdir); - out1c('\n'); - } else { - if (getcwd(buf, sizeof(buf)) == NULL) - error(".: %s", strerror(errno)); - out1str(buf); - out1c('\n'); - } + if (phys) + if (mblk_mkcdpath(cdir, 0, phys)) + return -1; + + out1str((*cdir)->d); + out1c('\n'); return 0; } @@ -364,24 +480,8 @@ char * getpwd(void) { - char buf[PATH_MAX]; - - if (curdir) - return curdir; - if (getcwd(buf, sizeof(buf)) == NULL) { - char *pwd = getenv("PWD"); - struct stat stdot, stpwd; - - if (pwd && *pwd == '/' && stat(".", &stdot) != -1 && - stat(pwd, &stpwd) != -1 && - stdot.st_dev == stpwd.st_dev && - stdot.st_ino == stpwd.st_ino) { - curdir = savestr(pwd); - return curdir; - } - return NULL; - } - curdir = savestr(buf); - - return curdir; + if (!*cdir) + if (mblk_mkcdpath(cdir, 0, 1)) + return 0; + return (*cdir)->d; } >Release-Note: >Audit-Trail: >Unformatted: