Add wordexp(3). The wordexp function performs shell-style word expansions.
This implementation is wrapper around the undocumented wordexp sh(1) built-in command. From FreeBSD. Provided in PR lib/26123. Approved by kleink@.
This commit is contained in:
parent
cf788c3115
commit
2f8bbc118e
@ -1,4 +1,4 @@
|
||||
# $NetBSD: mi,v 1.713 2004/07/10 13:49:09 junyoung Exp $
|
||||
# $NetBSD: mi,v 1.714 2004/07/13 15:42:03 seb Exp $
|
||||
./etc/mtree/set.comp comp-sys-root
|
||||
./usr/bin/addr2line comp-debug-bin bfd
|
||||
./usr/bin/ar comp-util-bin bfd
|
||||
@ -1507,6 +1507,7 @@
|
||||
./usr/include/vm/vnode_pager.h comp-obsolete obsolete
|
||||
./usr/include/wchar.h comp-c-include
|
||||
./usr/include/wctype.h comp-c-include
|
||||
./usr/include/wordexp.h comp-c-include
|
||||
./usr/include/zconf.h comp-c-include
|
||||
./usr/include/zlib.h comp-c-include
|
||||
./usr/lib/crt0.o comp-c-lib
|
||||
@ -4510,6 +4511,7 @@
|
||||
./usr/share/man/cat3/wmemset.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/wmove.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/wnoutrefresh.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/wordexp.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/wprintw.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/wrefresh.0 comp-c-catman .cat
|
||||
./usr/share/man/cat3/wresize.0 comp-c-catman .cat
|
||||
@ -8238,6 +8240,7 @@
|
||||
./usr/share/man/man3/wmemset.3 comp-c-man .man
|
||||
./usr/share/man/man3/wmove.3 comp-c-man .man
|
||||
./usr/share/man/man3/wnoutrefresh.3 comp-c-man .man
|
||||
./usr/share/man/man3/wordexp.3 comp-c-man .man
|
||||
./usr/share/man/man3/wprintw.3 comp-c-man .man
|
||||
./usr/share/man/man3/wrefresh.3 comp-c-man .man
|
||||
./usr/share/man/man3/wresize.3 comp-c-man .man
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile,v 1.116 2004/05/21 02:27:35 christos Exp $
|
||||
# $NetBSD: Makefile,v 1.117 2004/07/13 15:42:03 seb Exp $
|
||||
# @(#)Makefile 8.2 (Berkeley) 1/4/94
|
||||
|
||||
# Doing a make includes builds /usr/include
|
||||
@ -20,7 +20,7 @@ INCS= a.out.h ar.h assert.h bitstring.h bm.h cpio.h ctype.h db.h dirent.h \
|
||||
sgtty.h signal.h stab.h stddef.h stdio.h stdlib.h string.h \
|
||||
strings.h stringlist.h struct.h sysexits.h tar.h threadlib.h time.h \
|
||||
ttyent.h tzfile.h ucontext.h ulimit.h unistd.h util.h utime.h utmp.h \
|
||||
utmpx.h varargs.h vis.h wchar.h wctype.h
|
||||
utmpx.h varargs.h vis.h wchar.h wctype.h wordexp.h
|
||||
INCS+= arpa/ftp.h arpa/inet.h arpa/nameser.h arpa/nameser_compat.h \
|
||||
arpa/telnet.h arpa/tftp.h
|
||||
INCS+= protocols/dumprestore.h protocols/routed.h protocols/rwhod.h \
|
||||
|
81
include/wordexp.h
Normal file
81
include/wordexp.h
Normal file
@ -0,0 +1,81 @@
|
||||
/* $NetBSD: wordexp.h,v 1.1 2004/07/13 15:42:03 seb Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 Tim J. Robbins.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD: /repoman/r/ncvs/src/include/wordexp.h,v 1.4 2003/01/03 12:03:38 tjr Exp $
|
||||
*/
|
||||
|
||||
#ifndef _WORDEXP_H_
|
||||
#define _WORDEXP_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/featuretest.h>
|
||||
#include <machine/ansi.h>
|
||||
|
||||
#ifdef _BSD_SIZE_T_
|
||||
typedef _BSD_SIZE_T_ size_t;
|
||||
#undef _BSD_SIZE_T_
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t we_wordc; /* count of words matched */
|
||||
char **we_wordv; /* pointer to list of words */
|
||||
size_t we_offs; /* slots to reserve in we_wordv */
|
||||
/* following are internals */
|
||||
char *we_strings; /* storage for wordv strings */
|
||||
size_t we_nbytes; /* size of we_strings */
|
||||
} wordexp_t;
|
||||
|
||||
/*
|
||||
* Flags for wordexp().
|
||||
*/
|
||||
#define WRDE_APPEND 0x1 /* append to previously generated */
|
||||
#define WRDE_DOOFFS 0x2 /* we_offs member is valid */
|
||||
#define WRDE_NOCMD 0x4 /* disallow command substitution */
|
||||
#define WRDE_REUSE 0x8 /* reuse wordexp_t */
|
||||
#define WRDE_SHOWERR 0x10 /* don't redirect stderr to /dev/null */
|
||||
#define WRDE_UNDEF 0x20 /* disallow undefined shell vars */
|
||||
|
||||
/*
|
||||
* Return values from wordexp().
|
||||
*/
|
||||
#define WRDE_BADCHAR 1 /* unquoted special character */
|
||||
#define WRDE_BADVAL 2 /* undefined variable */
|
||||
#define WRDE_CMDSUB 3 /* command substitution not allowed */
|
||||
#define WRDE_NOSPACE 4 /* no memory for result */
|
||||
#if (_XOPEN_SOURCE - 0) >= 4 || defined(_NETBSD_SOURCE)
|
||||
#define WRDE_NOSYS 5 /* obsolete, reserved */
|
||||
#endif
|
||||
#define WRDE_SYNTAX 6 /* shell syntax error */
|
||||
#define WRDE_ERRNO 7 /* other errors see errno */
|
||||
|
||||
__BEGIN_DECLS
|
||||
int wordexp(const char * __restrict, wordexp_t * __restrict, int);
|
||||
void wordfree(wordexp_t *);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_WORDEXP_H_ */
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: Makefile.inc,v 1.133 2004/05/31 06:51:59 itojun Exp $
|
||||
# $NetBSD: Makefile.inc,v 1.134 2004/07/13 15:42:03 seb Exp $
|
||||
# from: @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
|
||||
|
||||
# gen sources
|
||||
@ -28,7 +28,7 @@ SRCS+= _errno.c alarm.c arc4random.c assert.c basename.c clock.c closedir.c \
|
||||
times.c timezone.c toascii.c tolower_.c ttyname.c ttyslot.c \
|
||||
toupper_.c ualarm.c ulimit.c uname.c unvis.c usleep.c utime.c utmp.c \
|
||||
utmpx.c valloc.c vis.c wait.c wait3.c waitpid.c warn.c warnx.c \
|
||||
vwarn.c vwarnx.c verr.c verrx.c
|
||||
vwarn.c vwarnx.c verr.c verrx.c wordexp.c
|
||||
|
||||
# indirect reference stubs, to be removed soon.
|
||||
SRCS+= _err.c _errx.c _sys_errlist.c _sys_nerr.c _sys_siglist.c \
|
||||
@ -63,7 +63,8 @@ MAN+= alarm.3 arc4random.3 basename.3 bswap.3 clock.3 closefrom.3 confstr.3 \
|
||||
signal.3 signbit.3 sigrelse.3 sigset.3 sigsetops.3 sleep.3 \
|
||||
stringlist.3 sysconf.3 sysctl.3 syslog.3 time.3 times.3 \
|
||||
timezone.3 toascii.3 tolower.3 toupper.3 ttyname.3 \
|
||||
ualarm.3 ulimit.3 uname.3 unvis.3 usleep.3 utime.3 valloc.3 vis.3
|
||||
ualarm.3 ulimit.3 uname.3 unvis.3 usleep.3 utime.3 valloc.3 vis.3 \
|
||||
wordexp.3
|
||||
|
||||
MLINKS+=bswap.3 bswap16.3 bswap.3 bswap32.3 bswap.3 bswap64.3
|
||||
MLINKS+=directory.3 closedir.3 directory.3 dirfd.3 directory.3 opendir.3 \
|
||||
|
226
lib/libc/gen/wordexp.3
Normal file
226
lib/libc/gen/wordexp.3
Normal file
@ -0,0 +1,226 @@
|
||||
.\" $NetBSD: wordexp.3,v 1.1 2004/07/13 15:42:03 seb Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2002 Tim J. Robbins
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD: /repoman/r/ncvs/src/lib/libc/gen/wordexp.3,v 1.6 2003/09/08 19:57:14 ru Exp $
|
||||
.\"
|
||||
.Dd July 13, 2004
|
||||
.Dt WORDEXP 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm wordexp
|
||||
.Nd "perform shell-style word expansions"
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
.In wordexp.h
|
||||
.Ft int
|
||||
.Fn wordexp "const char * restrict words" "wordexp_t * restrict pwordexp" "int flags"
|
||||
.Ft void
|
||||
.Fn wordfree "wordexp_t *pwordexp"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn wordexp
|
||||
function performs shell-style word expansion on
|
||||
.Fa words
|
||||
and places the list of expanded words into the structure pointed to by
|
||||
.Fa pwordexp .
|
||||
.Pp
|
||||
The
|
||||
.Fa flags
|
||||
argument is the bitwise inclusive OR of any of the following constants:
|
||||
.Bl -tag -width ".Dv WRDE_SHOWERR"
|
||||
.It Dv WRDE_APPEND
|
||||
Append the words to those generated by a previous call to
|
||||
.Fn wordexp .
|
||||
.It Dv WRDE_DOOFFS
|
||||
As many
|
||||
.Dv NULL
|
||||
pointers as are specified by the
|
||||
.Va we_offs
|
||||
member of
|
||||
.Fa we
|
||||
are added to the front of
|
||||
.Va we_wordv .
|
||||
.It Dv WRDE_NOCMD
|
||||
Disallow command substitution in
|
||||
.Fa words .
|
||||
See the note in
|
||||
.Sx BUGS
|
||||
before using this.
|
||||
.It Dv WRDE_REUSE
|
||||
The
|
||||
.Fa we
|
||||
argument was passed to a previous successful call to
|
||||
.Fn wordexp
|
||||
but has not been passed to
|
||||
.Fn wordfree .
|
||||
The implementation may reuse the space allocated to it.
|
||||
.It Dv WRDE_SHOWERR
|
||||
Do not redirect shell error messages to
|
||||
.Pa /dev/null .
|
||||
.It Dv WRDE_UNDEF
|
||||
Report error on an attempt to expand an undefined shell variable.
|
||||
.El
|
||||
.Pp
|
||||
The structure type
|
||||
.Nm wordexp_t
|
||||
includes the following members:
|
||||
.Bd -literal -offset indent
|
||||
size_t we_wordc
|
||||
char **we_wordv
|
||||
size_t we_offs
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Fa we_wordc
|
||||
member is the count of generated words.
|
||||
.Pp
|
||||
The
|
||||
.Fa we_wordv
|
||||
member points to a list of pointers to expanded words.
|
||||
.Pp
|
||||
The
|
||||
.Fa we_offs
|
||||
member is the number of slots to reserve at the beginning of the
|
||||
.Fa we_wordv
|
||||
member.
|
||||
.Pp
|
||||
It is the caller's responsibility to allocate the storage pointed to by
|
||||
.Fa pwordexp .
|
||||
The
|
||||
.Fn wordexp
|
||||
function allocates other space as needed, including memory
|
||||
pointed to by the
|
||||
.Fa we_wordv
|
||||
member.
|
||||
.Pp
|
||||
The
|
||||
.Fn wordfree
|
||||
function frees the memory allocated by
|
||||
.Fn wordexp .
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
The
|
||||
.Fn wordexp
|
||||
function is implemented as a wrapper around the undocumented
|
||||
.Ic wordexp
|
||||
shell built-in command.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn wordexp
|
||||
function returns zero if successful, otherwise it returns one of the following
|
||||
error codes:
|
||||
.Bl -tag -width ".Dv WRDE_NOSPACE"
|
||||
.It Dv WRDE_BADCHAR
|
||||
The
|
||||
.Fa words
|
||||
argument contains one of the following unquoted characters:
|
||||
.Aq newline ,
|
||||
.Ql | ,
|
||||
.Ql \*[Am] ,
|
||||
.Ql \&; ,
|
||||
.Ql \*[Lt] ,
|
||||
.Ql \*[Gt] ,
|
||||
.Ql \&( ,
|
||||
.Ql \&) ,
|
||||
.Ql { ,
|
||||
.Ql } .
|
||||
.It Dv WRDE_BADVAL
|
||||
An attempt was made to expand an undefined shell variable and
|
||||
.Dv WRDE_UNDEF
|
||||
is set in
|
||||
.Fa flags .
|
||||
.It Dv WRDE_CMDSUB
|
||||
An attempt was made to use command substitution and
|
||||
.Dv WRDE_NOCMD
|
||||
is set in
|
||||
.Fa flags .
|
||||
.It Dv WRDE_NOSPACE
|
||||
Not enough memory to store the result.
|
||||
.It Dv WRDE_SYNTAX
|
||||
Shell syntax error in
|
||||
.Fa words .
|
||||
.It Dv WRDE_ERRNO
|
||||
An internal error occured and
|
||||
.Va errno
|
||||
is set to indicate the error.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn wordfree
|
||||
function returns no value.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width ".Ev IFS"
|
||||
.It Ev IFS
|
||||
Field separator.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Invoke the editor on all
|
||||
.Pa .c
|
||||
files in the current directory
|
||||
and
|
||||
.Pa /etc/motd
|
||||
(error checking omitted):
|
||||
.Bd -literal -offset indent
|
||||
wordexp_t we;
|
||||
|
||||
wordexp("${EDITOR:-vi} *.c /etc/motd", *[Am]we, 0);
|
||||
execvp(we-\*[Gt]we_wordv[0], we-\*[Gt]we_wordv);
|
||||
.Ed
|
||||
.Sh DIAGNOSTICS
|
||||
Diagnostic messages from the shell are written to the standard error output
|
||||
if
|
||||
.Dv WRDE_SHOWERR
|
||||
is set in
|
||||
.Fa flags .
|
||||
.Sh SEE ALSO
|
||||
.Xr sh 1 ,
|
||||
.Xr fnmatch 3 ,
|
||||
.Xr glob 3 ,
|
||||
.Xr popen 3 ,
|
||||
.Xr system 3
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Fn wordexp
|
||||
and
|
||||
.Fn wordfree
|
||||
functions conform to
|
||||
.St -p1003.1-2001 .
|
||||
Their first release was in
|
||||
.St -p1003.2-92 .
|
||||
The return value
|
||||
.Dv WRDE_ERRNO
|
||||
is an extension.
|
||||
.Sh BUGS
|
||||
Do not pass untrusted user data to
|
||||
.Fn wordexp ,
|
||||
regardless of whether the
|
||||
.Dv WRDE_NOCMD
|
||||
flag is set.
|
||||
The
|
||||
.Fn wordexp
|
||||
function attempts to detect input that would cause commands to be
|
||||
executed before passing it to the shell
|
||||
but it does not use the same parser so it may be fooled.
|
345
lib/libc/gen/wordexp.c
Normal file
345
lib/libc/gen/wordexp.c
Normal file
@ -0,0 +1,345 @@
|
||||
/* $NetBSD: wordexp.c,v 1.1 2004/07/13 15:42:03 seb Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 Tim J. Robbins.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "namespace.h"
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wordexp.h>
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
#if 0
|
||||
__FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/gen/wordexp.c,v 1.5 2004/04/09 11:32:32 tjr Exp $");
|
||||
#else
|
||||
__RCSID("$NetBSD: wordexp.c,v 1.1 2004/07/13 15:42:03 seb Exp $");
|
||||
#endif
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
static int we_askshell(const char *, wordexp_t *, int);
|
||||
static int we_check(const char *, int);
|
||||
|
||||
/*
|
||||
* wordexp --
|
||||
* Perform shell word expansion on `words' and place the resulting list
|
||||
* of words in `we'. See wordexp(3).
|
||||
*
|
||||
*/
|
||||
int
|
||||
wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags)
|
||||
{
|
||||
int error;
|
||||
|
||||
_DIAGASSERT(we != NULL);
|
||||
_DIAGASSERT(words != NULL);
|
||||
if (flags & WRDE_REUSE)
|
||||
wordfree(we);
|
||||
if ((flags & WRDE_APPEND) == 0) {
|
||||
we->we_wordc = 0;
|
||||
we->we_wordv = NULL;
|
||||
we->we_strings = NULL;
|
||||
we->we_nbytes = 0;
|
||||
}
|
||||
if ((error = we_check(words, flags)) != 0) {
|
||||
wordfree(we);
|
||||
return (error);
|
||||
}
|
||||
if ((error = we_askshell(words, we, flags)) != 0) {
|
||||
wordfree(we);
|
||||
return (error);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* we_askshell --
|
||||
* Use the `wordexp' /bin/sh builtin function to do most of the work
|
||||
* in expanding the word string. This function is complicated by
|
||||
* memory management.
|
||||
*/
|
||||
static int
|
||||
we_askshell(const char *words, wordexp_t *we, int flags)
|
||||
{
|
||||
int pdes[2]; /* Pipe to child */
|
||||
size_t nwords, nbytes; /* Number of words, bytes from child */
|
||||
int i; /* Handy integer */
|
||||
size_t sofs; /* Offset into we->we_strings */
|
||||
size_t vofs; /* Offset into we->we_wordv */
|
||||
pid_t pid; /* Process ID of child */
|
||||
int status; /* Child exit status */
|
||||
char *ifs; /* IFS env. var. */
|
||||
char *np, *p; /* Handy pointers */
|
||||
char *nstrings; /* Temporary for realloc() */
|
||||
char **nwv; /* Temporary for realloc() */
|
||||
FILE *fp; /* Stream to read pipe */
|
||||
extern char **environ;
|
||||
char *cmd;
|
||||
|
||||
if ((ifs = getenv("IFS")) == NULL)
|
||||
ifs = " \t\n";
|
||||
if (asprintf(&cmd, "wordexp%c%s\n", *ifs, words) < 0)
|
||||
return (WRDE_NOSPACE);
|
||||
if (pipe(pdes) < 0) {
|
||||
free(cmd);
|
||||
return (WRDE_ERRNO);
|
||||
}
|
||||
if ((fp = fdopen(pdes[0], "r")) == NULL) {
|
||||
free(cmd);
|
||||
return (WRDE_ERRNO);
|
||||
}
|
||||
if ((pid = fork()) < 0) {
|
||||
free(cmd);
|
||||
fclose(fp);
|
||||
close(pdes[1]);
|
||||
return (WRDE_ERRNO);
|
||||
}
|
||||
else if (pid == 0) {
|
||||
/*
|
||||
* We are the child; just get /bin/sh to run the wordexp
|
||||
* builtin on `words'.
|
||||
*/
|
||||
int devnull;
|
||||
|
||||
close(pdes[0]);
|
||||
if (pdes[1] != STDOUT_FILENO) {
|
||||
if (dup2(pdes[1], STDOUT_FILENO) < 0)
|
||||
_exit(1);
|
||||
close(pdes[1]);
|
||||
}
|
||||
if ((flags & WRDE_SHOWERR) == 0) {
|
||||
if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0666)) < 0)
|
||||
_exit(1);
|
||||
if (dup2(devnull, STDERR_FILENO) < 0)
|
||||
_exit(1);
|
||||
close(devnull);
|
||||
}
|
||||
execle(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u",
|
||||
"-c", cmd, (char *)NULL, environ);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are the parent; read the output of the shell wordexp function,
|
||||
* which is a decimal word count, an null, a decimal byte count,
|
||||
* (not including terminating null bytes), a null and then followed
|
||||
* by the expanded words separated by nulls.
|
||||
*/
|
||||
free(cmd);
|
||||
close(pdes[1]);
|
||||
/* read the word count */
|
||||
nwords = 0;
|
||||
while ((i = getc(fp)) != EOF) {
|
||||
if (i == '\0')
|
||||
break;
|
||||
nwords *= 10;
|
||||
nwords += (i - '0');
|
||||
}
|
||||
/* read the byte count */
|
||||
nbytes = 0;
|
||||
while ((i = getc(fp)) != EOF) {
|
||||
if (i == '\0')
|
||||
break;
|
||||
nbytes *= 10;
|
||||
nbytes += (i - '0');
|
||||
}
|
||||
if (i == EOF) {
|
||||
fclose(fp);
|
||||
waitpid(pid, &status, 0);
|
||||
return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
|
||||
}
|
||||
nbytes += nwords;
|
||||
|
||||
/*
|
||||
* Allocate or reallocate (when flags & WRDE_APPEND) the word vector
|
||||
* and string storage buffers for the expanded words we're about to
|
||||
* read from the child.
|
||||
*/
|
||||
sofs = we->we_nbytes;
|
||||
vofs = we->we_wordc;
|
||||
if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND))
|
||||
vofs += we->we_offs;
|
||||
we->we_wordc += nwords;
|
||||
we->we_nbytes += nbytes;
|
||||
if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 +
|
||||
(flags & WRDE_DOOFFS ? we->we_offs : 0)) *
|
||||
sizeof(char *))) == NULL) {
|
||||
fclose(fp);
|
||||
waitpid(pid, &status, 0);
|
||||
return (WRDE_NOSPACE);
|
||||
}
|
||||
we->we_wordv = nwv;
|
||||
if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) {
|
||||
fclose(fp);
|
||||
waitpid(pid, &status, 0);
|
||||
return (WRDE_NOSPACE);
|
||||
}
|
||||
for (i = 0; i < vofs; i++)
|
||||
if (we->we_wordv[i] != NULL)
|
||||
we->we_wordv[i] += nstrings - we->we_strings;
|
||||
we->we_strings = nstrings;
|
||||
|
||||
if (fread(we->we_strings + sofs, sizeof(char), nbytes, fp) != nbytes) {
|
||||
fclose(fp);
|
||||
waitpid(pid, &status, 0);
|
||||
return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
|
||||
}
|
||||
|
||||
if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) ||
|
||||
WEXITSTATUS(status) != 0) {
|
||||
fclose(fp);
|
||||
return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
/*
|
||||
* Break the null-terminated expanded word strings out into
|
||||
* the vector.
|
||||
*/
|
||||
if (vofs == 0 && flags & WRDE_DOOFFS)
|
||||
while (vofs < we->we_offs)
|
||||
we->we_wordv[vofs++] = NULL;
|
||||
p = we->we_strings + sofs;
|
||||
while (nwords-- != 0) {
|
||||
we->we_wordv[vofs++] = p;
|
||||
if ((np = memchr(p, '\0', nbytes)) == NULL)
|
||||
return (WRDE_NOSPACE); /* XXX */
|
||||
nbytes -= np - p + 1;
|
||||
p = np + 1;
|
||||
}
|
||||
we->we_wordv[vofs] = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* we_check --
|
||||
* Check that the string contains none of the following unquoted
|
||||
* special characters: <newline> |&;<>(){}
|
||||
* or command substitutions when WRDE_NOCMD is set in flags.
|
||||
*/
|
||||
static int
|
||||
we_check(const char *words, int flags)
|
||||
{
|
||||
char c;
|
||||
int dquote, level, quote, squote;
|
||||
|
||||
quote = squote = dquote = 0;
|
||||
while ((c = *words++) != '\0') {
|
||||
switch (c) {
|
||||
case '\\':
|
||||
quote ^= 1;
|
||||
continue;
|
||||
case '\'':
|
||||
if (quote + dquote == 0)
|
||||
squote ^= 1;
|
||||
break;
|
||||
case '"':
|
||||
if (quote + squote == 0)
|
||||
dquote ^= 1;
|
||||
break;
|
||||
case '`':
|
||||
if (quote + squote == 0 && flags & WRDE_NOCMD)
|
||||
return (WRDE_CMDSUB);
|
||||
while ((c = *words++) != '\0' && c != '`')
|
||||
if (c == '\\' && (c = *words++) == '\0')
|
||||
break;
|
||||
if (c == '\0')
|
||||
return (WRDE_SYNTAX);
|
||||
break;
|
||||
case '|': case '&': case ';': case '<': case '>':
|
||||
case '{': case '}': case '(': case ')': case '\n':
|
||||
if (quote + squote + dquote == 0)
|
||||
return (WRDE_BADCHAR);
|
||||
break;
|
||||
case '$':
|
||||
if ((c = *words++) == '\0')
|
||||
break;
|
||||
else if (quote + squote == 0 && c == '(') {
|
||||
if (flags & WRDE_NOCMD && *words != '(')
|
||||
return (WRDE_CMDSUB);
|
||||
level = 1;
|
||||
while ((c = *words++) != '\0') {
|
||||
if (c == '\\') {
|
||||
if ((c = *words++) == '\0')
|
||||
break;
|
||||
} else if (c == '(')
|
||||
level++;
|
||||
else if (c == ')' && --level == 0)
|
||||
break;
|
||||
}
|
||||
if (c == '\0' || level != 0)
|
||||
return (WRDE_SYNTAX);
|
||||
} else if (quote + squote == 0 && c == '{') {
|
||||
level = 1;
|
||||
while ((c = *words++) != '\0') {
|
||||
if (c == '\\') {
|
||||
if ((c = *words++) == '\0')
|
||||
break;
|
||||
} else if (c == '{')
|
||||
level++;
|
||||
else if (c == '}' && --level == 0)
|
||||
break;
|
||||
}
|
||||
if (c == '\0' || level != 0)
|
||||
return (WRDE_SYNTAX);
|
||||
} else
|
||||
c = *--words;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
quote = 0;
|
||||
}
|
||||
if (quote + squote + dquote != 0)
|
||||
return (WRDE_SYNTAX);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* wordfree --
|
||||
* Free the result of wordexp(). See wordexp(3).
|
||||
*
|
||||
*/
|
||||
void
|
||||
wordfree(wordexp_t *we)
|
||||
{
|
||||
_DIAGASSERT(we != NULL);
|
||||
free(we->we_wordv);
|
||||
free(we->we_strings);
|
||||
we->we_wordv = NULL;
|
||||
we->we_strings = NULL;
|
||||
we->we_nbytes = 0;
|
||||
we->we_wordc = 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user