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