14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * cd [-LP]  [dirname]
234887Schin  * cd [-LP]  [old] [new]
244887Schin  * pwd [-LP]
254887Schin  *
264887Schin  *   David Korn
274887Schin  *   AT&T Labs
284887Schin  *   research!dgk
294887Schin  *
304887Schin  */
314887Schin 
324887Schin #include	"defs.h"
334887Schin #include	<stak.h>
344887Schin #include	<error.h>
354887Schin #include	"variables.h"
364887Schin #include	"path.h"
374887Schin #include	"name.h"
384887Schin #include	"builtins.h"
394887Schin #include	<ls.h>
404887Schin #include	<ctype.h>
414887Schin 
424887Schin /*
434887Schin  * Invalidate path name bindings to relative paths
444887Schin  */
454887Schin static void rehash(register Namval_t *np,void *data)
464887Schin {
474887Schin 	Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
484887Schin 	NOT_USED(data);
494887Schin 	if(pp && *pp->name!='/')
504887Schin 		nv_unset(np);
514887Schin }
524887Schin 
534887Schin int	b_cd(int argc, char *argv[],void *extra)
544887Schin {
554887Schin 	register char *dir;
564887Schin 	Pathcomp_t *cdpath = 0;
574887Schin 	register const char *dp;
58*8462SApril.Chin@Sun.COM 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
594887Schin 	int saverrno=0;
604887Schin 	int rval,flag=0;
614887Schin 	char *oldpwd;
624887Schin 	Namval_t *opwdnod, *pwdnod;
634887Schin 	if(sh_isoption(SH_RESTRICTED))
644887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_restricted+4);
654887Schin 	while((rval = optget(argv,sh_optcd))) switch(rval)
664887Schin 	{
674887Schin 		case 'L':
684887Schin 			flag = 0;
694887Schin 			break;
704887Schin 		case 'P':
714887Schin 			flag = 1;
724887Schin 			break;
734887Schin 		case ':':
744887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
754887Schin 			break;
764887Schin 		case '?':
774887Schin 			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
784887Schin 			break;
794887Schin 	}
804887Schin 	argv += opt_info.index;
814887Schin 	argc -= opt_info.index;
824887Schin 	dir =  argv[0];
834887Schin 	if(error_info.errors>0 || argc >2)
844887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
854887Schin 	oldpwd = (char*)shp->pwd;
864887Schin 	opwdnod = (shp->subshell?sh_assignok(OLDPWDNOD,1):OLDPWDNOD);
874887Schin 	pwdnod = (shp->subshell?sh_assignok(PWDNOD,1):PWDNOD);
884887Schin 	if(argc==2)
894887Schin 		dir = sh_substitute(oldpwd,dir,argv[1]);
904887Schin 	else if(!dir || *dir==0)
914887Schin 		dir = nv_getval(HOME);
924887Schin 	else if(*dir == '-' && dir[1]==0)
934887Schin 		dir = nv_getval(opwdnod);
944887Schin 	if(!dir || *dir==0)
954887Schin 		errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct);
964887Schin #if _WINIX
974887Schin 	if(*dir != '/' && (dir[1]!=':'))
984887Schin #else
994887Schin 	if(*dir != '/')
1004887Schin #endif /* _WINIX */
1014887Schin 	{
1024887Schin 		if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=(CDPNOD)->nvalue.cp))
1034887Schin 		{
1044887Schin 			if(cdpath=path_addpath((Pathcomp_t*)0,dp,PATH_CDPATH))
1054887Schin 			{
1064887Schin 				shp->cdpathlist = (void*)cdpath;
1074887Schin 				cdpath->shp = shp;
1084887Schin 			}
1094887Schin 		}
1104887Schin 		if(!oldpwd)
1114887Schin 			oldpwd = path_pwd(1);
1124887Schin 	}
1134887Schin 	if(*dir=='.')
1144887Schin 	{
1154887Schin 		/* test for pathname . ./ .. or ../ */
1164887Schin 		if(*(dp=dir+1) == '.')
1174887Schin 			dp++;
1184887Schin 		if(*dp==0 || *dp=='/')
1194887Schin 			cdpath = 0;
1204887Schin 	}
1214887Schin 	rval = -1;
1224887Schin 	do
1234887Schin 	{
1244887Schin 		dp = cdpath?cdpath->name:"";
1254887Schin 		cdpath = path_nextcomp(cdpath,dir,0);
1264887Schin #if _WINIX
1274887Schin                 if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET)))
1284887Schin 		{
1294887Schin 			*stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET);
1304887Schin 			*stakptr(PATH_OFFSET)='/';
1314887Schin 		}
1324887Schin #endif /* _WINIX */
1334887Schin                 if(*stakptr(PATH_OFFSET)!='/')
1344887Schin 
1354887Schin 		{
1364887Schin 			char *last=(char*)stakfreeze(1);
1374887Schin 			stakseek(PATH_OFFSET);
1384887Schin 			stakputs(oldpwd);
1394887Schin 			/* don't add '/' of oldpwd is / itself */
1404887Schin 			if(*oldpwd!='/' || oldpwd[1])
1414887Schin 				stakputc('/');
1424887Schin 			stakputs(last+PATH_OFFSET);
1434887Schin 			stakputc(0);
1444887Schin 		}
1454887Schin 		if(!flag)
1464887Schin 		{
1474887Schin 			register char *cp;
1484887Schin 			stakseek(PATH_MAX+PATH_OFFSET);
1494887Schin #if SHOPT_FS_3D
1504887Schin 			if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT)))
1514887Schin 				continue;
1524887Schin 			/* eliminate trailing '/' */
1534887Schin 			while(*--cp == '/' && cp>stakptr(PATH_OFFSET))
1544887Schin 				*cp = 0;
1554887Schin #else
1564887Schin 			if(*(cp=stakptr(PATH_OFFSET))=='/')
1574887Schin 				if(!pathcanon(cp,PATH_DOTDOT))
1584887Schin 					continue;
1594887Schin #endif /* SHOPT_FS_3D */
1604887Schin 		}
1614887Schin 		if((rval=chdir(path_relative(stakptr(PATH_OFFSET)))) >= 0)
1624887Schin 			goto success;
1634887Schin 		if(errno!=ENOENT && saverrno==0)
1644887Schin 			saverrno=errno;
1654887Schin 	}
1664887Schin 	while(cdpath);
1674887Schin 	if(rval<0 && *dir=='/' && *(path_relative(stakptr(PATH_OFFSET)))!='/')
1684887Schin 		rval = chdir(dir);
1694887Schin 	/* use absolute chdir() if relative chdir() fails */
1704887Schin 	if(rval<0)
1714887Schin 	{
1724887Schin 		if(saverrno)
1734887Schin 			errno = saverrno;
1744887Schin 		errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
1754887Schin 	}
1764887Schin success:
1774887Schin 	if(dir == nv_getval(opwdnod) || argc==2)
1784887Schin 		dp = dir;	/* print out directory for cd - */
1794887Schin 	if(flag)
1804887Schin 	{
1814887Schin 		dir = stakptr(PATH_OFFSET);
1824887Schin 		if (!(dir=pathcanon(dir,PATH_PHYSICAL)))
1834887Schin 		{
1844887Schin 			dir = stakptr(PATH_OFFSET);
1854887Schin 			errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
1864887Schin 		}
1874887Schin 		stakseek(dir-stakptr(0));
1884887Schin 	}
1894887Schin 	dir = (char*)stakfreeze(1)+PATH_OFFSET;
1904887Schin 	if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/'))
1914887Schin 		sfputr(sfstdout,dir,'\n');
1924887Schin 	if(*dir != '/')
1934887Schin 		return(0);
1944887Schin 	nv_putval(opwdnod,oldpwd,NV_RDONLY);
1954887Schin 	if(oldpwd)
1964887Schin 		free(oldpwd);
1974887Schin 	flag = strlen(dir);
1984887Schin 	/* delete trailing '/' */
1994887Schin 	while(--flag>0 && dir[flag]=='/')
2004887Schin 		dir[flag] = 0;
2014887Schin 	nv_putval(pwdnod,dir,NV_RDONLY);
2024887Schin 	nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT);
2034887Schin 	shp->pwd = pwdnod->nvalue.cp;
2044887Schin 	nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
2054887Schin 	path_newdir(shp->pathlist);
2064887Schin 	path_newdir(shp->cdpathlist);
2074887Schin 	return(0);
2084887Schin }
2094887Schin 
2104887Schin int	b_pwd(int argc, char *argv[],void *extra)
2114887Schin {
2124887Schin 	register int n, flag = 0;
2134887Schin 	register char *cp;
214*8462SApril.Chin@Sun.COM 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
2154887Schin 	NOT_USED(argc);
2164887Schin 	while((n = optget(argv,sh_optpwd))) switch(n)
2174887Schin 	{
2184887Schin 		case 'L':
2194887Schin 			flag = 0;
2204887Schin 			break;
2214887Schin 		case 'P':
2224887Schin 			flag = 1;
2234887Schin 			break;
2244887Schin 		case ':':
2254887Schin 			errormsg(SH_DICT,2, "%s", opt_info.arg);
2264887Schin 			break;
2274887Schin 		case '?':
2284887Schin 			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
2294887Schin 			break;
2304887Schin 	}
2314887Schin 	if(error_info.errors)
2324887Schin 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
2334887Schin 	if(*(cp = path_pwd(0)) != '/')
2344887Schin 		errormsg(SH_DICT,ERROR_system(1), e_pwd);
2354887Schin 	if(flag)
2364887Schin 	{
2374887Schin #if SHOPT_FS_3D
2384887Schin 		if(shp->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0)
2394887Schin 		{
2404887Schin 			cp = (char*)stakseek(++flag+PATH_MAX);
2414887Schin 			mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0);
2424887Schin 		}
2434887Schin 		else
2444887Schin #endif /* SHOPT_FS_3D */
2454887Schin 			cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp);
2464887Schin 		pathcanon(cp,PATH_PHYSICAL);
2474887Schin 	}
2484887Schin 	sfputr(sfstdout,cp,'\n');
2494887Schin 	return(0);
2504887Schin }
2514887Schin 
252