* posix/wordexp.c: Use we_offs everywhere if WRDE_DOOFS.  Expand ~
	correctly.  Detect syntax errors in command substitutions.  Delete
	trailing newlines correctly.  Don't split fields in command
	substitution situations.  Restore old structure in case of an
	error.  Handle WRDE_APPEND correctly.
	Patch by Geoff Clare <gwc@unisoft.com>.
This commit is contained in:
Ulrich Drepper 2000-02-24 07:36:39 +00:00
parent 5866b13180
commit 05d5dedc62
2 changed files with 186 additions and 92 deletions

View File

@ -1,5 +1,12 @@
2000-02-23 Ulrich Drepper <drepper@redhat.com> 2000-02-23 Ulrich Drepper <drepper@redhat.com>
* posix/wordexp.c: Use we_offs everywhere if WRDE_DOOFS. Expand ~
correctly. Detect syntax errors in command substitutions. Delete
trailing newlines correctly. Don't split fields in command
substitution situations. Restore old structure in case of an
error. Handle WRDE_APPEND correctly.
Patch by Geoff Clare <gwc@unisoft.com>.
* locale/programs/ld-ctype.c (allocate_arrays): Make sure the end * locale/programs/ld-ctype.c (allocate_arrays): Make sure the end
of width table is 4-byte aligned. of width table is 4-byte aligned.
(ctype_output): Write out the entire width array. (ctype_output): Write out the entire width array.

View File

