#include "config.h"
#include "bashtypes.h"
#ifndef _MINIX
# include <sys/param.h>
#endif
#include "posixstat.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "filecntl.h"
#include "bashansi.h"
#include <stdio.h>
#include "chartypes.h"
#include <errno.h>
#include "bashintl.h"
#include "shell.h"
#include "test.h"
#include <tilde/tilde.h>
#if !defined (errno)
extern int errno;
#endif
extern int expand_aliases;
extern int interactive_comments;
extern int check_hashed_filenames;
extern int source_uses_path;
extern int source_searches_cwd;
static char *bash_special_tilde_expansions __P((char *));
static int unquoted_tilde_word __P((const char *));
static void initialize_group_array __P((void));
char *bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
void
posix_initialize (on)
int on;
{
if (on != 0)
{
interactive_comments = source_uses_path = expand_aliases = 1;
}
if (on == 0)
{
source_searches_cwd = 1;
expand_aliases = interactive_shell;
}
}
#if defined (RLIMTYPE)
RLIMTYPE
string_to_rlimtype (s)
char *s;
{
RLIMTYPE ret;
int neg;
ret = 0;
neg = 0;
while (s && *s && whitespace (*s))
s++;
if (*s == '-' || *s == '+')
{
neg = *s == '-';
s++;
}
for ( ; s && *s && DIGIT (*s); s++)
ret = (ret * 10) + TODIGIT (*s);
return (neg ? -ret : ret);
}
void
print_rlimtype (n, addnl)
RLIMTYPE n;
int addnl;
{
char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
p = s + sizeof(s);
*--p = '\0';
if (n < 0)
{
do
*--p = '0' - n % 10;
while ((n /= 10) != 0);
*--p = '-';
}
else
{
do
*--p = '0' + n % 10;
while ((n /= 10) != 0);
}
printf ("%s%s", p, addnl ? "\n" : "");
}
#endif
int
all_digits (string)
char *string;
{
register char *s;
for (s = string; *s; s++)
if (DIGIT (*s) == 0)
return (0);
return (1);
}
int
legal_number (string, result)
char *string;
intmax_t *result;
{
intmax_t value;
char *ep;
if (result)
*result = 0;
errno = 0;
value = strtoimax (string, &ep, 10);
if (errno)
return 0;
while (whitespace (*ep))
ep++;
if (string && *string && *ep == '\0')
{
if (result)
*result = value;
return 1;
}
return (0);
}
int
legal_identifier (name)
char *name;
{
register char *s;
unsigned char c;
if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
return (0);
for (s = name + 1; (c = *s) != 0; s++)
{
if (legal_variable_char (c) == 0)
return (0);
}
return (1);
}
int
check_identifier (word, check_word)
WORD_DESC *word;
int check_word;
{
if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
{
internal_error (_("`%s': not a valid identifier"), word->word);
return (0);
}
else if (check_word && legal_identifier (word->word) == 0)
{
internal_error (_("`%s': not a valid identifier"), word->word);
return (0);
}
else
return (1);
}
int
legal_alias_name (string, flags)
char *string;
int flags;
{
register char *s;
for (s = string; *s; s++)
if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/'))
return 0;
return 1;
}
int
assignment (string, flags)
const char *string;
int flags;
{
register unsigned char c;
register int newi, indx;
c = string[indx = 0];
#if defined (ARRAY_VARS)
if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '['))
#else
if (legal_variable_starter (c) == 0)
#endif
return (0);
while (c = string[indx])
{
if (c == '=')
return (indx);
#if defined (ARRAY_VARS)
if (c == '[')
{
newi = skipsubscript (string, indx);
if (string[newi++] != ']')
return (0);
if (string[newi] == '+' && string[newi+1] == '=')
return (newi + 1);
return ((string[newi] == '=') ? newi : 0);
}
#endif
if (c == '+' && string[indx+1] == '=')
return (indx + 1);
if (legal_variable_char (c) == 0)
return (0);
indx++;
}
return (0);
}
#if !defined (O_NDELAY)
# if defined (FNDELAY)
# define O_NDELAY FNDELAY
# endif
#endif
int
sh_unset_nodelay_mode (fd)
int fd;
{
int flags, bflags;
if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
return -1;
bflags = 0;
#ifdef O_NONBLOCK
bflags |= O_NONBLOCK;
#endif
#ifdef O_NDELAY
bflags |= O_NDELAY;
#endif
if (flags & bflags)
{
flags &= ~bflags;
return (fcntl (fd, F_SETFL, flags));
}
return 0;
}
int
sh_validfd (fd)
int fd;
{
return (fcntl (fd, F_GETFD, 0) >= 0);
}
#if defined (__BEOS__)
# undef O_NONBLOCK
# define O_NONBLOCK 0
#endif
void
check_dev_tty ()
{
int tty_fd;
char *tty;
tty_fd = open ("/dev/tty", O_RDWR|O_NONBLOCK);
if (tty_fd < 0)
{
tty = (char *)ttyname (fileno (stdin));
if (tty == 0)
return;
tty_fd = open (tty, O_RDWR|O_NONBLOCK);
}
close (tty_fd);
}
int
same_file (path1, path2, stp1, stp2)
char *path1, *path2;
struct stat *stp1, *stp2;
{
struct stat st1, st2;
if (stp1 == NULL)
{
if (stat (path1, &st1) != 0)
return (0);
stp1 = &st1;
}
if (stp2 == NULL)
{
if (stat (path2, &st2) != 0)
return (0);
stp2 = &st2;
}
return ((stp1->st_dev == stp2->st_dev) && (stp1->st_ino == stp2->st_ino));
}
int
move_to_high_fd (fd, check_new, maxfd)
int fd, check_new, maxfd;
{
int script_fd, nfds, ignore;
if (maxfd < 20)
{
nfds = getdtablesize ();
if (nfds <= 0)
nfds = 20;
if (nfds > HIGH_FD_MAX)
nfds = HIGH_FD_MAX;
}
else
nfds = maxfd;
for (nfds--; check_new && nfds > 3; nfds--)
if (fcntl (nfds, F_GETFD, &ignore) == -1)
break;
if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
{
if (check_new == 0 || fd != fileno (stderr))
close (fd);
return (script_fd);
}
return (fd);
}
int
check_binary_file (sample, sample_len)
char *sample;
int sample_len;
{
register int i;
unsigned char c;
for (i = 0; i < sample_len; i++)
{
c = sample[i];
if (c == '\n')
return (0);
#if 0
if (ISSPACE (c) == 0 && ISPRINT (c) == 0)
#else
if (c == '\0')
#endif
return (1);
}
return (0);
}
int
file_isdir (fn)
char *fn;
{
struct stat sb;
return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
}
int
file_iswdir (fn)
char *fn;
{
return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
}
int
absolute_pathname (string)
const char *string;
{
if (string == 0 || *string == '\0')
return (0);
if (ABSPATH(string))
return (1);
if (string[0] == '.' && PATHSEP(string[1]))
return (1);
if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2]))
return (1);
return (0);
}
int
absolute_program (string)
const char *string;
{
return ((char *)xstrchr (string, '/') != (char *)NULL);
}
char *
make_absolute (string, dot_path)
char *string, *dot_path;
{
char *result;
if (dot_path == 0 || ABSPATH(string))
#ifdef __CYGWIN__
{
char pathbuf[PATH_MAX + 1];
cygwin_conv_to_full_posix_path (string, pathbuf);
result = savestring (pathbuf);
}
#else
result = savestring (string);
#endif
else
result = sh_makepath (dot_path, string, 0);
return (result);
}
char *
base_pathname (string)
char *string;
{
char *p;
#if 0
if (absolute_pathname (string) == 0)
return (string);
#endif
if (string[0] == '/' && string[1] == 0)
return (string);
p = (char *)strrchr (string, '/');
return (p ? ++p : string);
}
char *
full_pathname (file)
char *file;
{
char *ret;
file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
if (ABSPATH(file))
return (file);
ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
free (file);
return (ret);
}
static char tdir[PATH_MAX];
char *
polite_directory_format (name)
char *name;
{
char *home;
int l;
home = get_string_value ("HOME");
l = home ? strlen (home) : 0;
if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
{
strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
tdir[0] = '~';
tdir[sizeof(tdir) - 1] = '\0';
return (tdir);
}
else
return (name);
}
char *
extract_colon_unit (string, p_index)
char *string;
int *p_index;
{
int i, start, len;
char *value;
if (string == 0)
return (string);
len = strlen (string);
if (*p_index >= len)
return ((char *)NULL);
i = *p_index;
if (i && string[i] == ':')
i++;
for (start = i; string[i] && string[i] != ':'; i++)
;
*p_index = i;
if (i == start)
{
if (string[i])
(*p_index)++;
value = (char *)xmalloc (1);
value[0] = '\0';
}
else
value = substring (string, start, i);
return (value);
}
#if defined (PUSHD_AND_POPD)
extern char *get_dirstack_from_string __P((char *));
#endif
static char **bash_tilde_prefixes;
static char **bash_tilde_prefixes2;
static char **bash_tilde_suffixes;
static char **bash_tilde_suffixes2;
static char *
bash_special_tilde_expansions (text)
char *text;
{
char *result;
result = (char *)NULL;
if (text[0] == '+' && text[1] == '\0')
result = get_string_value ("PWD");
else if (text[0] == '-' && text[1] == '\0')
result = get_string_value ("OLDPWD");
#if defined (PUSHD_AND_POPD)
else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
result = get_dirstack_from_string (text);
#endif
return (result ? savestring (result) : (char *)NULL);
}
void
tilde_initialize ()
{
static int times_called = 0;
tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
if (times_called++ == 0)
{
bash_tilde_prefixes = strvec_create (3);
bash_tilde_prefixes[0] = "=~";
bash_tilde_prefixes[1] = ":~";
bash_tilde_prefixes[2] = (char *)NULL;
bash_tilde_prefixes2 = strvec_create (2);
bash_tilde_prefixes2[0] = ":~";
bash_tilde_prefixes2[1] = (char *)NULL;
tilde_additional_prefixes = bash_tilde_prefixes;
bash_tilde_suffixes = strvec_create (3);
bash_tilde_suffixes[0] = ":";
bash_tilde_suffixes[1] = "=~";
bash_tilde_suffixes[2] = (char *)NULL;
tilde_additional_suffixes = bash_tilde_suffixes;
bash_tilde_suffixes2 = strvec_create (2);
bash_tilde_suffixes2[0] = ":";
bash_tilde_suffixes2[1] = (char *)NULL;
}
}
#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
static int
unquoted_tilde_word (s)
const char *s;
{
const char *r;
for (r = s; TILDE_END(*r) == 0; r++)
{
switch (*r)
{
case '\\':
case '\'':
case '"':
return 0;
}
}
return 1;
}
char *
bash_tilde_find_word (s, flags, lenp)
const char *s;
int flags, *lenp;
{
const char *r;
char *ret;
int l;
for (r = s; *r && *r != '/'; r++)
{
if (*r == '\\' || *r == '\'' || *r == '"')
{
ret = savestring (s);
if (lenp)
*lenp = 0;
return ret;
}
else if (flags && *r == ':')
break;
}
l = r - s;
ret = xmalloc (l + 1);
strncpy (ret, s, l);
ret[l] = '\0';
if (lenp)
*lenp = l;
return ret;
}
char *
bash_tilde_expand (s, assign_p)
const char *s;
int assign_p;
{
int old_immed, r;
char *ret;
old_immed = interrupt_immediately;
interrupt_immediately = 1;
tilde_additional_prefixes = assign_p == 0 ? (char **)0
: (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes);
if (assign_p == 2)
tilde_additional_suffixes = bash_tilde_suffixes2;
r = (*s == '~') ? unquoted_tilde_word (s) : 1;
ret = r ? tilde_expand (s) : savestring (s);
interrupt_immediately = old_immed;
return (ret);
}
static int ngroups, maxgroups;
static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
#if !defined (NOGROUP)
# define NOGROUP (gid_t) -1
#endif
static void
initialize_group_array ()
{
register int i;
if (maxgroups == 0)
maxgroups = getmaxgroups ();
ngroups = 0;
group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
#if defined (HAVE_GETGROUPS)
ngroups = getgroups (maxgroups, group_array);
#endif
if (ngroups == 0)
{
group_array[0] = current_user.gid;
ngroups = 1;
}
for (i = 0; i < ngroups; i++)
if (current_user.gid == (gid_t)group_array[i])
break;
if (i == ngroups && ngroups < maxgroups)
{
for (i = ngroups; i > 0; i--)
group_array[i] = group_array[i - 1];
group_array[0] = current_user.gid;
ngroups++;
}
if (group_array[0] != current_user.gid)
{
for (i = 0; i < ngroups; i++)
if (group_array[i] == current_user.gid)
break;
if (i < ngroups)
{
group_array[i] = group_array[0];
group_array[0] = current_user.gid;
}
}
}
int
#if defined (__STDC__) || defined ( _MINIX)
group_member (gid_t gid)
#else
group_member (gid)
gid_t gid;
#endif
{
#if defined (HAVE_GETGROUPS)
register int i;
#endif
if (gid == current_user.gid || gid == current_user.egid)
return (1);
#if defined (HAVE_GETGROUPS)
if (ngroups == 0)
initialize_group_array ();
if (ngroups <= 0)
return (0);
for (i = 0; i < ngroups; i++)
if (gid == (gid_t)group_array[i])
return (1);
#endif
return (0);
}
char **
get_group_list (ngp)
int *ngp;
{
static char **group_vector = (char **)NULL;
register int i;
if (group_vector)
{
if (ngp)
*ngp = ngroups;
return group_vector;
}
if (ngroups == 0)
initialize_group_array ();
if (ngroups <= 0)
{
if (ngp)
*ngp = 0;
return (char **)NULL;
}
group_vector = strvec_create (ngroups);
for (i = 0; i < ngroups; i++)
group_vector[i] = itos (group_array[i]);
if (ngp)
*ngp = ngroups;
return group_vector;
}
int *
get_group_array (ngp)
int *ngp;
{
int i;
static int *group_iarray = (int *)NULL;
if (group_iarray)
{
if (ngp)
*ngp = ngroups;
return (group_iarray);
}
if (ngroups == 0)
initialize_group_array ();
if (ngroups <= 0)
{
if (ngp)
*ngp = 0;
return (int *)NULL;
}
group_iarray = (int *)xmalloc (ngroups * sizeof (int));
for (i = 0; i < ngroups; i++)
group_iarray[i] = (int)group_array[i];
if (ngp)
*ngp = ngroups;
return group_iarray;
}