14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.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
414887Schin /*
424887Schin * Invalidate path name bindings to relative paths
434887Schin */
rehash(register Namval_t * np,void * data)444887Schin static void rehash(register Namval_t *np,void *data)
454887Schin {
464887Schin Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
474887Schin NOT_USED(data);
484887Schin if(pp && *pp->name!='/')
494887Schin nv_unset(np);
504887Schin }
514887Schin
b_cd(int argc,char * argv[],void * extra)524887Schin int b_cd(int argc, char *argv[],void *extra)
534887Schin {
544887Schin register char *dir;
554887Schin Pathcomp_t *cdpath = 0;
564887Schin register const char *dp;
578462SApril.Chin@Sun.COM register Shell_t *shp = ((Shbltin_t*)extra)->shp;
584887Schin int saverrno=0;
594887Schin int rval,flag=0;
604887Schin char *oldpwd;
614887Schin Namval_t *opwdnod, *pwdnod;
624887Schin if(sh_isoption(SH_RESTRICTED))
634887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted+4);
644887Schin while((rval = optget(argv,sh_optcd))) switch(rval)
654887Schin {
664887Schin case 'L':
674887Schin flag = 0;
684887Schin break;
694887Schin case 'P':
704887Schin flag = 1;
714887Schin break;
724887Schin case ':':
734887Schin errormsg(SH_DICT,2, "%s", opt_info.arg);
744887Schin break;
754887Schin case '?':
764887Schin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
774887Schin break;
784887Schin }
794887Schin argv += opt_info.index;
804887Schin argc -= opt_info.index;
814887Schin dir = argv[0];
824887Schin if(error_info.errors>0 || argc >2)
834887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
844887Schin oldpwd = (char*)shp->pwd;
854887Schin opwdnod = (shp->subshell?sh_assignok(OLDPWDNOD,1):OLDPWDNOD);
864887Schin pwdnod = (shp->subshell?sh_assignok(PWDNOD,1):PWDNOD);
874887Schin if(argc==2)
884887Schin dir = sh_substitute(oldpwd,dir,argv[1]);
894887Schin else if(!dir || *dir==0)
904887Schin dir = nv_getval(HOME);
914887Schin else if(*dir == '-' && dir[1]==0)
924887Schin dir = nv_getval(opwdnod);
934887Schin if(!dir || *dir==0)
944887Schin errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct);
954887Schin #if _WINIX
964887Schin if(*dir != '/' && (dir[1]!=':'))
974887Schin #else
984887Schin if(*dir != '/')
994887Schin #endif /* _WINIX */
1004887Schin {
1014887Schin if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=(CDPNOD)->nvalue.cp))
1024887Schin {
1034887Schin if(cdpath=path_addpath((Pathcomp_t*)0,dp,PATH_CDPATH))
1044887Schin {
1054887Schin shp->cdpathlist = (void*)cdpath;
1064887Schin cdpath->shp = shp;
1074887Schin }
1084887Schin }
1094887Schin if(!oldpwd)
1104887Schin oldpwd = path_pwd(1);
1114887Schin }
1124887Schin if(*dir=='.')
1134887Schin {
1144887Schin /* test for pathname . ./ .. or ../ */
1154887Schin if(*(dp=dir+1) == '.')
1164887Schin dp++;
1174887Schin if(*dp==0 || *dp=='/')
1184887Schin cdpath = 0;
1194887Schin }
1204887Schin rval = -1;
1214887Schin do
1224887Schin {
1234887Schin dp = cdpath?cdpath->name:"";
1244887Schin cdpath = path_nextcomp(cdpath,dir,0);
1254887Schin #if _WINIX
1264887Schin if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET)))
1274887Schin {
1284887Schin *stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET);
1294887Schin *stakptr(PATH_OFFSET)='/';
1304887Schin }
1314887Schin #endif /* _WINIX */
1324887Schin if(*stakptr(PATH_OFFSET)!='/')
1334887Schin
1344887Schin {
1354887Schin char *last=(char*)stakfreeze(1);
1364887Schin stakseek(PATH_OFFSET);
1374887Schin stakputs(oldpwd);
1384887Schin /* don't add '/' of oldpwd is / itself */
1394887Schin if(*oldpwd!='/' || oldpwd[1])
1404887Schin stakputc('/');
1414887Schin stakputs(last+PATH_OFFSET);
1424887Schin stakputc(0);
1434887Schin }
1444887Schin if(!flag)
1454887Schin {
1464887Schin register char *cp;
1474887Schin stakseek(PATH_MAX+PATH_OFFSET);
1484887Schin #if SHOPT_FS_3D
1494887Schin if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT)))
1504887Schin continue;
1514887Schin /* eliminate trailing '/' */
1524887Schin while(*--cp == '/' && cp>stakptr(PATH_OFFSET))
1534887Schin *cp = 0;
1544887Schin #else
1554887Schin if(*(cp=stakptr(PATH_OFFSET))=='/')
1564887Schin if(!pathcanon(cp,PATH_DOTDOT))
1574887Schin continue;
1584887Schin #endif /* SHOPT_FS_3D */
1594887Schin }
1604887Schin if((rval=chdir(path_relative(stakptr(PATH_OFFSET)))) >= 0)
1614887Schin goto success;
1624887Schin if(errno!=ENOENT && saverrno==0)
1634887Schin saverrno=errno;
1644887Schin }
1654887Schin while(cdpath);
1664887Schin if(rval<0 && *dir=='/' && *(path_relative(stakptr(PATH_OFFSET)))!='/')
1674887Schin rval = chdir(dir);
1684887Schin /* use absolute chdir() if relative chdir() fails */
1694887Schin if(rval<0)
1704887Schin {
1714887Schin if(saverrno)
1724887Schin errno = saverrno;
1734887Schin errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
1744887Schin }
1754887Schin success:
1764887Schin if(dir == nv_getval(opwdnod) || argc==2)
1774887Schin dp = dir; /* print out directory for cd - */
1784887Schin if(flag)
1794887Schin {
1804887Schin dir = stakptr(PATH_OFFSET);
1814887Schin if (!(dir=pathcanon(dir,PATH_PHYSICAL)))
1824887Schin {
1834887Schin dir = stakptr(PATH_OFFSET);
1844887Schin errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
1854887Schin }
1864887Schin stakseek(dir-stakptr(0));
1874887Schin }
1884887Schin dir = (char*)stakfreeze(1)+PATH_OFFSET;
1894887Schin if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/'))
1904887Schin sfputr(sfstdout,dir,'\n');
1914887Schin if(*dir != '/')
1924887Schin return(0);
1934887Schin nv_putval(opwdnod,oldpwd,NV_RDONLY);
1944887Schin if(oldpwd)
1954887Schin free(oldpwd);
1964887Schin flag = strlen(dir);
1974887Schin /* delete trailing '/' */
1984887Schin while(--flag>0 && dir[flag]=='/')
1994887Schin dir[flag] = 0;
2004887Schin nv_putval(pwdnod,dir,NV_RDONLY);
2014887Schin nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT);
2024887Schin shp->pwd = pwdnod->nvalue.cp;
2034887Schin nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
2044887Schin path_newdir(shp->pathlist);
2054887Schin path_newdir(shp->cdpathlist);
2064887Schin return(0);
2074887Schin }
2084887Schin
b_pwd(int argc,char * argv[],void * extra)2094887Schin int b_pwd(int argc, char *argv[],void *extra)
2104887Schin {
2114887Schin register int n, flag = 0;
2124887Schin register char *cp;
213*12068SRoger.Faulkner@Oracle.COM #if SHOPT_FS_3D
2148462SApril.Chin@Sun.COM register Shell_t *shp = ((Shbltin_t*)extra)->shp;
215*12068SRoger.Faulkner@Oracle.COM #else
216*12068SRoger.Faulkner@Oracle.COM NOT_USED(extra);
217*12068SRoger.Faulkner@Oracle.COM #endif
2184887Schin NOT_USED(argc);
2194887Schin while((n = optget(argv,sh_optpwd))) switch(n)
2204887Schin {
2214887Schin case 'L':
2224887Schin flag = 0;
2234887Schin break;
2244887Schin case 'P':
2254887Schin flag = 1;
2264887Schin break;
2274887Schin case ':':
2284887Schin errormsg(SH_DICT,2, "%s", opt_info.arg);
2294887Schin break;
2304887Schin case '?':
2314887Schin errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
2324887Schin break;
2334887Schin }
2344887Schin if(error_info.errors)
2354887Schin errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
2364887Schin if(*(cp = path_pwd(0)) != '/')
2374887Schin errormsg(SH_DICT,ERROR_system(1), e_pwd);
2384887Schin if(flag)
2394887Schin {
2404887Schin #if SHOPT_FS_3D
2414887Schin if(shp->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0)
2424887Schin {
2434887Schin cp = (char*)stakseek(++flag+PATH_MAX);
2444887Schin mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0);
2454887Schin }
2464887Schin else
2474887Schin #endif /* SHOPT_FS_3D */
2484887Schin cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp);
2494887Schin pathcanon(cp,PATH_PHYSICAL);
2504887Schin }
2514887Schin sfputr(sfstdout,cp,'\n');
2524887Schin return(0);
2534887Schin }
2544887Schin
255