@ -174,8 +174,8 @@ w_addword (wordexp_t *pwordexp, char *word)
if (new_wordv != NULL) if (new_wordv != NULL)
{ {
pwordexp->we_wordv = new_wordv; pwordexp->we_wordv = new_wordv;
pwordexp->we_wordv[pwordexp->we_wordc++] = word; pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word;
pwordexp->we_wordv[pwordexp->we_wordc] = NULL; pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL;
return 0; return 0;
} }
@ -299,35 +299,51 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
uid_t uid; uid_t uid;
struct passwd pwd, *tpwd; struct passwd pwd, *tpwd;
int buflen = 1000; int buflen = 1000;
char* buffer = __alloca (buflen); char* home;
char* buffer;
int result; int result;
uid = __getuid (); /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
results are unspecified. We do a lookup on the uid if
HOME is unset. */
while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0 home = getenv ("HOME");
&& errno == ERANGE) if (home != NULL)
{ {
buflen += 1000; *word = w_addstr (*word, word_length, max_length, home);
buffer = __alloca (buflen);
}
if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
{
*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
if (*word == NULL) if (*word == NULL)
return WRDE_NOSPACE; return WRDE_NOSPACE;
} }
else else
{ {
*word = w_addchar (*word, word_length, max_length, '~'); uid = __getuid ();
if (*word == NULL) buffer = __alloca (buflen);
return WRDE_NOSPACE;
while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
&& errno == ERANGE)
{
buflen += 1000;
buffer = __alloca (buflen);
}
if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
{
*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
if (*word == NULL)
return WRDE_NOSPACE;
}
else
{
*word = w_addchar (*word, word_length, max_length, '~');
if (*word == NULL)
return WRDE_NOSPACE;
}
} }
} }
else else
{ {
/* Look up user name in database to get home directory */ /* Look up user name in database to get home directory */
char *user = __strndup (&words[1 + *offset], i - *offset); char *user = __strndup (&words[1 + *offset], i - (1 + *offset));
struct passwd pwd, *tpwd; struct passwd pwd, *tpwd;
int buflen = 1000; int buflen = 1000;
char* buffer = __alloca (buflen); char* buffer = __alloca (buflen);
@ -806,6 +822,44 @@ parse_arith (char **word, size_t *word_length, size_t *max_length,
return WRDE_SYNTAX; return WRDE_SYNTAX;
} }
/* Function called by child process in exec_comm() */
static void
internal_function
exec_comm_child (char *comm, int *fildes, int showerr, int noexec)
{
const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
/* Execute the command, or just check syntax? */
if (noexec)
args[1] = "-nc";
/* Redirect output. */
__dup2 (fildes[1], 1);
__close (fildes[1]);
/* Redirect stderr to /dev/null if we have to. */
if (showerr == 0)
{
int fd;
__close (2);
fd = __open (_PATH_DEVNULL, O_WRONLY);
if (fd >= 0 && fd != 2)
{
__dup2 (fd, 2);
__close (fd);
}
}
/* Make sure the subshell doesn't field-split on our behalf. */
unsetenv ("IFS");
__close (fildes[0]);
__execve (_PATH_BSHELL, (char *const *) args, __environ);
/* Bad. What now? */
abort ();
}
/* Function to execute a command and retrieve the results */ /* Function to execute a command and retrieve the results */
/* pwordexp contains NULL if field-splitting is forbidden */ /* pwordexp contains NULL if field-splitting is forbidden */
static int static int
@ -818,6 +872,8 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
int bufsize = 128; int bufsize = 128;
int buflen; int buflen;
int i; int i;
int status = 0;
size_t maxnewlines = 0;
char *buffer; char *buffer;
pid_t pid; pid_t pid;
@ -838,36 +894,7 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
} }
if (pid == 0) if (pid == 0)
{ exec_comm_child(comm, fildes, (flags & WRDE_SHOWERR), 0);
/* Child */
const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
/* Redirect output. */
__dup2 (fildes[1], 1);
__close (fildes[1]);
/* Redirect stderr to /dev/null if we have to. */
if ((flags & WRDE_SHOWERR) == 0)
{
int fd;
__close (2);
fd = __open (_PATH_DEVNULL, O_WRONLY);
if (fd >= 0 && fd != 2)
{
__dup2 (fd, 2);
__close (fd);
}
}
/* Make sure the subshell doesn't field-split on our behalf. */
unsetenv ("IFS");
__close (fildes[0]);
__execve (_PATH_BSHELL, (char *const *) args, __environ);
/* Bad. What now? */
abort ();
}
/* Parent */ /* Parent */
@ -875,18 +902,20 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
buffer = __alloca (bufsize); buffer = __alloca (bufsize);
if (!pwordexp) if (!pwordexp)
{ /* Quoted - no field splitting */ /* Quoted - no field splitting */
{
while (1) while (1)
{ {
if ((buflen = __read (fildes[0], buffer, bufsize)) < 1) if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
{ {
if (__waitpid (pid, NULL, WNOHANG) == 0) if (__waitpid (pid, &status, WNOHANG) == 0)
continue; continue;
if ((buflen = __read (fildes[0], buffer, bufsize)) < 1) if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
break; break;
} }
maxnewlines += buflen;
*word = w_addmem (*word, word_length, max_length, buffer, buflen); *word = w_addmem (*word, word_length, max_length, buffer, buflen);
if (*word == NULL) if (*word == NULL)
goto no_space; goto no_space;
@ -900,15 +929,16 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
* 0 when searching for first character in a field not IFS white space * 0 when searching for first character in a field not IFS white space
* 1 when copying the text of a field * 1 when copying the text of a field
* 2 when searching for possible non-whitespace IFS * 2 when searching for possible non-whitespace IFS
* 3 when searching for non-newline after copying field
*/ */
while (1) while (1)
{ {
if ((buflen = __read (fildes[0], buffer, bufsize)) < 1) if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
{ {
if (__waitpid (pid, NULL, WNOHANG) == 0) if (__waitpid (pid, &status, WNOHANG) == 0)
continue; continue;
if ((__read (fildes[0], buffer, bufsize)) < 1) if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
break; break;
} }
@ -938,29 +968,64 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
} }
else else
{ {
/* Current character is IFS white space */ if (buffer[i] == '\n')
{
/* Current character is (IFS) newline */
/* If not copying a field, ignore it */ /* If copying a field, this is the end of it,
if (copying != 1) but maybe all that's left is trailing newlines.
continue; So start searching for a non-newline. */
if (copying == 1)
copying = 3;
/* End of field (search for non-ws IFS afterwards) */ continue;
copying = 2; }
else
{
/* Current character is IFS white space, but
not a newline */
/* If not either copying a field or searching
for non-newline after a field, ignore it */
if (copying != 1 && copying != 3)
continue;
/* End of field (search for non-ws IFS afterwards) */
copying = 2;
}
} }
/* First IFS white space, or IFS non-whitespace. /* First IFS white space (non-newline), or IFS non-whitespace.
* Delimit the field. Nulls are converted by w_addword. */ * Delimit the field. Nulls are converted by w_addword. */
if (w_addword (pwordexp, *word) == WRDE_NOSPACE) if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
goto no_space; goto no_space;
*word = w_newword (word_length, max_length); *word = w_newword (word_length, max_length);
maxnewlines = 0;
/* fall back round the loop.. */ /* fall back round the loop.. */
} }
else else
{ {
/* Not IFS character */ /* Not IFS character */
if (copying == 3)
{
/* Nothing but (IFS) newlines since the last field,
so delimit it here before starting new word */
if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
goto no_space;
*word = w_newword (word_length, max_length);
}
copying = 1; copying = 1;
if (buffer[i] == '\n') /* happens if newline not in IFS */
maxnewlines++;
else
maxnewlines = 0;
*word = w_addchar (*word, word_length, max_length, *word = w_addchar (*word, word_length, max_length,
buffer[i]); buffer[i]);
if (*word == NULL) if (*word == NULL)
@ -970,8 +1035,11 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
} }
} }
/* Bash chops off trailing newlines, which seems sensible. */ /* Chop off trailing newlines (required by POSIX.2) */
while (*word_length > 0 && (*word)[*word_length - 1] == '\n') /* Ensure we don't go back further than the beginning of the
substitution (i.e. remove maxnewlines bytes at most) */
while (maxnewlines-- != 0 &&
*word_length > 0 && (*word)[*word_length - 1] == '\n')
{ {
(*word)[--*word_length] = '\0'; (*word)[--*word_length] = '\0';
@ -986,6 +1054,26 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
} }
__close (fildes[0]); __close (fildes[0]);
/* Check for syntax error (re-execute but with "-n" flag) */
if (buflen < 1 && status != 0)
{
if ((pid = __fork ()) < 0)
{
/* Bad */
return WRDE_NOSPACE;
}
if (pid == 0)
{
fildes[0] = fildes[1] = -1;
exec_comm_child(comm, fildes, 0, 1);
}
if (__waitpid (pid, &status, 0) == pid && status != 0)
return WRDE_SYNTAX;
}
return 0; return 0;
no_space: no_space:
@ -2109,7 +2197,6 @@ wordfree (wordexp_t *pwordexp)
int int
wordexp (const char *words, wordexp_t *pwordexp, int flags) wordexp (const char *words, wordexp_t *pwordexp, int flags)
{ {
size_t wordv_offset;
size_t words_offset; size_t words_offset;
size_t word_length; size_t word_length;
size_t max_length; size_t max_length;
@ -2117,41 +2204,40 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
int error; int error;
char *ifs; char *ifs;
char ifs_white[4]; char ifs_white[4];
char **old_wordv = pwordexp->we_wordv; wordexp_t old_word = *pwordexp;
size_t old_wordc = (flags & WRDE_REUSE) ? pwordexp->we_wordc : 0;
if (flags & WRDE_REUSE) if (flags & WRDE_REUSE)
{ {
/* Minimal implementation of WRDE_REUSE for now */ /* Minimal implementation of WRDE_REUSE for now */
wordfree (pwordexp); wordfree (pwordexp);
old_wordv = NULL; old_word.we_wordv = NULL;
}
if (flags & WRDE_DOOFFS)
{
pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
if (pwordexp->we_wordv == NULL)
{
error = WRDE_NOSPACE;
goto do_error;
}
}
else
{
pwordexp->we_wordv = calloc (1, sizeof (char *));
if (pwordexp->we_wordv == NULL)
{
error = WRDE_NOSPACE;
goto do_error;
}
pwordexp->we_offs = 0;
} }
if ((flags & WRDE_APPEND) == 0) if ((flags & WRDE_APPEND) == 0)
pwordexp->we_wordc = 0; {
pwordexp->we_wordc = 0;
wordv_offset = pwordexp->we_offs + pwordexp->we_wordc; if (flags & WRDE_DOOFFS)
{
pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
if (pwordexp->we_wordv == NULL)
{
error = WRDE_NOSPACE;
goto do_error;
}
}
else
{
pwordexp->we_wordv = calloc (1, sizeof (char *));
if (pwordexp->we_wordv == NULL)
{
error = WRDE_NOSPACE;
goto do_error;
}
pwordexp->we_offs = 0;
}
}
/* Find out what the field separators are. /* Find out what the field separators are.
* There are two types: whitespace and non-whitespace. * There are two types: whitespace and non-whitespace.
@ -2333,7 +2419,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
do_error: do_error:
/* Error: /* Error:
* free memory used (unless error is WRDE_NOSPACE), and * free memory used (unless error is WRDE_NOSPACE), and
* set we_wordc and wd_wordv back to what they were. * set pwordexp members back to what they were.
*/ */
if (word != NULL) if (word != NULL)
@ -2342,8 +2428,9 @@ do_error:
if (error == WRDE_NOSPACE) if (error == WRDE_NOSPACE)
return WRDE_NOSPACE; return WRDE_NOSPACE;
wordfree (pwordexp); if ((flags & WRDE_APPEND) == 0)
pwordexp->we_wordv = old_wordv; wordfree (pwordexp);
pwordexp->we_wordc = old_wordc;
*pwordexp = old_word;
return error; return error;
} }