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