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