mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-09 23:00:07 +00:00
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>
|
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.
|
||||||
|
271
posix/wordexp.c
271
posix/wordexp.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user