1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1982-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * cd [-LP] [dirname]
1N/A * cd [-LP] [old] [new]
1N/A * pwd [-LP]
1N/A *
1N/A * David Korn
1N/A * AT&T Labs
1N/A * research!dgk
1N/A *
1N/A */
1N/A
1N/A#include "defs.h"
1N/A#include <stak.h>
1N/A#include <error.h>
1N/A#include "variables.h"
1N/A#include "path.h"
1N/A#include "name.h"
1N/A#include "builtins.h"
1N/A#include <ls.h>
1N/A
1N/A/*
1N/A * Invalidate path name bindings to relative paths
1N/A */
1N/Astatic void rehash(register Namval_t *np,void *data)
1N/A{
1N/A Pathcomp_t *pp = (Pathcomp_t*)np->nvalue.cp;
1N/A NOT_USED(data);
1N/A if(pp && *pp->name!='/')
1N/A _nv_unset(np,0);
1N/A}
1N/A
1N/Aint b_cd(int argc, char *argv[],void *extra)
1N/A{
1N/A register char *dir;
1N/A Pathcomp_t *cdpath = 0;
1N/A register const char *dp;
1N/A register Shell_t *shp = ((Shbltin_t*)extra)->shp;
1N/A int saverrno=0;
1N/A int rval,flag=0;
1N/A char *oldpwd;
1N/A Namval_t *opwdnod, *pwdnod;
1N/A if(sh_isoption(SH_RESTRICTED))
1N/A errormsg(SH_DICT,ERROR_exit(1),e_restricted+4);
1N/A while((rval = optget(argv,sh_optcd))) switch(rval)
1N/A {
1N/A case 'L':
1N/A flag = 0;
1N/A break;
1N/A case 'P':
1N/A flag = 1;
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT,2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argv += opt_info.index;
1N/A argc -= opt_info.index;
1N/A dir = argv[0];
1N/A if(error_info.errors>0 || argc >2)
1N/A errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
1N/A oldpwd = (char*)shp->pwd;
1N/A opwdnod = (shp->subshell?sh_assignok(OLDPWDNOD,1):OLDPWDNOD);
1N/A pwdnod = (shp->subshell?sh_assignok(PWDNOD,1):PWDNOD);
1N/A if(argc==2)
1N/A dir = sh_substitute(oldpwd,dir,argv[1]);
1N/A else if(!dir)
1N/A dir = nv_getval(HOME);
1N/A else if(*dir == '-' && dir[1]==0)
1N/A dir = nv_getval(opwdnod);
1N/A if(!dir || *dir==0)
1N/A errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct);
1N/A#if _WINIX
1N/A if(*dir != '/' && (dir[1]!=':'))
1N/A#else
1N/A if(*dir != '/')
1N/A#endif /* _WINIX */
1N/A {
1N/A if(!(cdpath = (Pathcomp_t*)shp->cdpathlist) && (dp=sh_scoped(shp,CDPNOD)->nvalue.cp))
1N/A {
1N/A if(cdpath=path_addpath(shp,(Pathcomp_t*)0,dp,PATH_CDPATH))
1N/A {
1N/A shp->cdpathlist = (void*)cdpath;
1N/A cdpath->shp = shp;
1N/A }
1N/A }
1N/A if(!oldpwd)
1N/A oldpwd = path_pwd(shp,1);
1N/A }
1N/A if(*dir=='.')
1N/A {
1N/A /* test for pathname . ./ .. or ../ */
1N/A if(*(dp=dir+1) == '.')
1N/A dp++;
1N/A if(*dp==0 || *dp=='/')
1N/A cdpath = 0;
1N/A }
1N/A rval = -1;
1N/A do
1N/A {
1N/A dp = cdpath?cdpath->name:"";
1N/A cdpath = path_nextcomp(shp,cdpath,dir,0);
1N/A#if _WINIX
1N/A if(*stakptr(PATH_OFFSET+1)==':' && isalpha(*stakptr(PATH_OFFSET)))
1N/A {
1N/A *stakptr(PATH_OFFSET+1) = *stakptr(PATH_OFFSET);
1N/A *stakptr(PATH_OFFSET)='/';
1N/A }
1N/A#endif /* _WINIX */
1N/A if(*stakptr(PATH_OFFSET)!='/')
1N/A
1N/A {
1N/A char *last=(char*)stakfreeze(1);
1N/A stakseek(PATH_OFFSET);
1N/A stakputs(oldpwd);
1N/A /* don't add '/' of oldpwd is / itself */
1N/A if(*oldpwd!='/' || oldpwd[1])
1N/A stakputc('/');
1N/A stakputs(last+PATH_OFFSET);
1N/A stakputc(0);
1N/A }
1N/A if(!flag)
1N/A {
1N/A register char *cp;
1N/A stakseek(PATH_MAX+PATH_OFFSET);
1N/A#if SHOPT_FS_3D
1N/A if(!(cp = pathcanon(stakptr(PATH_OFFSET),PATH_DOTDOT)))
1N/A continue;
1N/A /* eliminate trailing '/' */
1N/A while(*--cp == '/' && cp>stakptr(PATH_OFFSET))
1N/A *cp = 0;
1N/A#else
1N/A if(*(cp=stakptr(PATH_OFFSET))=='/')
1N/A if(!pathcanon(cp,PATH_DOTDOT))
1N/A continue;
1N/A#endif /* SHOPT_FS_3D */
1N/A }
1N/A if((rval=chdir(path_relative(shp,stakptr(PATH_OFFSET)))) >= 0)
1N/A goto success;
1N/A if(errno!=ENOENT && saverrno==0)
1N/A saverrno=errno;
1N/A }
1N/A while(cdpath);
1N/A if(rval<0 && *dir=='/' && *(path_relative(shp,stakptr(PATH_OFFSET)))!='/')
1N/A rval = chdir(dir);
1N/A /* use absolute chdir() if relative chdir() fails */
1N/A if(rval<0)
1N/A {
1N/A if(saverrno)
1N/A errno = saverrno;
1N/A errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
1N/A }
1N/Asuccess:
1N/A if(dir == nv_getval(opwdnod) || argc==2)
1N/A dp = dir; /* print out directory for cd - */
1N/A if(flag)
1N/A {
1N/A dir = stakptr(PATH_OFFSET);
1N/A if (!(dir=pathcanon(dir,PATH_PHYSICAL)))
1N/A {
1N/A dir = stakptr(PATH_OFFSET);
1N/A errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
1N/A }
1N/A stakseek(dir-stakptr(0));
1N/A }
1N/A dir = (char*)stakfreeze(1)+PATH_OFFSET;
1N/A if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/'))
1N/A sfputr(sfstdout,dir,'\n');
1N/A if(*dir != '/')
1N/A return(0);
1N/A nv_putval(opwdnod,oldpwd,NV_RDONLY);
1N/A if(oldpwd)
1N/A free(oldpwd);
1N/A flag = strlen(dir);
1N/A /* delete trailing '/' */
1N/A while(--flag>0 && dir[flag]=='/')
1N/A dir[flag] = 0;
1N/A nv_putval(pwdnod,dir,NV_RDONLY);
1N/A nv_onattr(pwdnod,NV_NOFREE|NV_EXPORT);
1N/A shp->pwd = pwdnod->nvalue.cp;
1N/A nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED);
1N/A path_newdir(shp,shp->pathlist);
1N/A path_newdir(shp,shp->cdpathlist);
1N/A return(0);
1N/A}
1N/A
1N/Aint b_pwd(int argc, char *argv[],void *extra)
1N/A{
1N/A register int n, flag = 0;
1N/A register char *cp;
1N/A#if SHOPT_FS_3D
1N/A register Shell_t *shp = ((Shbltin_t*)extra)->shp;
1N/A#else
1N/A NOT_USED(extra);
1N/A#endif
1N/A NOT_USED(argc);
1N/A while((n = optget(argv,sh_optpwd))) switch(n)
1N/A {
1N/A case 'L':
1N/A flag = 0;
1N/A break;
1N/A case 'P':
1N/A flag = 1;
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT,2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A if(error_info.errors)
1N/A errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
1N/A if(*(cp = path_pwd(shp,0)) != '/')
1N/A errormsg(SH_DICT,ERROR_system(1), e_pwd);
1N/A if(flag)
1N/A {
1N/A#if SHOPT_FS_3D
1N/A if(shp->gd->lim.fs3d && (flag = mount(e_dot,NIL(char*),FS3D_GET|FS3D_VIEW,0))>=0)
1N/A {
1N/A cp = (char*)stakseek(++flag+PATH_MAX);
1N/A mount(e_dot,cp,FS3D_GET|FS3D_VIEW|FS3D_SIZE(flag),0);
1N/A }
1N/A else
1N/A#endif /* SHOPT_FS_3D */
1N/A cp = strcpy(stakseek(strlen(cp)+PATH_MAX),cp);
1N/A pathcanon(cp,PATH_PHYSICAL);
1N/A }
1N/A sfputr(sfstdout,cp,'\n');
1N/A return(0);
1N/A}
1N/A