Update.
* 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:
parent
5866b13180
commit
05d5dedc62
@ -1,5 +1,12 @@
|
||||
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
|
||||
of width table is 4-byte aligned.
|
||||
(ctype_output): Write out the entire width array.
|
||||
|
201
posix/wordexp.c
201
posix/wordexp.c
@ -174,8 +174,8 @@ w_addword (wordexp_t *pwordexp, char *word)
|
||||
if (new_wordv != NULL)
|
||||
{
|
||||
pwordexp->we_wordv = new_wordv;
|
||||
pwordexp->we_wordv[pwordexp->we_wordc++] = word;
|
||||
pwordexp->we_wordv[pwordexp->we_wordc] = NULL;
|
||||
pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word;
|
||||
pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -299,10 +299,25 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
|
||||
uid_t uid;
|
||||
struct passwd pwd, *tpwd;
|
||||
int buflen = 1000;
|
||||
char* buffer = __alloca (buflen);
|
||||
char* home;
|
||||
char* buffer;
|
||||
int result;
|
||||
|
||||
/* 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. */
|
||||
|
||||
home = getenv ("HOME");
|
||||
if (home != NULL)
|
||||
{
|
||||
*word = w_addstr (*word, word_length, max_length, home);
|
||||
if (*word == NULL)
|
||||
return WRDE_NOSPACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uid = __getuid ();
|
||||
buffer = __alloca (buflen);
|
||||
|
||||
while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
|
||||
&& errno == ERANGE)
|
||||
@ -324,10 +339,11 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
|
||||
return WRDE_NOSPACE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
int buflen = 1000;
|
||||
char* buffer = __alloca (buflen);
|
||||
@ -806,6 +822,44 @@ parse_arith (char **word, size_t *word_length, size_t *max_length,
|
||||
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 */
|
||||
/* pwordexp contains NULL if field-splitting is forbidden */
|
||||
static int
|
||||
@ -818,6 +872,8 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
||||
int bufsize = 128;
|
||||
int buflen;
|
||||
int i;
|
||||
int status = 0;
|
||||
size_t maxnewlines = 0;
|
||||
char *buffer;
|
||||
pid_t pid;
|
||||
|
||||
@ -838,36 +894,7 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
||||
}
|
||||
|
||||
if (pid == 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 ();
|
||||
}
|
||||
exec_comm_child(comm, fildes, (flags & WRDE_SHOWERR), 0);
|
||||
|
||||
/* Parent */
|
||||
|
||||
@ -875,18 +902,20 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
||||
buffer = __alloca (bufsize);
|
||||
|
||||
if (!pwordexp)
|
||||
{ /* Quoted - no field splitting */
|
||||
|
||||
/* Quoted - no field splitting */
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
|
||||
{
|
||||
if (__waitpid (pid, NULL, WNOHANG) == 0)
|
||||
if (__waitpid (pid, &status, WNOHANG) == 0)
|
||||
continue;
|
||||
if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
|
||||
break;
|
||||
}
|
||||
|
||||
maxnewlines += buflen;
|
||||
|
||||
*word = w_addmem (*word, word_length, max_length, buffer, buflen);
|
||||
if (*word == NULL)
|
||||
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
|
||||
* 1 when copying the text of a field
|
||||
* 2 when searching for possible non-whitespace IFS
|
||||
* 3 when searching for non-newline after copying field
|
||||
*/
|
||||
|
||||
while (1)
|
||||
{
|
||||
if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
|
||||
{
|
||||
if (__waitpid (pid, NULL, WNOHANG) == 0)
|
||||
if (__waitpid (pid, &status, WNOHANG) == 0)
|
||||
continue;
|
||||
if ((__read (fildes[0], buffer, bufsize)) < 1)
|
||||
if ((buflen = __read (fildes[0], buffer, bufsize)) < 1)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -938,29 +968,64 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
||||
}
|
||||
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 != 1)
|
||||
/* If copying a field, this is the end of it,
|
||||
but maybe all that's left is trailing newlines.
|
||||
So start searching for a non-newline. */
|
||||
if (copying == 1)
|
||||
copying = 3;
|
||||
|
||||
continue;
|
||||
}
|
||||
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. */
|
||||
if (w_addword (pwordexp, *word) == WRDE_NOSPACE)
|
||||
goto no_space;
|
||||
|
||||
*word = w_newword (word_length, max_length);
|
||||
|
||||
maxnewlines = 0;
|
||||
/* fall back round the loop.. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
|
||||
if (buffer[i] == '\n') /* happens if newline not in IFS */
|
||||
maxnewlines++;
|
||||
else
|
||||
maxnewlines = 0;
|
||||
|
||||
*word = w_addchar (*word, word_length, max_length,
|
||||
buffer[i]);
|
||||
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. */
|
||||
while (*word_length > 0 && (*word)[*word_length - 1] == '\n')
|
||||
/* Chop off trailing newlines (required by POSIX.2) */
|
||||
/* 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';
|
||||
|
||||
@ -986,6 +1054,26 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
|
||||
}
|
||||
|
||||
__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;
|
||||
|
||||
no_space:
|
||||
@ -2109,7 +2197,6 @@ wordfree (wordexp_t *pwordexp)
|
||||
int
|
||||
wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
{
|
||||
size_t wordv_offset;
|
||||
size_t words_offset;
|
||||
size_t word_length;
|
||||
size_t max_length;
|
||||
@ -2117,16 +2204,19 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
int error;
|
||||
char *ifs;
|
||||
char ifs_white[4];
|
||||
char **old_wordv = pwordexp->we_wordv;
|
||||
size_t old_wordc = (flags & WRDE_REUSE) ? pwordexp->we_wordc : 0;
|
||||
wordexp_t old_word = *pwordexp;
|
||||
|
||||
if (flags & WRDE_REUSE)
|
||||
{
|
||||
/* Minimal implementation of WRDE_REUSE for now */
|
||||
wordfree (pwordexp);
|
||||
old_wordv = NULL;
|
||||
old_word.we_wordv = NULL;
|
||||
}
|
||||
|
||||
if ((flags & WRDE_APPEND) == 0)
|
||||
{
|
||||
pwordexp->we_wordc = 0;
|
||||
|
||||
if (flags & WRDE_DOOFFS)
|
||||
{
|
||||
pwordexp->we_wordv = calloc (1 + pwordexp->we_offs, sizeof (char *));
|
||||
@ -2147,11 +2237,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
|
||||
pwordexp->we_offs = 0;
|
||||
}
|
||||
|
||||
if ((flags & WRDE_APPEND) == 0)
|
||||
pwordexp->we_wordc = 0;
|
||||
|
||||
wordv_offset = pwordexp->we_offs + pwordexp->we_wordc;
|
||||
}
|
||||
|
||||
/* Find out what the field separators are.
|
||||
* There are two types: whitespace and non-whitespace.
|
||||
@ -2333,7 +2419,7 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
|
||||
do_error:
|
||||
/* Error:
|
||||
* 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)
|
||||
@ -2342,8 +2428,9 @@ do_error:
|
||||
if (error == WRDE_NOSPACE)
|
||||
return WRDE_NOSPACE;
|
||||
|
||||
if ((flags & WRDE_APPEND) == 0)
|
||||
wordfree (pwordexp);
|
||||
pwordexp->we_wordv = old_wordv;
|
||||
pwordexp->we_wordc = old_wordc;
|
||||
|
||||
*pwordexp = old_word;
|
||||
return error;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user