1/***********************************************************************
2*                                                                      *
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                     *
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 */
44static 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
52int	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	}
175success:
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
209int	b_pwd(int argc, char *argv[],void *extra)
210{
211	register int n, flag = 0;
212	register char *cp;
213#if SHOPT_FS_3D
214	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
215#else
216	NOT_USED(extra);
217#endif
218	NOT_USED(argc);
219	while((n = optget(argv,sh_optpwd))) switch(n)
220	{
221		case 'L':
222			flag = 0;
223			break;
224		case 'P':
225			flag = 1;
226			break;
227		case ':':
228			errormsg(SH_DICT,2, "%s", opt_info.arg);
229			break;
230		case '?':
231			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
232			break;
233	}
234	if(error_info.errors)
235		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
236	if(*(cp = path_pwd(0)) != '/')
237		errormsg(SH_DICT,ERROR_system(1), e_pwd);
238	if(flag)
239	{
240#if SHOPT_FS_3D
241		if(shp->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0)
242		{
243			cp = (char*)stakseek(++flag+PATH_MAX);
244			mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0);
245		}
246		else
247#endif /* SHOPT_FS_3D */
248			cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp);
249		pathcanon(cp,PATH_PHYSICAL);
250	}
251	sfputr(sfstdout,cp,'\n');
252	return(0);
253}
254
255