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