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