#line 23 "cd.def"
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include "posixdir.h"
#include "posixstat.h"
#ifndef _MINIX
#include <sys/param.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "../flags.h"
#include "maxpath.h"
#include "common.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
extern int posixly_correct;
extern int array_needs_making;
extern char *bash_getcwd_errstr;
static int bindpwd __P((int));
static void setpwd __P((char *));
static char *resetpwd __P((char *));
static int change_to_directory __P((char *, int));
static char *cdspell __P((char *));
int cdspelling = 0;
int cdable_vars;
#line 88 "cd.def"
static void
setpwd (dirname)
char *dirname;
{
int old_anm;
SHELL_VAR *tvar;
old_anm = array_needs_making;
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
array_needs_making = 0;
}
}
static int
bindpwd (no_symlinks)
int no_symlinks;
{
char *dirname, *pwdvar;
int old_anm;
SHELL_VAR *tvar;
#define tcwd the_current_working_directory
dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("cd");
#undef tcwd
old_anm = array_needs_making;
pwdvar = get_string_value ("PWD");
tvar = bind_variable ("OLDPWD", pwdvar, 0);
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
array_needs_making = 0;
}
setpwd (dirname);
if (dirname && dirname != the_current_working_directory)
free (dirname);
return (EXECUTION_SUCCESS);
}
static char *
resetpwd (caller)
char *caller;
{
char *tdir;
FREE (the_current_working_directory);
the_current_working_directory = (char *)NULL;
tdir = get_working_directory (caller);
return (tdir);
}
#define LCD_DOVARS 0x001
#define LCD_DOSPELL 0x002
#define LCD_PRINTPATH 0x004
#define LCD_FREEDIRNAME 0x010
int
cd_builtin (list)
WORD_LIST *list;
{
char *dirname, *cdpath, *path, *temp;
int path_index, no_symlinks, opt, lflag;
#if defined (RESTRICTED_SHELL)
if (restricted)
{
sh_restricted ((char *)NULL);
return (EXECUTION_FAILURE);
}
#endif
no_symlinks = no_symbolic_links;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "LP")) != -1)
{
switch (opt)
{
case 'P':
no_symlinks = 1;
break;
case 'L':
no_symlinks = 0;
break;
default:
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
list = loptend;
lflag = (cdable_vars ? LCD_DOVARS : 0) |
((interactive && cdspelling) ? LCD_DOSPELL : 0);
if (list == 0)
{
dirname = get_string_value ("HOME");
if (dirname == 0)
{
builtin_error ("%s", _("HOME not set"));
return (EXECUTION_FAILURE);
}
lflag = 0;
}
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
{
dirname = get_string_value ("OLDPWD");
if (dirname == 0)
{
builtin_error ("%s", _("OLDPWD not set"));
return (EXECUTION_FAILURE);
}
#if 0
lflag = interactive ? LCD_PRINTPATH : 0;
#else
lflag = LCD_PRINTPATH;
#endif
}
else if (absolute_pathname (list->word->word))
dirname = list->word->word;
else if (cdpath = get_string_value ("CDPATH"))
{
dirname = list->word->word;
path_index = 0;
while (path = extract_colon_unit (cdpath, &path_index))
{
opt = path[0] != '\0';
temp = sh_makepath (path, dirname, MP_DOTILDE);
free (path);
if (change_to_directory (temp, no_symlinks))
{
if (opt && (path = no_symlinks ? temp : the_current_working_directory))
printf ("%s\n", path);
free (temp);
#if 0
return (bindpwd (posixly_correct || no_symlinks));
#else
return (bindpwd (no_symlinks));
#endif
}
else
free (temp);
}
if (posixly_correct && cdpath[0])
{
builtin_error ("%s: %s", dirname, strerror (ENOENT));
return (EXECUTION_FAILURE);
}
}
else
dirname = list->word->word;
if (change_to_directory (dirname, no_symlinks))
{
if (lflag & LCD_PRINTPATH)
printf ("%s\n", dirname);
return (bindpwd (no_symlinks));
}
if (lflag & LCD_DOVARS)
{
temp = get_string_value (dirname);
if (temp && change_to_directory (temp, no_symlinks))
{
printf ("%s\n", temp);
return (bindpwd (no_symlinks));
}
}
if (lflag & LCD_DOSPELL)
{
temp = cdspell (dirname);
if (temp && change_to_directory (temp, no_symlinks))
{
printf ("%s\n", temp);
return (bindpwd (no_symlinks));
}
else
FREE (temp);
}
builtin_error ("%s: %s", dirname, strerror (errno));
return (EXECUTION_FAILURE);
}
#line 324 "cd.def"
static int verbatim_pwd;
int
pwd_builtin (list)
WORD_LIST *list;
{
char *directory;
int opt, pflag;
verbatim_pwd = no_symbolic_links;
pflag = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "LP")) != -1)
{
switch (opt)
{
case 'P':
verbatim_pwd = pflag = 1;
break;
case 'L':
verbatim_pwd = 0;
break;
default:
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
list = loptend;
#define tcwd the_current_working_directory
directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("pwd");
if ((tcwd && directory == 0) ||
(posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
directory = resetpwd ("pwd");
#undef tcwd
if (directory)
{
printf ("%s\n", directory);
if (posixly_correct && pflag)
setpwd (directory);
if (directory != the_current_working_directory)
free (directory);
fflush (stdout);
if (ferror (stdout))
{
sh_wrerror ();
clearerr (stdout);
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
else
return (EXECUTION_FAILURE);
}
static int
change_to_directory (newdir, nolinks)
char *newdir;
int nolinks;
{
char *t, *tdir;
int err, canon_failed, r, ndlen, dlen;
tdir = (char *)NULL;
if (the_current_working_directory == 0)
{
t = get_working_directory ("chdir");
FREE (t);
}
t = make_absolute (newdir, the_current_working_directory);
tdir = nolinks ? sh_physpath (t, 0)
: sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
ndlen = strlen (newdir);
dlen = strlen (t);
canon_failed = 0;
if (tdir && *tdir)
free (t);
else
{
FREE (tdir);
tdir = t;
canon_failed = 1;
}
if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
{
#if defined ENAMETOOLONG
if (errno != ENOENT && errno != ENAMETOOLONG)
#else
if (errno != ENOENT)
#endif
errno = ENOTDIR;
free (tdir);
return (0);
}
if (chdir (nolinks ? newdir : tdir) == 0)
{
if (canon_failed)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
}
else
set_working_directory (tdir);
free (tdir);
return (1);
}
if (nolinks)
{
free (tdir);
return (0);
}
err = errno;
if (chdir (newdir) == 0)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
else
free (t);
r = 1;
}
else
{
errno = err;
r = 0;
}
free (tdir);
return r;
}
static char *
cdspell (dirname)
char *dirname;
{
int n;
char *guess;
n = (strlen (dirname) * 3 + 1) / 2 + 1;
guess = (char *)xmalloc (n);
switch (spname (dirname, guess))
{
case -1:
default:
free (guess);
return (char *)NULL;
case 0:
case 1:
return guess;
}
}