1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate /* 10*7c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 11*7c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley Software License Agreement 12*7c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 13*7c478bd9Sstevel@tonic-gate */ 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #include "sh.h" 18*7c478bd9Sstevel@tonic-gate #include "sh.dir.h" 19*7c478bd9Sstevel@tonic-gate #include "sh.tconst.h" 20*7c478bd9Sstevel@tonic-gate 21*7c478bd9Sstevel@tonic-gate /* 22*7c478bd9Sstevel@tonic-gate * C Shell - directory management 23*7c478bd9Sstevel@tonic-gate */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate struct directory *dfind(); 26*7c478bd9Sstevel@tonic-gate tchar *dfollow(); 27*7c478bd9Sstevel@tonic-gate tchar *dcanon(); 28*7c478bd9Sstevel@tonic-gate struct directory dhead; /* "head" of loop */ 29*7c478bd9Sstevel@tonic-gate int printd; /* force name to be printed */ 30*7c478bd9Sstevel@tonic-gate static tchar *fakev[] = { S_dirs, NOSTR }; 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate /* 33*7c478bd9Sstevel@tonic-gate * dinit - initialize current working directory 34*7c478bd9Sstevel@tonic-gate */ 35*7c478bd9Sstevel@tonic-gate dinit(hp) 36*7c478bd9Sstevel@tonic-gate tchar *hp; 37*7c478bd9Sstevel@tonic-gate { 38*7c478bd9Sstevel@tonic-gate register tchar *cp; 39*7c478bd9Sstevel@tonic-gate register struct directory *dp; 40*7c478bd9Sstevel@tonic-gate tchar path[MAXPATHLEN]; 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #ifdef TRACE 43*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dinit()\n"); 44*7c478bd9Sstevel@tonic-gate #endif 45*7c478bd9Sstevel@tonic-gate /* 46*7c478bd9Sstevel@tonic-gate * If this is a login shell, we should have a home directory. But, 47*7c478bd9Sstevel@tonic-gate * if we got here via 'su - <user>' where the user has no directory 48*7c478bd9Sstevel@tonic-gate * in his passwd file, then su has passed HOME=<nothing>, so hp is 49*7c478bd9Sstevel@tonic-gate * non-null, but has zero length. Thus, we do not know the current 50*7c478bd9Sstevel@tonic-gate * working directory based on the home directory. 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate if (loginsh && hp && *hp) 53*7c478bd9Sstevel@tonic-gate cp = hp; 54*7c478bd9Sstevel@tonic-gate else { 55*7c478bd9Sstevel@tonic-gate cp = getwd_(path); 56*7c478bd9Sstevel@tonic-gate if (cp == NULL) { 57*7c478bd9Sstevel@tonic-gate printf ("Warning: cannot determine current directory\n"); 58*7c478bd9Sstevel@tonic-gate cp = S_DOT; 59*7c478bd9Sstevel@tonic-gate } 60*7c478bd9Sstevel@tonic-gate } 61*7c478bd9Sstevel@tonic-gate dp = (struct directory *)calloc(sizeof (struct directory), 1); 62*7c478bd9Sstevel@tonic-gate dp->di_name = savestr(cp); 63*7c478bd9Sstevel@tonic-gate dp->di_count = 0; 64*7c478bd9Sstevel@tonic-gate dhead.di_next = dhead.di_prev = dp; 65*7c478bd9Sstevel@tonic-gate dp->di_next = dp->di_prev = &dhead; 66*7c478bd9Sstevel@tonic-gate printd = 0; 67*7c478bd9Sstevel@tonic-gate dnewcwd(dp); 68*7c478bd9Sstevel@tonic-gate } 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* 71*7c478bd9Sstevel@tonic-gate * dodirs - list all directories in directory loop 72*7c478bd9Sstevel@tonic-gate */ 73*7c478bd9Sstevel@tonic-gate dodirs(v) 74*7c478bd9Sstevel@tonic-gate tchar **v; 75*7c478bd9Sstevel@tonic-gate { 76*7c478bd9Sstevel@tonic-gate register struct directory *dp; 77*7c478bd9Sstevel@tonic-gate bool lflag; 78*7c478bd9Sstevel@tonic-gate tchar *hp = value(S_home); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate #ifdef TRACE 81*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dodirs()\n"); 82*7c478bd9Sstevel@tonic-gate #endif 83*7c478bd9Sstevel@tonic-gate if (*hp == '\0') 84*7c478bd9Sstevel@tonic-gate hp = NOSTR; 85*7c478bd9Sstevel@tonic-gate if (*++v != NOSTR) 86*7c478bd9Sstevel@tonic-gate if (eq(*v, S_MINl /* "-l" */) && *++v == NOSTR) 87*7c478bd9Sstevel@tonic-gate lflag = 1; 88*7c478bd9Sstevel@tonic-gate else 89*7c478bd9Sstevel@tonic-gate error("Usage: dirs [ -l ]"); 90*7c478bd9Sstevel@tonic-gate else 91*7c478bd9Sstevel@tonic-gate lflag = 0; 92*7c478bd9Sstevel@tonic-gate dp = dcwd; 93*7c478bd9Sstevel@tonic-gate do { 94*7c478bd9Sstevel@tonic-gate if (dp == &dhead) 95*7c478bd9Sstevel@tonic-gate continue; 96*7c478bd9Sstevel@tonic-gate if (!lflag && hp != NOSTR) { 97*7c478bd9Sstevel@tonic-gate dtildepr(hp, dp->di_name); 98*7c478bd9Sstevel@tonic-gate } else 99*7c478bd9Sstevel@tonic-gate printf("%t", dp->di_name); 100*7c478bd9Sstevel@tonic-gate printf(" "); 101*7c478bd9Sstevel@tonic-gate } while ((dp = dp->di_prev) != dcwd); 102*7c478bd9Sstevel@tonic-gate printf("\n"); 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate dtildepr(home, dir) 106*7c478bd9Sstevel@tonic-gate register tchar *home, *dir; 107*7c478bd9Sstevel@tonic-gate { 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate #ifdef TRACE 110*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dtildepr()\n"); 111*7c478bd9Sstevel@tonic-gate #endif 112*7c478bd9Sstevel@tonic-gate if (!eq(home, S_SLASH /* "/" */) && prefix(home, dir)) 113*7c478bd9Sstevel@tonic-gate printf("~%t", dir + strlen_(home)); 114*7c478bd9Sstevel@tonic-gate else 115*7c478bd9Sstevel@tonic-gate printf("%t", dir); 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* 119*7c478bd9Sstevel@tonic-gate * dochngd - implement chdir command. 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate dochngd(v) 122*7c478bd9Sstevel@tonic-gate tchar **v; 123*7c478bd9Sstevel@tonic-gate { 124*7c478bd9Sstevel@tonic-gate register tchar *cp; 125*7c478bd9Sstevel@tonic-gate register struct directory *dp; 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate #ifdef TRACE 128*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dochngd()\n"); 129*7c478bd9Sstevel@tonic-gate #endif 130*7c478bd9Sstevel@tonic-gate printd = 0; 131*7c478bd9Sstevel@tonic-gate if (*++v == NOSTR) { 132*7c478bd9Sstevel@tonic-gate if ((cp = value(S_home)) == NOSTR || *cp == 0) 133*7c478bd9Sstevel@tonic-gate bferr("No home directory"); 134*7c478bd9Sstevel@tonic-gate if (chdir_(cp) < 0) 135*7c478bd9Sstevel@tonic-gate bferr("Can't change to home directory"); 136*7c478bd9Sstevel@tonic-gate cp = savestr(cp); 137*7c478bd9Sstevel@tonic-gate } else if ((dp = dfind(*v)) != 0) { 138*7c478bd9Sstevel@tonic-gate printd = 1; 139*7c478bd9Sstevel@tonic-gate if (chdir_(dp->di_name) < 0) 140*7c478bd9Sstevel@tonic-gate Perror(dp->di_name); 141*7c478bd9Sstevel@tonic-gate dcwd->di_prev->di_next = dcwd->di_next; 142*7c478bd9Sstevel@tonic-gate dcwd->di_next->di_prev = dcwd->di_prev; 143*7c478bd9Sstevel@tonic-gate goto flushcwd; 144*7c478bd9Sstevel@tonic-gate } else 145*7c478bd9Sstevel@tonic-gate cp = dfollow(*v); 146*7c478bd9Sstevel@tonic-gate dp = (struct directory *)calloc(sizeof (struct directory), 1); 147*7c478bd9Sstevel@tonic-gate dp->di_name = cp; 148*7c478bd9Sstevel@tonic-gate dp->di_count = 0; 149*7c478bd9Sstevel@tonic-gate dp->di_next = dcwd->di_next; 150*7c478bd9Sstevel@tonic-gate dp->di_prev = dcwd->di_prev; 151*7c478bd9Sstevel@tonic-gate dp->di_prev->di_next = dp; 152*7c478bd9Sstevel@tonic-gate dp->di_next->di_prev = dp; 153*7c478bd9Sstevel@tonic-gate flushcwd: 154*7c478bd9Sstevel@tonic-gate dfree(dcwd); 155*7c478bd9Sstevel@tonic-gate dnewcwd(dp); 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* 159*7c478bd9Sstevel@tonic-gate * dfollow - change to arg directory; fall back on cdpath if not valid 160*7c478bd9Sstevel@tonic-gate */ 161*7c478bd9Sstevel@tonic-gate tchar * 162*7c478bd9Sstevel@tonic-gate dfollow(cp) 163*7c478bd9Sstevel@tonic-gate register tchar *cp; 164*7c478bd9Sstevel@tonic-gate { 165*7c478bd9Sstevel@tonic-gate register tchar *dp; 166*7c478bd9Sstevel@tonic-gate struct varent *c; 167*7c478bd9Sstevel@tonic-gate int cdhashval, cdhashval1; 168*7c478bd9Sstevel@tonic-gate int index; 169*7c478bd9Sstevel@tonic-gate int slash; /*slashes in the argument*/ 170*7c478bd9Sstevel@tonic-gate tchar *fullpath; 171*7c478bd9Sstevel@tonic-gate tchar *slashcp; /*cp string prepended with a slash*/ 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate #ifdef TRACE 174*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dfollow()\n"); 175*7c478bd9Sstevel@tonic-gate #endif 176*7c478bd9Sstevel@tonic-gate cp = globone(cp); 177*7c478bd9Sstevel@tonic-gate if (chdir_(cp) >= 0) 178*7c478bd9Sstevel@tonic-gate goto gotcha; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* 181*7c478bd9Sstevel@tonic-gate * If the directory argument has a slash in it, 182*7c478bd9Sstevel@tonic-gate * for example, directory/directory, then can't 183*7c478bd9Sstevel@tonic-gate * find that in the cache table. 184*7c478bd9Sstevel@tonic-gate */ 185*7c478bd9Sstevel@tonic-gate slash = any('/', cp); 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * Try interpreting wrt successive components of cdpath. 189*7c478bd9Sstevel@tonic-gate * cdpath caching is turned off or directory argument 190*7c478bd9Sstevel@tonic-gate * has a slash in it. 191*7c478bd9Sstevel@tonic-gate */ 192*7c478bd9Sstevel@tonic-gate if (cp[0] != '/' 193*7c478bd9Sstevel@tonic-gate && !prefix(S_DOTSLA /* "./" */, cp) 194*7c478bd9Sstevel@tonic-gate && !prefix(S_DOTDOTSLA /* "../" */, cp) 195*7c478bd9Sstevel@tonic-gate && (c = adrof(S_cdpath)) 196*7c478bd9Sstevel@tonic-gate && ( !havhash2 || slash) ) { 197*7c478bd9Sstevel@tonic-gate tchar **cdp; 198*7c478bd9Sstevel@tonic-gate register tchar *p; 199*7c478bd9Sstevel@tonic-gate tchar buf[MAXPATHLEN]; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate for (cdp = c->vec; *cdp; cdp++) { 202*7c478bd9Sstevel@tonic-gate for (dp = buf, p = *cdp; *dp++ = *p++;) 203*7c478bd9Sstevel@tonic-gate ; 204*7c478bd9Sstevel@tonic-gate dp[-1] = '/'; 205*7c478bd9Sstevel@tonic-gate for (p = cp; *dp++ = *p++;) 206*7c478bd9Sstevel@tonic-gate ; 207*7c478bd9Sstevel@tonic-gate if (chdir_(buf) >= 0) { 208*7c478bd9Sstevel@tonic-gate printd = 1; 209*7c478bd9Sstevel@tonic-gate xfree(cp); 210*7c478bd9Sstevel@tonic-gate cp = savestr(buf); 211*7c478bd9Sstevel@tonic-gate goto gotcha; 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* cdpath caching turned on */ 217*7c478bd9Sstevel@tonic-gate if (cp[0] != '/' 218*7c478bd9Sstevel@tonic-gate && !prefix(S_DOTSLA /* "./" */, cp) 219*7c478bd9Sstevel@tonic-gate && !prefix(S_DOTDOTSLA /* "../" */, cp) 220*7c478bd9Sstevel@tonic-gate && (c = adrof(S_cdpath)) 221*7c478bd9Sstevel@tonic-gate && havhash2 && !slash ) { 222*7c478bd9Sstevel@tonic-gate tchar **pv; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate /* If no cdpath or no paths in cdpath, leave */ 225*7c478bd9Sstevel@tonic-gate if ( c == 0 || c->vec[0]== 0 ) 226*7c478bd9Sstevel@tonic-gate pv = justabs; 227*7c478bd9Sstevel@tonic-gate else 228*7c478bd9Sstevel@tonic-gate pv = c->vec; 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate slashcp = strspl(S_SLASH, cp); 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate cdhashval = hashname(cp); 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /*index points to next path component to test*/ 235*7c478bd9Sstevel@tonic-gate index=0; 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * Look at each path in cdpath until get a match. 239*7c478bd9Sstevel@tonic-gate * Only look at those path beginning with a slash 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate do { 242*7c478bd9Sstevel@tonic-gate /* only check cache for absolute pathnames */ 243*7c478bd9Sstevel@tonic-gate if ( pv[0][0] == '/' ) { 244*7c478bd9Sstevel@tonic-gate cdhashval1 = hash(cdhashval, index); 245*7c478bd9Sstevel@tonic-gate if (bit(xhash2, cdhashval1)) { 246*7c478bd9Sstevel@tonic-gate /* 247*7c478bd9Sstevel@tonic-gate * concatenate found path with 248*7c478bd9Sstevel@tonic-gate * arg directory 249*7c478bd9Sstevel@tonic-gate */ 250*7c478bd9Sstevel@tonic-gate fullpath = strspl(*pv, slashcp); 251*7c478bd9Sstevel@tonic-gate if (chdir_(fullpath) >= 0) { 252*7c478bd9Sstevel@tonic-gate printd = 1; 253*7c478bd9Sstevel@tonic-gate xfree(cp); 254*7c478bd9Sstevel@tonic-gate cp = savestr(fullpath); 255*7c478bd9Sstevel@tonic-gate xfree(slashcp); 256*7c478bd9Sstevel@tonic-gate xfree(fullpath); 257*7c478bd9Sstevel@tonic-gate goto gotcha; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate /* 262*7c478bd9Sstevel@tonic-gate * relative pathnames are not cached, and must be 263*7c478bd9Sstevel@tonic-gate * checked manually 264*7c478bd9Sstevel@tonic-gate */ 265*7c478bd9Sstevel@tonic-gate else { 266*7c478bd9Sstevel@tonic-gate register tchar *p; 267*7c478bd9Sstevel@tonic-gate tchar buf[MAXPATHLEN]; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate for (dp = buf, p = *pv; *dp++ = *p++; ) 270*7c478bd9Sstevel@tonic-gate ; 271*7c478bd9Sstevel@tonic-gate dp[-1] = '/'; 272*7c478bd9Sstevel@tonic-gate for (p = cp; *dp++ = *p++; ) 273*7c478bd9Sstevel@tonic-gate ; 274*7c478bd9Sstevel@tonic-gate if (chdir_(buf) >= 0) { 275*7c478bd9Sstevel@tonic-gate printd = 1; 276*7c478bd9Sstevel@tonic-gate xfree(cp); 277*7c478bd9Sstevel@tonic-gate cp = savestr(buf); 278*7c478bd9Sstevel@tonic-gate xfree(slashcp); 279*7c478bd9Sstevel@tonic-gate goto gotcha; 280*7c478bd9Sstevel@tonic-gate } 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate pv++; 283*7c478bd9Sstevel@tonic-gate index++; 284*7c478bd9Sstevel@tonic-gate } while (*pv); 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate /* 288*7c478bd9Sstevel@tonic-gate * Try dereferencing the variable named by the argument. 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate dp = value(cp); 291*7c478bd9Sstevel@tonic-gate if ((dp[0] == '/' || dp[0] == '.') && chdir_(dp) >= 0) { 292*7c478bd9Sstevel@tonic-gate xfree(cp); 293*7c478bd9Sstevel@tonic-gate cp = savestr(dp); 294*7c478bd9Sstevel@tonic-gate printd = 1; 295*7c478bd9Sstevel@tonic-gate goto gotcha; 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate xfree(cp); /* XXX, use after free */ 298*7c478bd9Sstevel@tonic-gate Perror(cp); 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate gotcha: 301*7c478bd9Sstevel@tonic-gate if (*cp != '/') { 302*7c478bd9Sstevel@tonic-gate register tchar *p, *q; 303*7c478bd9Sstevel@tonic-gate int cwdlen; 304*7c478bd9Sstevel@tonic-gate int len; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * All in the name of efficiency? 308*7c478bd9Sstevel@tonic-gate */ 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate if ( ( cwdlen = (strlen_(dcwd->di_name) ) ) == 1 ){ 311*7c478bd9Sstevel@tonic-gate if ( *dcwd->di_name == '/' ) /* root */ 312*7c478bd9Sstevel@tonic-gate cwdlen = 0; 313*7c478bd9Sstevel@tonic-gate else 314*7c478bd9Sstevel@tonic-gate { 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * if we are here, when the shell started 317*7c478bd9Sstevel@tonic-gate * it was unable to getwd(), lets try it again 318*7c478bd9Sstevel@tonic-gate */ 319*7c478bd9Sstevel@tonic-gate tchar path[MAXPATHLEN]; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate p = getwd_(path); 322*7c478bd9Sstevel@tonic-gate if (p == NULL) 323*7c478bd9Sstevel@tonic-gate error("cannot determine current directory"); 324*7c478bd9Sstevel@tonic-gate else 325*7c478bd9Sstevel@tonic-gate { 326*7c478bd9Sstevel@tonic-gate xfree(dcwd->di_name); 327*7c478bd9Sstevel@tonic-gate dcwd->di_name = savestr(p); 328*7c478bd9Sstevel@tonic-gate xfree(cp); 329*7c478bd9Sstevel@tonic-gate cp = savestr(p); 330*7c478bd9Sstevel@tonic-gate return dcanon(cp, cp); 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate } 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * 337*7c478bd9Sstevel@tonic-gate * for (p = cp; *p++;) 338*7c478bd9Sstevel@tonic-gate * ; 339*7c478bd9Sstevel@tonic-gate * dp = (tchar *)xalloc((unsigned) (cwdlen + (p - cp) + 1)*sizeof (tchar)) 340*7c478bd9Sstevel@tonic-gate */ 341*7c478bd9Sstevel@tonic-gate len = strlen_(cp); 342*7c478bd9Sstevel@tonic-gate dp = (tchar *)xalloc((unsigned) (cwdlen + len + 2)*sizeof(tchar)); 343*7c478bd9Sstevel@tonic-gate for (p = dp, q = dcwd->di_name; *p++ = *q++;) 344*7c478bd9Sstevel@tonic-gate ; 345*7c478bd9Sstevel@tonic-gate if (cwdlen) 346*7c478bd9Sstevel@tonic-gate p[-1] = '/'; 347*7c478bd9Sstevel@tonic-gate else 348*7c478bd9Sstevel@tonic-gate p--; /* don't add a / after root */ 349*7c478bd9Sstevel@tonic-gate for (q = cp; *p++ = *q++;) 350*7c478bd9Sstevel@tonic-gate ; 351*7c478bd9Sstevel@tonic-gate xfree(cp); 352*7c478bd9Sstevel@tonic-gate cp = dp; 353*7c478bd9Sstevel@tonic-gate dp += cwdlen; 354*7c478bd9Sstevel@tonic-gate } else 355*7c478bd9Sstevel@tonic-gate dp = cp; 356*7c478bd9Sstevel@tonic-gate return dcanon(cp, dp); 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate /* 360*7c478bd9Sstevel@tonic-gate * dopushd - push new directory onto directory stack. 361*7c478bd9Sstevel@tonic-gate * with no arguments exchange top and second. 362*7c478bd9Sstevel@tonic-gate * with numeric argument (+n) bring it to top. 363*7c478bd9Sstevel@tonic-gate */ 364*7c478bd9Sstevel@tonic-gate dopushd(v) 365*7c478bd9Sstevel@tonic-gate tchar **v; 366*7c478bd9Sstevel@tonic-gate { 367*7c478bd9Sstevel@tonic-gate register struct directory *dp; 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate #ifdef TRACE 370*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dopushd()\n"); 371*7c478bd9Sstevel@tonic-gate #endif 372*7c478bd9Sstevel@tonic-gate printd = 1; 373*7c478bd9Sstevel@tonic-gate if (*++v == NOSTR) { 374*7c478bd9Sstevel@tonic-gate if ((dp = dcwd->di_prev) == &dhead) 375*7c478bd9Sstevel@tonic-gate dp = dhead.di_prev; 376*7c478bd9Sstevel@tonic-gate if (dp == dcwd) 377*7c478bd9Sstevel@tonic-gate bferr("No other directory"); 378*7c478bd9Sstevel@tonic-gate if (chdir_(dp->di_name) < 0) 379*7c478bd9Sstevel@tonic-gate Perror(dp->di_name); 380*7c478bd9Sstevel@tonic-gate dp->di_prev->di_next = dp->di_next; 381*7c478bd9Sstevel@tonic-gate dp->di_next->di_prev = dp->di_prev; 382*7c478bd9Sstevel@tonic-gate dp->di_next = dcwd->di_next; 383*7c478bd9Sstevel@tonic-gate dp->di_prev = dcwd; 384*7c478bd9Sstevel@tonic-gate dcwd->di_next->di_prev = dp; 385*7c478bd9Sstevel@tonic-gate dcwd->di_next = dp; 386*7c478bd9Sstevel@tonic-gate } else if (dp = dfind(*v)) { 387*7c478bd9Sstevel@tonic-gate if (chdir_(dp->di_name) < 0) 388*7c478bd9Sstevel@tonic-gate Perror(dp->di_name); 389*7c478bd9Sstevel@tonic-gate } else { 390*7c478bd9Sstevel@tonic-gate register tchar *cp; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate cp = dfollow(*v); 393*7c478bd9Sstevel@tonic-gate dp = (struct directory *)calloc(sizeof (struct directory), 1); 394*7c478bd9Sstevel@tonic-gate dp->di_name = cp; 395*7c478bd9Sstevel@tonic-gate dp->di_count = 0; 396*7c478bd9Sstevel@tonic-gate dp->di_prev = dcwd; 397*7c478bd9Sstevel@tonic-gate dp->di_next = dcwd->di_next; 398*7c478bd9Sstevel@tonic-gate dcwd->di_next = dp; 399*7c478bd9Sstevel@tonic-gate dp->di_next->di_prev = dp; 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate dnewcwd(dp); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate /* 405*7c478bd9Sstevel@tonic-gate * dfind - find a directory if specified by numeric (+n) argument 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate struct directory * 408*7c478bd9Sstevel@tonic-gate dfind(cp) 409*7c478bd9Sstevel@tonic-gate register tchar *cp; 410*7c478bd9Sstevel@tonic-gate { 411*7c478bd9Sstevel@tonic-gate register struct directory *dp; 412*7c478bd9Sstevel@tonic-gate register int i; 413*7c478bd9Sstevel@tonic-gate register tchar *ep; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate #ifdef TRACE 416*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dfind()\n"); 417*7c478bd9Sstevel@tonic-gate #endif 418*7c478bd9Sstevel@tonic-gate if (*cp++ != '+') 419*7c478bd9Sstevel@tonic-gate return (0); 420*7c478bd9Sstevel@tonic-gate for (ep = cp; digit(*ep); ep++) 421*7c478bd9Sstevel@tonic-gate continue; 422*7c478bd9Sstevel@tonic-gate if (*ep) 423*7c478bd9Sstevel@tonic-gate return (0); 424*7c478bd9Sstevel@tonic-gate i = getn(cp); 425*7c478bd9Sstevel@tonic-gate if (i <= 0) 426*7c478bd9Sstevel@tonic-gate return (0); 427*7c478bd9Sstevel@tonic-gate for (dp = dcwd; i != 0; i--) { 428*7c478bd9Sstevel@tonic-gate if ((dp = dp->di_prev) == &dhead) 429*7c478bd9Sstevel@tonic-gate dp = dp->di_prev; 430*7c478bd9Sstevel@tonic-gate if (dp == dcwd) 431*7c478bd9Sstevel@tonic-gate bferr("Directory stack not that deep"); 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate return (dp); 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate /* 437*7c478bd9Sstevel@tonic-gate * dopopd - pop a directory out of the directory stack 438*7c478bd9Sstevel@tonic-gate * with a numeric argument just discard it. 439*7c478bd9Sstevel@tonic-gate */ 440*7c478bd9Sstevel@tonic-gate dopopd(v) 441*7c478bd9Sstevel@tonic-gate tchar **v; 442*7c478bd9Sstevel@tonic-gate { 443*7c478bd9Sstevel@tonic-gate register struct directory *dp, *p; 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate #ifdef TRACE 446*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dopopd()\n"); 447*7c478bd9Sstevel@tonic-gate #endif 448*7c478bd9Sstevel@tonic-gate printd = 1; 449*7c478bd9Sstevel@tonic-gate if (*++v == NOSTR) 450*7c478bd9Sstevel@tonic-gate dp = dcwd; 451*7c478bd9Sstevel@tonic-gate else if ((dp = dfind(*v)) == 0) 452*7c478bd9Sstevel@tonic-gate bferr("Invalid argument"); 453*7c478bd9Sstevel@tonic-gate if (dp->di_prev == &dhead && dp->di_next == &dhead) 454*7c478bd9Sstevel@tonic-gate bferr("Directory stack empty"); 455*7c478bd9Sstevel@tonic-gate if (dp == dcwd) { 456*7c478bd9Sstevel@tonic-gate if ((p = dp->di_prev) == &dhead) 457*7c478bd9Sstevel@tonic-gate p = dhead.di_prev; 458*7c478bd9Sstevel@tonic-gate if (chdir_(p->di_name) < 0) 459*7c478bd9Sstevel@tonic-gate Perror(p->di_name); 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate dp->di_prev->di_next = dp->di_next; 462*7c478bd9Sstevel@tonic-gate dp->di_next->di_prev = dp->di_prev; 463*7c478bd9Sstevel@tonic-gate if (dp == dcwd) 464*7c478bd9Sstevel@tonic-gate dnewcwd(p); 465*7c478bd9Sstevel@tonic-gate else 466*7c478bd9Sstevel@tonic-gate dodirs(fakev); 467*7c478bd9Sstevel@tonic-gate dfree(dp); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * dfree - free the directory (or keep it if it still has ref count) 472*7c478bd9Sstevel@tonic-gate */ 473*7c478bd9Sstevel@tonic-gate dfree(dp) 474*7c478bd9Sstevel@tonic-gate register struct directory *dp; 475*7c478bd9Sstevel@tonic-gate { 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate #ifdef TRACE 478*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dfree()\n"); 479*7c478bd9Sstevel@tonic-gate #endif 480*7c478bd9Sstevel@tonic-gate if (dp->di_count != 0) 481*7c478bd9Sstevel@tonic-gate dp->di_next = dp->di_prev = 0; 482*7c478bd9Sstevel@tonic-gate else 483*7c478bd9Sstevel@tonic-gate xfree(dp->di_name), xfree( (tchar *)dp); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate /* 487*7c478bd9Sstevel@tonic-gate * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. 488*7c478bd9Sstevel@tonic-gate * We are of course assuming that the file system is standardly 489*7c478bd9Sstevel@tonic-gate * constructed (always have ..'s, directories have links). 490*7c478bd9Sstevel@tonic-gate * 491*7c478bd9Sstevel@tonic-gate * If the hardpaths shell variable is set, resolve the 492*7c478bd9Sstevel@tonic-gate * resulting pathname to contain no symbolic link components. 493*7c478bd9Sstevel@tonic-gate */ 494*7c478bd9Sstevel@tonic-gate tchar * 495*7c478bd9Sstevel@tonic-gate dcanon(cp, p) 496*7c478bd9Sstevel@tonic-gate register tchar *cp, *p; 497*7c478bd9Sstevel@tonic-gate { 498*7c478bd9Sstevel@tonic-gate register tchar *sp; /* rightmost component currently under 499*7c478bd9Sstevel@tonic-gate consideration */ 500*7c478bd9Sstevel@tonic-gate register tchar *p1, /* general purpose */ 501*7c478bd9Sstevel@tonic-gate *p2; 502*7c478bd9Sstevel@tonic-gate bool slash, dotdot, hardpaths; 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate #ifdef TRACE 505*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dcannon()\n"); 506*7c478bd9Sstevel@tonic-gate #endif 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate if (*cp != '/') 509*7c478bd9Sstevel@tonic-gate abort(); 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate if (hardpaths = (adrof(S_hardpaths) != NULL)) { 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * Be paranoid: don't trust the initial prefix 514*7c478bd9Sstevel@tonic-gate * to be symlink-free. 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate p = cp; 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate /* 520*7c478bd9Sstevel@tonic-gate * Loop invariant: cp points to the overall path start, 521*7c478bd9Sstevel@tonic-gate * p to its as yet uncanonicalized trailing suffix. 522*7c478bd9Sstevel@tonic-gate */ 523*7c478bd9Sstevel@tonic-gate while (*p) { /* for each component */ 524*7c478bd9Sstevel@tonic-gate sp = p; /* save slash address */ 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate while (*++p == '/') /* flush extra slashes */ 527*7c478bd9Sstevel@tonic-gate ; 528*7c478bd9Sstevel@tonic-gate if (p != ++sp) 529*7c478bd9Sstevel@tonic-gate for (p1 = sp, p2 = p; *p1++ = *p2++;) 530*7c478bd9Sstevel@tonic-gate ; 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate p = sp; /* save start of component */ 533*7c478bd9Sstevel@tonic-gate slash = 0; 534*7c478bd9Sstevel@tonic-gate if (*p) 535*7c478bd9Sstevel@tonic-gate while (*++p) /* find next slash or end of path */ 536*7c478bd9Sstevel@tonic-gate if (*p == '/') { 537*7c478bd9Sstevel@tonic-gate slash = 1; 538*7c478bd9Sstevel@tonic-gate *p = '\0'; 539*7c478bd9Sstevel@tonic-gate break; 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate if (*sp == '\0') { 543*7c478bd9Sstevel@tonic-gate /* component is null */ 544*7c478bd9Sstevel@tonic-gate if (--sp == cp) /* if path is one tchar (i.e. /) */ 545*7c478bd9Sstevel@tonic-gate break; 546*7c478bd9Sstevel@tonic-gate else 547*7c478bd9Sstevel@tonic-gate *sp = '\0'; 548*7c478bd9Sstevel@tonic-gate continue; 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate if (sp[0] == '.' && sp[1] == '\0') { 552*7c478bd9Sstevel@tonic-gate /* Squeeze out component consisting of "." */ 553*7c478bd9Sstevel@tonic-gate if (slash) { 554*7c478bd9Sstevel@tonic-gate for (p1 = sp, p2 = p + 1; *p1++ = *p2++;) 555*7c478bd9Sstevel@tonic-gate ; 556*7c478bd9Sstevel@tonic-gate p = --sp; 557*7c478bd9Sstevel@tonic-gate } else if (--sp != cp) 558*7c478bd9Sstevel@tonic-gate *sp = '\0'; 559*7c478bd9Sstevel@tonic-gate continue; 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate /* 563*7c478bd9Sstevel@tonic-gate * At this point we have a path of the form "x/yz", 564*7c478bd9Sstevel@tonic-gate * where "x" is null or rooted at "/", "y" is a single 565*7c478bd9Sstevel@tonic-gate * component, and "z" is possibly null. The pointer cp 566*7c478bd9Sstevel@tonic-gate * points to the start of "x", sp to the start of "y", 567*7c478bd9Sstevel@tonic-gate * and p to the beginning of "z", which has been forced 568*7c478bd9Sstevel@tonic-gate * to a null. 569*7c478bd9Sstevel@tonic-gate */ 570*7c478bd9Sstevel@tonic-gate /* 571*7c478bd9Sstevel@tonic-gate * Process symbolic link component. Provided that either 572*7c478bd9Sstevel@tonic-gate * the hardpaths shell variable is set or "y" is really 573*7c478bd9Sstevel@tonic-gate * ".." we replace the symlink with its contents. The 574*7c478bd9Sstevel@tonic-gate * second condition for replacement is necessary to make 575*7c478bd9Sstevel@tonic-gate * the command "cd x/.." produce the same results as the 576*7c478bd9Sstevel@tonic-gate * sequence "cd x; cd ..". 577*7c478bd9Sstevel@tonic-gate * 578*7c478bd9Sstevel@tonic-gate * Note that the two conditions correspond to different 579*7c478bd9Sstevel@tonic-gate * potential symlinks. When hardpaths is set, we must 580*7c478bd9Sstevel@tonic-gate * check "x/y"; otherwise, when "y" is known to be "..", 581*7c478bd9Sstevel@tonic-gate * we check "x". 582*7c478bd9Sstevel@tonic-gate */ 583*7c478bd9Sstevel@tonic-gate dotdot = sp[0] == '.' && sp[1] == '.' && sp[2] == '\0'; 584*7c478bd9Sstevel@tonic-gate if (hardpaths || dotdot) { 585*7c478bd9Sstevel@tonic-gate tchar link[MAXPATHLEN]; 586*7c478bd9Sstevel@tonic-gate int cc; 587*7c478bd9Sstevel@tonic-gate tchar *newcp; 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /* 590*7c478bd9Sstevel@tonic-gate * Isolate the end of the component that is to 591*7c478bd9Sstevel@tonic-gate * be checked for symlink-hood. 592*7c478bd9Sstevel@tonic-gate */ 593*7c478bd9Sstevel@tonic-gate sp--; 594*7c478bd9Sstevel@tonic-gate if (! hardpaths) 595*7c478bd9Sstevel@tonic-gate *sp = '\0'; 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /* 598*7c478bd9Sstevel@tonic-gate * See whether the component is really a symlink by 599*7c478bd9Sstevel@tonic-gate * trying to read it. If the read succeeds, it is. 600*7c478bd9Sstevel@tonic-gate */ 601*7c478bd9Sstevel@tonic-gate if ((hardpaths || sp > cp) && 602*7c478bd9Sstevel@tonic-gate (cc = readlink_(cp, link, MAXPATHLEN)) >= 0) { 603*7c478bd9Sstevel@tonic-gate /* 604*7c478bd9Sstevel@tonic-gate * readlink_ put null, so we don't need this. 605*7c478bd9Sstevel@tonic-gate */ 606*7c478bd9Sstevel@tonic-gate /* link[cc] = '\0'; */ 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate /* Restore path. */ 609*7c478bd9Sstevel@tonic-gate if (slash) 610*7c478bd9Sstevel@tonic-gate *p = '/'; 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* 613*7c478bd9Sstevel@tonic-gate * Point p at the start of the trailing 614*7c478bd9Sstevel@tonic-gate * path following the symlink component. 615*7c478bd9Sstevel@tonic-gate * It's already there is hardpaths is set. 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate if (! hardpaths) { 618*7c478bd9Sstevel@tonic-gate /* Restore path as well. */ 619*7c478bd9Sstevel@tonic-gate *(p = sp) = '/'; 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate /* 623*7c478bd9Sstevel@tonic-gate * Find length of p. 624*7c478bd9Sstevel@tonic-gate */ 625*7c478bd9Sstevel@tonic-gate for (p1 = p; *p1++;) 626*7c478bd9Sstevel@tonic-gate ; 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate if (*link != '/') { 629*7c478bd9Sstevel@tonic-gate /* 630*7c478bd9Sstevel@tonic-gate * Relative path: replace the symlink 631*7c478bd9Sstevel@tonic-gate * component with its value. First, 632*7c478bd9Sstevel@tonic-gate * set sp to point to the slash at 633*7c478bd9Sstevel@tonic-gate * its beginning. If hardpaths is 634*7c478bd9Sstevel@tonic-gate * set, this is already the case. 635*7c478bd9Sstevel@tonic-gate */ 636*7c478bd9Sstevel@tonic-gate if (! hardpaths) { 637*7c478bd9Sstevel@tonic-gate while (*--sp != '/') 638*7c478bd9Sstevel@tonic-gate ; 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* 642*7c478bd9Sstevel@tonic-gate * Terminate the leading part of the 643*7c478bd9Sstevel@tonic-gate * path, including trailing slash. 644*7c478bd9Sstevel@tonic-gate */ 645*7c478bd9Sstevel@tonic-gate sp++; 646*7c478bd9Sstevel@tonic-gate *sp = '\0'; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate * New length is: "x/" + link + "z" 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate p1 = newcp = (tchar *)xalloc((unsigned) 652*7c478bd9Sstevel@tonic-gate ((sp - cp) + cc + (p1 - p))*sizeof (tchar)); 653*7c478bd9Sstevel@tonic-gate /* 654*7c478bd9Sstevel@tonic-gate * Copy new path into newcp 655*7c478bd9Sstevel@tonic-gate */ 656*7c478bd9Sstevel@tonic-gate for (p2 = cp; *p1++ = *p2++;) 657*7c478bd9Sstevel@tonic-gate ; 658*7c478bd9Sstevel@tonic-gate for (p1--, p2 = link; *p1++ = *p2++;) 659*7c478bd9Sstevel@tonic-gate ; 660*7c478bd9Sstevel@tonic-gate for (p1--, p2 = p; *p1++ = *p2++;) 661*7c478bd9Sstevel@tonic-gate ; 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * Restart canonicalization at 664*7c478bd9Sstevel@tonic-gate * expanded "/y". 665*7c478bd9Sstevel@tonic-gate */ 666*7c478bd9Sstevel@tonic-gate p = sp - cp - 1 + newcp; 667*7c478bd9Sstevel@tonic-gate } else { 668*7c478bd9Sstevel@tonic-gate /* 669*7c478bd9Sstevel@tonic-gate * New length is: link + "z" 670*7c478bd9Sstevel@tonic-gate */ 671*7c478bd9Sstevel@tonic-gate p1 = newcp = (tchar *)xalloc((unsigned) 672*7c478bd9Sstevel@tonic-gate (cc + (p1 - p))*sizeof (tchar)); 673*7c478bd9Sstevel@tonic-gate /* 674*7c478bd9Sstevel@tonic-gate * Copy new path into newcp 675*7c478bd9Sstevel@tonic-gate */ 676*7c478bd9Sstevel@tonic-gate for (p2 = link; *p1++ = *p2++;) 677*7c478bd9Sstevel@tonic-gate ; 678*7c478bd9Sstevel@tonic-gate for (p1--, p2 = p; *p1++ = *p2++;) 679*7c478bd9Sstevel@tonic-gate ; 680*7c478bd9Sstevel@tonic-gate /* 681*7c478bd9Sstevel@tonic-gate * Restart canonicalization at beginning 682*7c478bd9Sstevel@tonic-gate */ 683*7c478bd9Sstevel@tonic-gate p = newcp; 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate xfree(cp); 686*7c478bd9Sstevel@tonic-gate cp = newcp; 687*7c478bd9Sstevel@tonic-gate continue; /* canonicalize the link */ 688*7c478bd9Sstevel@tonic-gate } 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate /* The component wasn't a symlink after all. */ 691*7c478bd9Sstevel@tonic-gate if (! hardpaths) 692*7c478bd9Sstevel@tonic-gate *sp = '/'; 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate if (dotdot) { 696*7c478bd9Sstevel@tonic-gate if (sp != cp) 697*7c478bd9Sstevel@tonic-gate while (*--sp != '/') 698*7c478bd9Sstevel@tonic-gate ; 699*7c478bd9Sstevel@tonic-gate if (slash) { 700*7c478bd9Sstevel@tonic-gate for (p1 = sp + 1, p2 = p + 1; *p1++ = *p2++;) 701*7c478bd9Sstevel@tonic-gate ; 702*7c478bd9Sstevel@tonic-gate p = sp; 703*7c478bd9Sstevel@tonic-gate } else if (cp == sp) 704*7c478bd9Sstevel@tonic-gate *++sp = '\0'; 705*7c478bd9Sstevel@tonic-gate else 706*7c478bd9Sstevel@tonic-gate *sp = '\0'; 707*7c478bd9Sstevel@tonic-gate continue; 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate if (slash) 711*7c478bd9Sstevel@tonic-gate *p = '/'; 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate return cp; 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate /* 717*7c478bd9Sstevel@tonic-gate * dnewcwd - make a new directory in the loop the current one 718*7c478bd9Sstevel@tonic-gate * and export its name to the PWD environment variable. 719*7c478bd9Sstevel@tonic-gate */ 720*7c478bd9Sstevel@tonic-gate dnewcwd(dp) 721*7c478bd9Sstevel@tonic-gate register struct directory *dp; 722*7c478bd9Sstevel@tonic-gate { 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate #ifdef TRACE 725*7c478bd9Sstevel@tonic-gate tprintf("TRACE- dnewcwd()\n"); 726*7c478bd9Sstevel@tonic-gate #endif 727*7c478bd9Sstevel@tonic-gate dcwd = dp; 728*7c478bd9Sstevel@tonic-gate #ifdef notdef 729*7c478bd9Sstevel@tonic-gate /* 730*7c478bd9Sstevel@tonic-gate * If we have a fast version of getwd available 731*7c478bd9Sstevel@tonic-gate * and hardpaths is set, it would be reasonable 732*7c478bd9Sstevel@tonic-gate * here to verify that dcwd->di_name really does 733*7c478bd9Sstevel@tonic-gate * name the current directory. Later... 734*7c478bd9Sstevel@tonic-gate */ 735*7c478bd9Sstevel@tonic-gate #endif notdef 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate didchdir=1; 738*7c478bd9Sstevel@tonic-gate set(S_cwd, savestr(dcwd->di_name)); 739*7c478bd9Sstevel@tonic-gate didchdir=0; 740*7c478bd9Sstevel@tonic-gate local_setenv(S_PWD, dcwd->di_name); 741*7c478bd9Sstevel@tonic-gate if (printd) 742*7c478bd9Sstevel@tonic-gate dodirs(fakev); 743*7c478bd9Sstevel@tonic-gate } 744