1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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,0); 50 } 51 52 int b_cd(int argc, char *argv[],Shbltin_t *context) 53 { 54 register char *dir; 55 Pathcomp_t *cdpath = 0; 56 register const char *dp; 57 register Shell_t *shp = context->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 = path_pwd(shp,0); 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) 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=sh_scoped(shp,CDPNOD)->nvalue.cp)) 102 { 103 if(cdpath=path_addpath(shp,(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(shp,1); 111 } 112 if(*dir!='/') 113 { 114 /* check for leading .. */ 115 char *cp; 116 sfprintf(shp->strbuf,"%s",dir); 117 cp = sfstruse(shp->strbuf); 118 pathcanon(cp, 0); 119 if(cp[0]=='.' && cp[1]=='.' && (cp[2]=='/' || cp[2]==0)) 120 { 121 if(!shp->strbuf2) 122 shp->strbuf2 = sfstropen(); 123 sfprintf(shp->strbuf2,"%s/%s",oldpwd,cp); 124 dir = sfstruse(shp->strbuf2); 125 pathcanon(dir, 0); 126 } 127 } 128 rval = -1; 129 do 130 { 131 dp = cdpath?cdpath->name:""; 132 cdpath = path_nextcomp(shp,cdpath,dir,0); 133 #if _WINIX 134 if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET))) 135 { 136 *stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET); 137 *stakptr(PATH_OFFSET)='/'; 138 } 139 #endif /* _WINIX */ 140 if(*stakptr(PATH_OFFSET)!='/') 141 142 { 143 char *last=(char*)stakfreeze(1); 144 stakseek(PATH_OFFSET); 145 stakputs(oldpwd); 146 /* don't add '/' of oldpwd is / itself */ 147 if(*oldpwd!='/' || oldpwd[1]) 148 stakputc('/'); 149 stakputs(last+PATH_OFFSET); 150 stakputc(0); 151 } 152 if(!flag) 153 { 154 register char *cp; 155 stakseek(PATH_MAX+PATH_OFFSET); 156 #if SHOPT_FS_3D 157 if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT))) 158 continue; 159 /* eliminate trailing '/' */ 160 while(*--cp == '/' && cp>stakptr(PATH_OFFSET)) 161 *cp = 0; 162 #else 163 if(*(cp=stakptr(PATH_OFFSET))=='/') 164 if(!pathcanon(cp,PATH_DOTDOT)) 165 continue; 166 #endif /* SHOPT_FS_3D */ 167 } 168 if((rval=chdir(path_relative(shp,stakptr(PATH_OFFSET)))) >= 0) 169 goto success; 170 if(errno!=ENOENT && saverrno==0) 171 saverrno=errno; 172 } 173 while(cdpath); 174 if(rval<0 && *dir=='/' && *(path_relative(shp,stakptr(PATH_OFFSET)))!='/') 175 rval = chdir(dir); 176 /* use absolute chdir() if relative chdir() fails */ 177 if(rval<0) 178 { 179 if(saverrno) 180 errno = saverrno; 181 errormsg(SH_DICT,ERROR_system(1),"%s:",dir); 182 } 183 success: 184 if(dir == nv_getval(opwdnod) || argc==2) 185 dp = dir; /* print out directory for cd - */ 186 if(flag) 187 { 188 dir = stakptr(PATH_OFFSET); 189 if (!(dir=pathcanon(dir,PATH_PHYSICAL))) 190 { 191 dir = stakptr(PATH_OFFSET); 192 errormsg(SH_DICT,ERROR_system(1),"%s:",dir); 193 } 194 stakseek(dir-stakptr(0)); 195 } 196 dir = (char*)stakfreeze(1)+PATH_OFFSET; 197 if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/')) 198 sfputr(sfstdout,dir,'\n'); 199 if(*dir != '/') 200 return(0); 201 nv_putval(opwdnod,oldpwd,NV_RDONLY); 202 flag = strlen(dir); 203 /* delete trailing '/' */ 204 while(--flag>0 && dir[flag]=='/') 205 dir[flag] = 0; 206 nv_putval(pwdnod,dir,NV_RDONLY); 207 nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT); 208 shp->pwd = pwdnod->nvalue.cp; 209 nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); 210 path_newdir(shp,shp->pathlist); 211 path_newdir(shp,shp->cdpathlist); 212 if(oldpwd && (oldpwd!=e_dot)) 213 free(oldpwd); 214 return(0); 215 } 216 217 int b_pwd(int argc, char *argv[],Shbltin_t *context) 218 { 219 register int n, flag = 0; 220 register char *cp; 221 register Shell_t *shp = context->shp; 222 NOT_USED(argc); 223 while((n = optget(argv,sh_optpwd))) switch(n) 224 { 225 case 'L': 226 flag = 0; 227 break; 228 case 'P': 229 flag = 1; 230 break; 231 case ':': 232 errormsg(SH_DICT,2, "%s", opt_info.arg); 233 break; 234 case '?': 235 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg); 236 break; 237 } 238 if(error_info.errors) 239 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 240 if(*(cp = path_pwd(shp,0)) != '/') 241 errormsg(SH_DICT,ERROR_system(1), e_pwd); 242 if(flag) 243 { 244 #if SHOPT_FS_3D 245 if(shp->gd->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0) 246 { 247 cp = (char*)stakseek(++flag+PATH_MAX); 248 mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0); 249 } 250 else 251 #endif /* SHOPT_FS_3D */ 252 cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp); 253 pathcanon(cp,PATH_PHYSICAL); 254 } 255 sfputr(sfstdout,cp,'\n'); 256 return(0); 257 } 258 259