1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * cd [-LP]  [dirname]
23*4887Schin  * cd [-LP]  [old] [new]
24*4887Schin  * pwd [-LP]
25*4887Schin  *
26*4887Schin  *   David Korn
27*4887Schin  *   AT&T Labs
28*4887Schin  *   research!dgk
29*4887Schin  *
30*4887Schin  */
31*4887Schin 
32*4887Schin #include	"defs.h"
33*4887Schin #include	<stak.h>
34*4887Schin #include	<error.h>
35*4887Schin #include	"variables.h"
36*4887Schin #include	"path.h"
37*4887Schin #include	"name.h"
38*4887Schin #include	"builtins.h"
39*4887Schin #include	<ls.h>
40*4887Schin #include	<ctype.h>
41*4887Schin 
42*4887Schin #ifdef PATH_BFPATH
43*4887Schin /*
44*4887Schin  * Invalidate path name bindings to relative paths
45*4887Schin  */
46*4887Schin static void rehash(register Namval_t *np,void *data)
47*4887Schin {
48*4887Schin 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
49*4887Schin 	NOT_USED(data);
50*4887Schin 	if(pp && *pp->name!='/')
51*4887Schin 		nv_unset(np);
52*4887Schin }
53*4887Schin #endif
54*4887Schin 
55*4887Schin int	b_cd(int argc, char *argv[],void *extra)
56*4887Schin {
57*4887Schin #ifdef PATH_BFPATH
58*4887Schin 	register char *dir;
59*4887Schin 	Pathcomp_t *cdpath = 0;
60*4887Schin #else
61*4887Schin 	register char *dir, *cdpath="";
62*4887Schin #endif
63*4887Schin 	register const char *dp;
64*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
65*4887Schin 	int saverrno=0;
66*4887Schin 	int rval,flag=0;
67*4887Schin 	char *oldpwd;
68*4887Schin 	Namval_t *opwdnod, *pwdnod;
69*4887Schin 	if(sh_isoption(SH_RESTRICTED))
70*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted+4);
71*4887Schin 	while((rval = optget(argv,sh_optcd))) switch(rval)
72*4887Schin 	{
73*4887Schin 		case 'L':
74*4887Schin 			flag = 0;
75*4887Schin 			break;
76*4887Schin 		case 'P':
77*4887Schin 			flag = 1;
78*4887Schin 			break;
79*4887Schin 		case ':':
80*4887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
81*4887Schin 			break;
82*4887Schin 		case '?':
83*4887Schin 			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
84*4887Schin 			break;
85*4887Schin 	}
86*4887Schin 	argv += opt_info.index;
87*4887Schin 	argc -= opt_info.index;
88*4887Schin 	dir =  argv[0];
89*4887Schin 	if(error_info.errors>0 || argc >2)
90*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
91*4887Schin 	oldpwd = (char*)shp->pwd;
92*4887Schin 	opwdnod = (shp->subshell?sh_assignok(OLDPWDNOD,1):OLDPWDNOD);
93*4887Schin 	pwdnod = (shp->subshell?sh_assignok(PWDNOD,1):PWDNOD);
94*4887Schin 	if(argc==2)
95*4887Schin 		dir = sh_substitute(oldpwd,dir,argv[1]);
96*4887Schin 	else if(!dir || *dir==0)
97*4887Schin 		dir = nv_getval(HOME);
98*4887Schin 	else if(*dir == '-' && dir[1]==0)
99*4887Schin 		dir = nv_getval(opwdnod);
100*4887Schin 	if(!dir || *dir==0)
101*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct);
102*4887Schin #if _WINIX
103*4887Schin 	if(*dir != '/' && (dir[1]!=':'))
104*4887Schin #else
105*4887Schin 	if(*dir != '/')
106*4887Schin #endif /* _WINIX */
107*4887Schin 	{
108*4887Schin #ifdef PATH_BFPATH
109*4887Schin 		if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=(CDPNOD)->nvalue.cp))
110*4887Schin 		{
111*4887Schin 			if(cdpath=path_addpath((Pathcomp_t*)0,dp,PATH_CDPATH))
112*4887Schin 			{
113*4887Schin 				shp->cdpathlist = (void*)cdpath;
114*4887Schin 				cdpath->shp = shp;
115*4887Schin 			}
116*4887Schin 		}
117*4887Schin #else
118*4887Schin 		cdpath = nv_getval(nv_scoped(CDPNOD));
119*4887Schin #endif
120*4887Schin 		if(!oldpwd)
121*4887Schin 			oldpwd = path_pwd(1);
122*4887Schin 	}
123*4887Schin #ifndef PATH_BFPATH
124*4887Schin 	if(!cdpath)
125*4887Schin 		cdpath = "";
126*4887Schin #endif
127*4887Schin 	if(*dir=='.')
128*4887Schin 	{
129*4887Schin 		/* test for pathname . ./ .. or ../ */
130*4887Schin 		if(*(dp=dir+1) == '.')
131*4887Schin 			dp++;
132*4887Schin 		if(*dp==0 || *dp=='/')
133*4887Schin #ifdef PATH_BFPATH
134*4887Schin 			cdpath = 0;
135*4887Schin #else
136*4887Schin 			cdpath = "";
137*4887Schin #endif
138*4887Schin 	}
139*4887Schin 	rval = -1;
140*4887Schin 	do
141*4887Schin 	{
142*4887Schin #ifdef PATH_BFPATH
143*4887Schin 		dp = cdpath?cdpath->name:"";
144*4887Schin 		cdpath = path_nextcomp(cdpath,dir,0);
145*4887Schin #else
146*4887Schin 		dp = cdpath;
147*4887Schin 		cdpath=path_join(cdpath,dir);
148*4887Schin #endif
149*4887Schin #if _WINIX
150*4887Schin                 if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET)))
151*4887Schin 		{
152*4887Schin 			*stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET);
153*4887Schin 			*stakptr(PATH_OFFSET)='/';
154*4887Schin 		}
155*4887Schin #endif /* _WINIX */
156*4887Schin                 if(*stakptr(PATH_OFFSET)!='/')
157*4887Schin 
158*4887Schin 		{
159*4887Schin 			char *last=(char*)stakfreeze(1);
160*4887Schin 			stakseek(PATH_OFFSET);
161*4887Schin 			stakputs(oldpwd);
162*4887Schin 			/* don't add '/' of oldpwd is / itself */
163*4887Schin 			if(*oldpwd!='/' || oldpwd[1])
164*4887Schin 				stakputc('/');
165*4887Schin 			stakputs(last+PATH_OFFSET);
166*4887Schin 			stakputc(0);
167*4887Schin 		}
168*4887Schin 		if(!flag)
169*4887Schin 		{
170*4887Schin 			register char *cp;
171*4887Schin 			stakseek(PATH_MAX+PATH_OFFSET);
172*4887Schin #if SHOPT_FS_3D
173*4887Schin 			if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT)))
174*4887Schin 				continue;
175*4887Schin 			/* eliminate trailing '/' */
176*4887Schin 			while(*--cp == '/' && cp>stakptr(PATH_OFFSET))
177*4887Schin 				*cp = 0;
178*4887Schin #else
179*4887Schin 			if(*(cp=stakptr(PATH_OFFSET))=='/')
180*4887Schin 				if(!pathcanon(cp,PATH_DOTDOT))
181*4887Schin 					continue;
182*4887Schin #endif /* SHOPT_FS_3D */
183*4887Schin 		}
184*4887Schin 		if((rval=chdir(path_relative(stakptr(PATH_OFFSET)))) >= 0)
185*4887Schin 			goto success;
186*4887Schin 		if(errno!=ENOENT && saverrno==0)
187*4887Schin 			saverrno=errno;
188*4887Schin 	}
189*4887Schin 	while(cdpath);
190*4887Schin 	if(rval<0 && *dir=='/' && *(path_relative(stakptr(PATH_OFFSET)))!='/')
191*4887Schin 		rval = chdir(dir);
192*4887Schin 	/* use absolute chdir() if relative chdir() fails */
193*4887Schin 	if(rval<0)
194*4887Schin 	{
195*4887Schin 		if(saverrno)
196*4887Schin 			errno = saverrno;
197*4887Schin 		errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
198*4887Schin 	}
199*4887Schin success:
200*4887Schin 	if(dir == nv_getval(opwdnod) || argc==2)
201*4887Schin 		dp = dir;	/* print out directory for cd - */
202*4887Schin 	if(flag)
203*4887Schin 	{
204*4887Schin 		dir = stakptr(PATH_OFFSET);
205*4887Schin 		if (!(dir=pathcanon(dir,PATH_PHYSICAL)))
206*4887Schin 		{
207*4887Schin 			dir = stakptr(PATH_OFFSET);
208*4887Schin 			errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
209*4887Schin 		}
210*4887Schin 		stakseek(dir-stakptr(0));
211*4887Schin 	}
212*4887Schin 	dir = (char*)stakfreeze(1)+PATH_OFFSET;
213*4887Schin #ifdef PATH_BFPATH
214*4887Schin 	if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/'))
215*4887Schin #else
216*4887Schin 	if(*dp && *dp!= ':' && strchr(dir,'/'))
217*4887Schin #endif
218*4887Schin 		sfputr(sfstdout,dir,'\n');
219*4887Schin 	if(*dir != '/')
220*4887Schin 		return(0);
221*4887Schin 	nv_putval(opwdnod,oldpwd,NV_RDONLY);
222*4887Schin 	if(oldpwd)
223*4887Schin 		free(oldpwd);
224*4887Schin 	flag = strlen(dir);
225*4887Schin 	/* delete trailing '/' */
226*4887Schin 	while(--flag>0 && dir[flag]=='/')
227*4887Schin 		dir[flag] = 0;
228*4887Schin 	nv_putval(pwdnod,dir,NV_RDONLY);
229*4887Schin 	nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT);
230*4887Schin 	shp->pwd = pwdnod->nvalue.cp;
231*4887Schin #ifdef PATH_BFPATH
232*4887Schin 	nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
233*4887Schin 	path_newdir(shp->pathlist);
234*4887Schin 	path_newdir(shp->cdpathlist);
235*4887Schin #endif
236*4887Schin 	return(0);
237*4887Schin }
238*4887Schin 
239*4887Schin int	b_pwd(int argc, char *argv[],void *extra)
240*4887Schin {
241*4887Schin 	register int n, flag = 0;
242*4887Schin 	register char *cp;
243*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
244*4887Schin 	NOT_USED(argc);
245*4887Schin 	while((n = optget(argv,sh_optpwd))) switch(n)
246*4887Schin 	{
247*4887Schin 		case 'L':
248*4887Schin 			flag = 0;
249*4887Schin 			break;
250*4887Schin 		case 'P':
251*4887Schin 			flag = 1;
252*4887Schin 			break;
253*4887Schin 		case ':':
254*4887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
255*4887Schin 			break;
256*4887Schin 		case '?':
257*4887Schin 			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
258*4887Schin 			break;
259*4887Schin 	}
260*4887Schin 	if(error_info.errors)
261*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
262*4887Schin 	if(*(cp = path_pwd(0)) != '/')
263*4887Schin 		errormsg(SH_DICT,ERROR_system(1), e_pwd);
264*4887Schin 	if(flag)
265*4887Schin 	{
266*4887Schin #if SHOPT_FS_3D
267*4887Schin 		if(shp->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0)
268*4887Schin 		{
269*4887Schin 			cp = (char*)stakseek(++flag+PATH_MAX);
270*4887Schin 			mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0);
271*4887Schin 		}
272*4887Schin 		else
273*4887Schin #endif /* SHOPT_FS_3D */
274*4887Schin 			cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp);
275*4887Schin 		pathcanon(cp,PATH_PHYSICAL);
276*4887Schin 	}
277*4887Schin 	sfputr(sfstdout,cp,'\n');
278*4887Schin 	return(0);
279*4887Schin }
280*4887Schin 
281