1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 /* 22 * cd [-LP] [dirname] 23 * cd [-LP] [old] [new] 24 * pwd [-LP] 25 * 26 * David Korn 27 * AT&T Labs 28 * research!dgk 29 * 30 */ 31 32 #include "defs.h" 33 #include <stak.h> 34 #include <error.h> 35 #include "variables.h" 36 #include "path.h" 37 #include "name.h" 38 #include "builtins.h" 39 #include <ls.h> 40 #include <ctype.h> 41 42 #ifdef PATH_BFPATH 43 /* 44 * Invalidate path name bindings to relative paths 45 */ 46 static void rehash(register Namval_t *np,void *data) 47 { 48 Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 49 NOT_USED(data); 50 if(pp && *pp->name!='/') 51 nv_unset(np); 52 } 53 #endif 54 55 int b_cd(int argc, char *argv[],void *extra) 56 { 57 #ifdef PATH_BFPATH 58 register char *dir; 59 Pathcomp_t *cdpath = 0; 60 #else 61 register char *dir, *cdpath=""; 62 #endif 63 register const char *dp; 64 register Shell_t *shp = (Shell_t*)extra; 65 int saverrno=0; 66 int rval,flag=0; 67 char *oldpwd; 68 Namval_t *opwdnod, *pwdnod; 69 if(sh_isoption(SH_RESTRICTED)) 70 errormsg(SH_DICT,ERROR_exit(1),e_restricted+4); 71 while((rval = optget(argv,sh_optcd))) switch(rval) 72 { 73 case 'L': 74 flag = 0; 75 break; 76 case 'P': 77 flag = 1; 78 break; 79 case ':': 80 errormsg(SH_DICT,2, "%s", opt_info.arg); 81 break; 82 case '?': 83 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 84 break; 85 } 86 argv += opt_info.index; 87 argc -= opt_info.index; 88 dir = argv[0]; 89 if(error_info.errors>0 || argc >2) 90 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 91 oldpwd = (char*)shp->pwd; 92 opwdnod = (shp->subshell?sh_assignok(OLDPWDNOD,1):OLDPWDNOD); 93 pwdnod = (shp->subshell?sh_assignok(PWDNOD,1):PWDNOD); 94 if(argc==2) 95 dir = sh_substitute(oldpwd,dir,argv[1]); 96 else if(!dir || *dir==0) 97 dir = nv_getval(HOME); 98 else if(*dir == '-' && dir[1]==0) 99 dir = nv_getval(opwdnod); 100 if(!dir || *dir==0) 101 errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct); 102 #if _WINIX 103 if(*dir != '/' && (dir[1]!=':')) 104 #else 105 if(*dir != '/') 106 #endif /* _WINIX */ 107 { 108 #ifdef PATH_BFPATH 109 if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=(CDPNOD)->nvalue.cp)) 110 { 111 if(cdpath=path_addpath((Pathcomp_t*)0,dp,PATH_CDPATH)) 112 { 113 shp->cdpathlist = (void*)cdpath; 114 cdpath->shp = shp; 115 } 116 } 117 #else 118 cdpath = nv_getval(nv_scoped(CDPNOD)); 119 #endif 120 if(!oldpwd) 121 oldpwd = path_pwd(1); 122 } 123 #ifndef PATH_BFPATH 124 if(!cdpath) 125 cdpath = ""; 126 #endif 127 if(*dir=='.') 128 { 129 /* test for pathname . ./ .. or ../ */ 130 if(*(dp=dir+1) == '.') 131 dp++; 132 if(*dp==0 || *dp=='/') 133 #ifdef PATH_BFPATH 134 cdpath = 0; 135 #else 136 cdpath = ""; 137 #endif 138 } 139 rval = -1; 140 do 141 { 142 #ifdef PATH_BFPATH 143 dp = cdpath?cdpath->name:""; 144 cdpath = path_nextcomp(cdpath,dir,0); 145 #else 146 dp = cdpath; 147 cdpath=path_join(cdpath,dir); 148 #endif 149 #if _WINIX 150 if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET))) 151 { 152 *stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET); 153 *stakptr(PATH_OFFSET)='/'; 154 } 155 #endif /* _WINIX */ 156 if(*stakptr(PATH_OFFSET)!='/') 157 158 { 159 char *last=(char*)stakfreeze(1); 160 stakseek(PATH_OFFSET); 161 stakputs(oldpwd); 162 /* don't add '/' of oldpwd is / itself */ 163 if(*oldpwd!='/' || oldpwd[1]) 164 stakputc('/'); 165 stakputs(last+PATH_OFFSET); 166 stakputc(0); 167 } 168 if(!flag) 169 { 170 register char *cp; 171 stakseek(PATH_MAX+PATH_OFFSET); 172 #if SHOPT_FS_3D 173 if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT))) 174 continue; 175 /* eliminate trailing '/' */ 176 while(*--cp == '/' && cp>stakptr(PATH_OFFSET)) 177 *cp = 0; 178 #else 179 if(*(cp=stakptr(PATH_OFFSET))=='/') 180 if(!pathcanon(cp,PATH_DOTDOT)) 181 continue; 182 #endif /* SHOPT_FS_3D */ 183 } 184 if((rval=chdir(path_relative(stakptr(PATH_OFFSET)))) >= 0) 185 goto success; 186 if(errno!=ENOENT && saverrno==0) 187 saverrno=errno; 188 } 189 while(cdpath); 190 if(rval<0 && *dir=='/' && *(path_relative(stakptr(PATH_OFFSET)))!='/') 191 rval = chdir(dir); 192 /* use absolute chdir() if relative chdir() fails */ 193 if(rval<0) 194 { 195 if(saverrno) 196 errno = saverrno; 197 errormsg(SH_DICT,ERROR_system(1),"%s:",dir); 198 } 199 success: 200 if(dir == nv_getval(opwdnod) || argc==2) 201 dp = dir; /* print out directory for cd - */ 202 if(flag) 203 { 204 dir = stakptr(PATH_OFFSET); 205 if (!(dir=pathcanon(dir,PATH_PHYSICAL))) 206 { 207 dir = stakptr(PATH_OFFSET); 208 errormsg(SH_DICT,ERROR_system(1),"%s:",dir); 209 } 210 stakseek(dir-stakptr(0)); 211 } 212 dir = (char*)stakfreeze(1)+PATH_OFFSET; 213 #ifdef PATH_BFPATH 214 if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/')) 215 #else 216 if(*dp && *dp!= ':' && strchr(dir,'/')) 217 #endif 218 sfputr(sfstdout,dir,'\n'); 219 if(*dir != '/') 220 return(0); 221 nv_putval(opwdnod,oldpwd,NV_RDONLY); 222 if(oldpwd) 223 free(oldpwd); 224 flag = strlen(dir); 225 /* delete trailing '/' */ 226 while(--flag>0 && dir[flag]=='/') 227 dir[flag] = 0; 228 nv_putval(pwdnod,dir,NV_RDONLY); 229 nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT); 230 shp->pwd = pwdnod->nvalue.cp; 231 #ifdef PATH_BFPATH 232 nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); 233 path_newdir(shp->pathlist); 234 path_newdir(shp->cdpathlist); 235 #endif 236 return(0); 237 } 238 239 int b_pwd(int argc, char *argv[],void *extra) 240 { 241 register int n, flag = 0; 242 register char *cp; 243 register Shell_t *shp = (Shell_t*)extra; 244 NOT_USED(argc); 245 while((n = optget(argv,sh_optpwd))) switch(n) 246 { 247 case 'L': 248 flag = 0; 249 break; 250 case 'P': 251 flag = 1; 252 break; 253 case ':': 254 errormsg(SH_DICT,2, "%s", opt_info.arg); 255 break; 256 case '?': 257 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 258 break; 259 } 260 if(error_info.errors) 261 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 262 if(*(cp = path_pwd(0)) != '/') 263 errormsg(SH_DICT,ERROR_system(1), e_pwd); 264 if(flag) 265 { 266 #if SHOPT_FS_3D 267 if(shp->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0) 268 { 269 cp = (char*)stakseek(++flag+PATH_MAX); 270 mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0); 271 } 272 else 273 #endif /* SHOPT_FS_3D */ 274 cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp); 275 pathcanon(cp,PATH_PHYSICAL); 276 } 277 sfputr(sfstdout,cp,'\n'); 278 return(0); 279 } 280 281