1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
23 * cd [-LP] [old] [new]
35 #include "variables.h"
42 * Invalidate path name bindings to relative paths
44 static void rehash(register Namval_t
*np
,void *data
)
46 Pathcomp_t
*pp
= (Pathcomp_t
*)np
->nvalue
.cp
;
48 if(pp
&& *pp
->name
!='/')
52 int b_cd(int argc
, char *argv
[],void *extra
)
55 Pathcomp_t
*cdpath
= 0;
56 register const char *dp
;
57 register Shell_t
*shp
= ((Shbltin_t
*)extra
)->shp
;
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
)
73 errormsg(SH_DICT
,2, "%s", opt_info
.arg
);
76 errormsg(SH_DICT
,ERROR_usage(2), "%s", opt_info
.arg
);
79 argv
+= opt_info
.index
;
80 argc
-= opt_info
.index
;
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
);
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
);
94 errormsg(SH_DICT
,ERROR_exit(1),argc
==2?e_subst
+4:e_direct
);
96 if(*dir
!= '/' && (dir
[1]!=':'))
101 if(!(cdpath
= (Pathcomp_t
*)shp
->cdpathlist
) && (dp
=(CDPNOD
)->nvalue
.cp
))
103 if(cdpath
=path_addpath((Pathcomp_t
*)0,dp
,PATH_CDPATH
))
105 shp
->cdpathlist
= (void*)cdpath
;
110 oldpwd
= path_pwd(1);
114 /* test for pathname . ./ .. or ../ */
115 if(*(dp
=dir
+1) == '.')
117 if(*dp
==0 || *dp
=='/')
123 dp
= cdpath
?cdpath
->name
:"";
124 cdpath
= path_nextcomp(cdpath
,dir
,0);
126 if(*stakptr(PATH_OFFSET
+1)==':' && isalpha(*stakptr(PATH_OFFSET
)))
128 *stakptr(PATH_OFFSET
+1) = *stakptr(PATH_OFFSET
);
129 *stakptr(PATH_OFFSET
)='/';
132 if(*stakptr(PATH_OFFSET
)!='/')
135 char *last
=(char*)stakfreeze(1);
136 stakseek(PATH_OFFSET
);
138 /* don't add '/' of oldpwd is / itself */
139 if(*oldpwd
!='/' || oldpwd
[1])
141 stakputs(last
+PATH_OFFSET
);
147 stakseek(PATH_MAX
+PATH_OFFSET
);
149 if(!(cp
= pathcanon(stakptr(PATH_OFFSET
),PATH_DOTDOT
)))
151 /* eliminate trailing '/' */
152 while(*--cp
== '/' && cp
>stakptr(PATH_OFFSET
))
155 if(*(cp
=stakptr(PATH_OFFSET
))=='/')
156 if(!pathcanon(cp
,PATH_DOTDOT
))
158 #endif /* SHOPT_FS_3D */
160 if((rval
=chdir(path_relative(stakptr(PATH_OFFSET
)))) >= 0)
162 if(errno
!=ENOENT
&& saverrno
==0)
166 if(rval
<0 && *dir
=='/' && *(path_relative(stakptr(PATH_OFFSET
)))!='/')
168 /* use absolute chdir() if relative chdir() fails */
173 errormsg(SH_DICT
,ERROR_system(1),"%s:",dir
);
176 if(dir
== nv_getval(opwdnod
) || argc
==2)
177 dp
= dir
; /* print out directory for cd - */
180 dir
= stakptr(PATH_OFFSET
);
181 if (!(dir
=pathcanon(dir
,PATH_PHYSICAL
)))
183 dir
= stakptr(PATH_OFFSET
);
184 errormsg(SH_DICT
,ERROR_system(1),"%s:",dir
);
186 stakseek(dir
-stakptr(0));
188 dir
= (char*)stakfreeze(1)+PATH_OFFSET
;
189 if(*dp
&& (*dp
!='.'||dp
[1]) && strchr(dir
,'/'))
190 sfputr(sfstdout
,dir
,'\n');
193 nv_putval(opwdnod
,oldpwd
,NV_RDONLY
);
196 /* delete trailing '/' */
197 while(--flag
>0 && dir
[flag
]=='/')
199 nv_putval(pwdnod
,dir
,NV_RDONLY
);
200 nv_onattr(pwdnod
,NV_NOFREE
|NV_EXPORT
);
201 shp
->pwd
= pwdnod
->nvalue
.cp
;
202 nv_scan(shp
->track_tree
,rehash
,(void*)0,NV_TAGGED
,NV_TAGGED
);
203 path_newdir(shp
->pathlist
);
204 path_newdir(shp
->cdpathlist
);
208 int b_pwd(int argc
, char *argv
[],void *extra
)
210 register int n
, flag
= 0;
213 register Shell_t
*shp
= ((Shbltin_t
*)extra
)->shp
;
218 while((n
= optget(argv
,sh_optpwd
))) switch(n
)
227 errormsg(SH_DICT
,2, "%s", opt_info
.arg
);
230 errormsg(SH_DICT
,ERROR_usage(2), "%s", opt_info
.arg
);
233 if(error_info
.errors
)
234 errormsg(SH_DICT
,ERROR_usage(2),"%s",optusage((char*)0));
235 if(*(cp
= path_pwd(0)) != '/')
236 errormsg(SH_DICT
,ERROR_system(1), e_pwd
);
240 if(shp
->lim
.fs3d
&& (flag
= mount(e_dot
,NIL(char*),FS3D_GET
|FS3D_VIEW
,0))>=0)
242 cp
= (char*)stakseek(++flag
+PATH_MAX
);
243 mount(e_dot
,cp
,FS3D_GET
|FS3D_VIEW
|FS3D_SIZE(flag
),0);
246 #endif /* SHOPT_FS_3D */
247 cp
= strcpy(stakseek(strlen(cp
)+PATH_MAX
),cp
);
248 pathcanon(cp
,PATH_PHYSICAL
);
250 sfputr(sfstdout
,cp
,'\n');