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 */
rehash(register Namval_t * np,void * data)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
b_cd(int argc,char * argv[],Shbltin_t * context)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
b_pwd(int argc,char * argv[],Shbltin_t * context)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