1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2008 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 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 /* 43 * Invalidate path name bindings to relative paths 44 */ 45 static void rehash(register Namval_t *np,void *data) 46 { 47 Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp; 48 NOT_USED(data); 49 if(pp && *pp->name!='/') 50 nv_unset(np); 51 } 52 53 int b_cd(int argc, char *argv[],void *extra) 54 { 55 register char *dir; 56 Pathcomp_t *cdpath = 0; 57 register const char *dp; 58 register Shell_t *shp = ((Shbltin_t*)extra)->shp; 59 int saverrno=0; 60 int rval,flag=0; 61 char *oldpwd; 62 Namval_t *opwdnod, *pwdnod; 63 if(sh_isoption(SH_RESTRICTED)) 64 errormsg(SH_DICT,ERROR_exit(1),e_restricted+4); 65 while((rval = optget(argv,sh_optcd))) switch(rval) 66 { 67 case 'L': 68 flag = 0; 69 break; 70 case 'P': 71 flag = 1; 72 break; 73 case ':': 74 errormsg(SH_DICT,2, "%s", opt_info.arg); 75 break; 76 case '?': 77 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 78 break; 79 } 80 argv += opt_info.index; 81 argc -= opt_info.index; 82 dir = argv[0]; 83 if(error_info.errors>0 || argc >2) 84 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 85 oldpwd = (char*)shp->pwd; 86 opwdnod = (shp->subshell?sh_assignok(OLDPWDNOD,1):OLDPWDNOD); 87 pwdnod = (shp->subshell?sh_assignok(PWDNOD,1):PWDNOD); 88 if(argc==2) 89 dir = sh_substitute(oldpwd,dir,argv[1]); 90 else if(!dir || *dir==0) 91 dir = nv_getval(HOME); 92 else if(*dir == '-' && dir[1]==0) 93 dir = nv_getval(opwdnod); 94 if(!dir || *dir==0) 95 errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct); 96 #if _WINIX 97 if(*dir != '/' && (dir[1]!=':')) 98 #else 99 if(*dir != '/') 100 #endif /* _WINIX */ 101 { 102 if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=(CDPNOD)->nvalue.cp)) 103 { 104 if(cdpath=path_addpath((Pathcomp_t*)0,dp,PATH_CDPATH)) 105 { 106 shp->cdpathlist = (void*)cdpath; 107 cdpath->shp = shp; 108 } 109 } 110 if(!oldpwd) 111 oldpwd = path_pwd(1); 112 } 113 if(*dir=='.') 114 { 115 /* test for pathname . ./ .. or ../ */ 116 if(*(dp=dir+1) == '.') 117 dp++; 118 if(*dp==0 || *dp=='/') 119 cdpath = 0; 120 } 121 rval = -1; 122 do 123 { 124 dp = cdpath?cdpath->name:""; 125 cdpath = path_nextcomp(cdpath,dir,0); 126 #if _WINIX 127 if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET))) 128 { 129 *stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET); 130 *stakptr(PATH_OFFSET)='/'; 131 } 132 #endif /* _WINIX */ 133 if(*stakptr(PATH_OFFSET)!='/') 134 135 { 136 char *last=(char*)stakfreeze(1); 137 stakseek(PATH_OFFSET); 138 stakputs(oldpwd); 139 /* don't add '/' of oldpwd is / itself */ 140 if(*oldpwd!='/' || oldpwd[1]) 141 stakputc('/'); 142 stakputs(last+PATH_OFFSET); 143 stakputc(0); 144 } 145 if(!flag) 146 { 147 register char *cp; 148 stakseek(PATH_MAX+PATH_OFFSET); 149 #if SHOPT_FS_3D 150 if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT))) 151 continue; 152 /* eliminate trailing '/' */ 153 while(*--cp == '/' && cp>stakptr(PATH_OFFSET)) 154 *cp = 0; 155 #else 156 if(*(cp=stakptr(PATH_OFFSET))=='/') 157 if(!pathcanon(cp,PATH_DOTDOT)) 158 continue; 159 #endif /* SHOPT_FS_3D */ 160 } 161 if((rval=chdir(path_relative(stakptr(PATH_OFFSET)))) >= 0) 162 goto success; 163 if(errno!=ENOENT && saverrno==0) 164 saverrno=errno; 165 } 166 while(cdpath); 167 if(rval<0 && *dir=='/' && *(path_relative(stakptr(PATH_OFFSET)))!='/') 168 rval = chdir(dir); 169 /* use absolute chdir() if relative chdir() fails */ 170 if(rval<0) 171 { 172 if(saverrno) 173 errno = saverrno; 174 errormsg(SH_DICT,ERROR_system(1),"%s:",dir); 175 } 176 success: 177 if(dir == nv_getval(opwdnod) || argc==2) 178 dp = dir; /* print out directory for cd - */ 179 if(flag) 180 { 181 dir = stakptr(PATH_OFFSET); 182 if (!(dir=pathcanon(dir,PATH_PHYSICAL))) 183 { 184 dir = stakptr(PATH_OFFSET); 185 errormsg(SH_DICT,ERROR_system(1),"%s:",dir); 186 } 187 stakseek(dir-stakptr(0)); 188 } 189 dir = (char*)stakfreeze(1)+PATH_OFFSET; 190 if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/')) 191 sfputr(sfstdout,dir,'\n'); 192 if(*dir != '/') 193 return(0); 194 nv_putval(opwdnod,oldpwd,NV_RDONLY); 195 if(oldpwd) 196 free(oldpwd); 197 flag = strlen(dir); 198 /* delete trailing '/' */ 199 while(--flag>0 && dir[flag]=='/') 200 dir[flag] = 0; 201 nv_putval(pwdnod,dir,NV_RDONLY); 202 nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT); 203 shp->pwd = pwdnod->nvalue.cp; 204 nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); 205 path_newdir(shp->pathlist); 206 path_newdir(shp->cdpathlist); 207 return(0); 208 } 209 210 int b_pwd(int argc, char *argv[],void *extra) 211 { 212 register int n, flag = 0; 213 register char *cp; 214 register Shell_t *shp = ((Shbltin_t*)extra)->shp; 215 NOT_USED(argc); 216 while((n = optget(argv,sh_optpwd))) switch(n) 217 { 218 case 'L': 219 flag = 0; 220 break; 221 case 'P': 222 flag = 1; 223 break; 224 case ':': 225 errormsg(SH_DICT,2, "%s", opt_info.arg); 226 break; 227 case '?': 228 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 229 break; 230 } 231 if(error_info.errors) 232 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 233 if(*(cp = path_pwd(0)) != '/') 234 errormsg(SH_DICT,ERROR_system(1), e_pwd); 235 if(flag) 236 { 237 #if SHOPT_FS_3D 238 if(shp->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0) 239 { 240 cp = (char*)stakseek(++flag+PATH_MAX); 241 mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0); 242 } 243 else 244 #endif /* SHOPT_FS_3D */ 245 cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp); 246 pathcanon(cp,PATH_PHYSICAL); 247 } 248 sfputr(sfstdout,cp,'\n'); 249 return(0); 250 } 251 252