17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5004388ebScasper * Common Development and Distribution License (the "License").
6004388ebScasper * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21ec6bbcf8Sraf
227c478bd9Sstevel@tonic-gate /*
23ead1f93eSLiane Praza * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * This code is MKS code ported to Solaris originally with minimum
297c478bd9Sstevel@tonic-gate * modifications so that upgrades from MKS would readily integrate.
307c478bd9Sstevel@tonic-gate * The MKS basis for this modification was:
317c478bd9Sstevel@tonic-gate *
327c478bd9Sstevel@tonic-gate * $Id: wordexp.c 1.22 1994/11/21 18:24:50 miked
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * Additional modifications have been made to this code to make it
357c478bd9Sstevel@tonic-gate * 64-bit clean.
367c478bd9Sstevel@tonic-gate */
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate * wordexp, wordfree -- POSIX.2 D11.2 word expansion routines.
407c478bd9Sstevel@tonic-gate *
417c478bd9Sstevel@tonic-gate * Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved.
42da2e3ebdSchin * Modified by Roland Mainz <roland.mainz@nrubsig.org> to support ksh93.
437c478bd9Sstevel@tonic-gate */
447c478bd9Sstevel@tonic-gate
457257d1b4Sraf #pragma weak _wordexp = wordexp
467257d1b4Sraf #pragma weak _wordfree = wordfree
4764e3e6f9Scraigm
487257d1b4Sraf #include "lint.h"
497c478bd9Sstevel@tonic-gate #include <stdio.h>
507c478bd9Sstevel@tonic-gate #include <unistd.h>
517c478bd9Sstevel@tonic-gate #include <limits.h>
527c478bd9Sstevel@tonic-gate #include <fcntl.h>
537c478bd9Sstevel@tonic-gate #include <limits.h>
547c478bd9Sstevel@tonic-gate #include <stdlib.h>
55da2e3ebdSchin #include <alloca.h>
567c478bd9Sstevel@tonic-gate #include <string.h>
577c478bd9Sstevel@tonic-gate #include <sys/wait.h>
58a574db85Sraf #include <pthread.h>
597c478bd9Sstevel@tonic-gate #include <unistd.h>
607c478bd9Sstevel@tonic-gate #include <wordexp.h>
617c478bd9Sstevel@tonic-gate #include <stdio.h>
62657b1f3dSraf #include <spawn.h>
637c478bd9Sstevel@tonic-gate #include <errno.h>
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate #define INITIAL 8 /* initial pathv allocation */
667c478bd9Sstevel@tonic-gate #define BUFSZ 256 /* allocation unit of the line buffer */
677c478bd9Sstevel@tonic-gate
681c7ddb37SRoger A. Faulkner /*
691c7ddb37SRoger A. Faulkner * Needs no locking if fetched only once.
701c7ddb37SRoger A. Faulkner * See getenv()/putenv()/setenv().
711c7ddb37SRoger A. Faulkner */
721c7ddb37SRoger A. Faulkner extern const char **_environ;
731c7ddb37SRoger A. Faulkner
74da2e3ebdSchin /* Local prototypes */
75da2e3ebdSchin static int append(wordexp_t *, char *);
76da2e3ebdSchin
77da2e3ebdSchin /*
78da2e3ebdSchin * |mystpcpy| - like |strcpy()| but returns the end of the buffer
79da2e3ebdSchin * We'll add this later (and a matching multibyte/widechar version)
80da2e3ebdSchin * as normal libc function.
81da2e3ebdSchin *
82da2e3ebdSchin * Copy string s2 to s1. s1 must be large enough.
83da2e3ebdSchin * return s1-1 (position of string terminator ('\0') in destination buffer).
84da2e3ebdSchin */
85da2e3ebdSchin static char *
mystpcpy(char * s1,const char * s2)86da2e3ebdSchin mystpcpy(char *s1, const char *s2)
87da2e3ebdSchin {
88*00ae5933SToomas Soome while ((*s1++ = *s2++) != '\0')
89da2e3ebdSchin ;
90da2e3ebdSchin return (s1-1);
91da2e3ebdSchin }
92da2e3ebdSchin
93da2e3ebdSchin /*
94da2e3ebdSchin * Do word expansion.
951c7ddb37SRoger A. Faulkner * We build a mini-script in |buff| which takes care of all details,
96da2e3ebdSchin * including stdin/stdout/stderr redirection, WRDE_NOCMD mode and
97da2e3ebdSchin * the word expansion itself.
98da2e3ebdSchin */
99da2e3ebdSchin int
wordexp(const char * word,wordexp_t * wp,int flags)100da2e3ebdSchin wordexp(const char *word, wordexp_t *wp, int flags)
101da2e3ebdSchin {
1021c7ddb37SRoger A. Faulkner const char *path = "/usr/bin/ksh93";
103da2e3ebdSchin wordexp_t wptmp;
104da2e3ebdSchin size_t si;
105da2e3ebdSchin pid_t pid;
1061c7ddb37SRoger A. Faulkner char *line, *eob, *cp; /* word from shell */
107da2e3ebdSchin int rv = WRDE_ERRNO;
108da2e3ebdSchin int status;
1091c7ddb37SRoger A. Faulkner int pv[2]; /* pipe from shell stdout */
1101c7ddb37SRoger A. Faulkner FILE *fp; /* pipe read stream */
1111c7ddb37SRoger A. Faulkner int tmpalloc;
1121c7ddb37SRoger A. Faulkner char *wd = NULL;
1131c7ddb37SRoger A. Faulkner const char **env = NULL;
1141c7ddb37SRoger A. Faulkner const char **envp;
1151c7ddb37SRoger A. Faulkner const char *ev;
1161c7ddb37SRoger A. Faulkner int n;
1171c7ddb37SRoger A. Faulkner posix_spawnattr_t attr;
1181c7ddb37SRoger A. Faulkner posix_spawn_file_actions_t fact;
1191c7ddb37SRoger A. Faulkner int error;
120a574db85Sraf int cancel_state;
1211c7ddb37SRoger A. Faulkner size_t bufflen; /* Length of |buff| */
1221c7ddb37SRoger A. Faulkner char *buff;
1231c7ddb37SRoger A. Faulkner char *currbuffp; /* Current position of '\0' in |buff| */
1241c7ddb37SRoger A. Faulkner char *args[10];
1251c7ddb37SRoger A. Faulkner int i;
126da2e3ebdSchin
127da2e3ebdSchin /*
128da2e3ebdSchin * Do absolute minimum necessary for the REUSE flag. Eventually
129da2e3ebdSchin * want to be able to actually avoid excessive malloc calls.
130da2e3ebdSchin */
131da2e3ebdSchin if (flags & WRDE_REUSE)
132da2e3ebdSchin wordfree(wp);
133da2e3ebdSchin
134da2e3ebdSchin /*
135da2e3ebdSchin * Initialize wordexp_t
136da2e3ebdSchin *
137da2e3ebdSchin * XPG requires that the struct pointed to by wp not be modified
138da2e3ebdSchin * unless wordexp() either succeeds, or fails on WRDE_NOSPACE.
139da2e3ebdSchin * So we work with wptmp, and only copy wptmp to wp if one of the
140da2e3ebdSchin * previously mentioned conditions is satisfied.
141da2e3ebdSchin */
142da2e3ebdSchin wptmp = *wp;
143da2e3ebdSchin
144da2e3ebdSchin /*
145da2e3ebdSchin * Man page says:
146da2e3ebdSchin * 2. All of the calls must set WRDE_DOOFFS, or all must not
1471c7ddb37SRoger A. Faulkner * set it.
148da2e3ebdSchin * Therefore, if it's not set, we_offs will always be reset.
149da2e3ebdSchin */
150da2e3ebdSchin if ((flags & WRDE_DOOFFS) == 0)
151da2e3ebdSchin wptmp.we_offs = 0;
152da2e3ebdSchin
153da2e3ebdSchin /*
154da2e3ebdSchin * If we get APPEND|REUSE, how should we do?
1551c7ddb37SRoger A. Faulkner * allocating buffer anyway to avoid segfault.
156da2e3ebdSchin */
157da2e3ebdSchin tmpalloc = 0;
158da2e3ebdSchin if ((flags & WRDE_APPEND) == 0 || (flags & WRDE_REUSE)) {
159da2e3ebdSchin wptmp.we_wordc = 0;
160da2e3ebdSchin wptmp.we_wordn = wptmp.we_offs + INITIAL;
1611c7ddb37SRoger A. Faulkner wptmp.we_wordv = malloc(sizeof (char *) * wptmp.we_wordn);
162da2e3ebdSchin if (wptmp.we_wordv == NULL)
163da2e3ebdSchin return (WRDE_NOSPACE);
164da2e3ebdSchin wptmp.we_wordp = wptmp.we_wordv + wptmp.we_offs;
165da2e3ebdSchin for (si = 0; si < wptmp.we_offs; si++)
166da2e3ebdSchin wptmp.we_wordv[si] = NULL;
167da2e3ebdSchin tmpalloc = 1;
168da2e3ebdSchin }
169da2e3ebdSchin
170ec6bbcf8Sraf /*
171ec6bbcf8Sraf * The UNIX98 Posix conformance test suite requires
1721c7ddb37SRoger A. Faulkner * |wordexp()| to not be a cancellation point.
173ec6bbcf8Sraf */
174ec6bbcf8Sraf (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
175ec6bbcf8Sraf
176da2e3ebdSchin /*
1771c7ddb37SRoger A. Faulkner * Make sure PWD is in the environment.
178da2e3ebdSchin */
1791c7ddb37SRoger A. Faulkner if ((envp = _environ) == NULL) {
1801c7ddb37SRoger A. Faulkner /* can happen when processing a SunOS 4.x AOUT file */
1811c7ddb37SRoger A. Faulkner ev = NULL;
1821c7ddb37SRoger A. Faulkner n = 0;
1831c7ddb37SRoger A. Faulkner } else {
1841c7ddb37SRoger A. Faulkner for (n = 0; (ev = envp[n]) != NULL; n++) {
1851c7ddb37SRoger A. Faulkner if (*ev == 'P' && strncmp(ev, "PWD=", 4) == 0)
1861c7ddb37SRoger A. Faulkner break;
1871c7ddb37SRoger A. Faulkner }
1881c7ddb37SRoger A. Faulkner }
1891c7ddb37SRoger A. Faulkner if (ev == NULL) { /* PWD missing from the environment */
1901c7ddb37SRoger A. Faulkner /* allocate a new environment */
1911c7ddb37SRoger A. Faulkner if ((env = malloc((n + 2) * sizeof (char *))) == NULL ||
1921c7ddb37SRoger A. Faulkner (wd = malloc(PATH_MAX + 4)) == NULL)
1931c7ddb37SRoger A. Faulkner goto cleanup;
1941c7ddb37SRoger A. Faulkner for (i = 0; i < n; i++)
1951c7ddb37SRoger A. Faulkner env[i] = envp[i];
1961c7ddb37SRoger A. Faulkner (void) strcpy(wd, "PWD=");
1971c7ddb37SRoger A. Faulkner if (getcwd(&wd[4], PATH_MAX) == NULL)
1981c7ddb37SRoger A. Faulkner (void) strcpy(&wd[4], "/");
1991c7ddb37SRoger A. Faulkner env[i] = wd;
2001c7ddb37SRoger A. Faulkner env[i + 1] = NULL;
2011c7ddb37SRoger A. Faulkner envp = env;
2021c7ddb37SRoger A. Faulkner }
203da2e3ebdSchin
204da2e3ebdSchin /*
2051c7ddb37SRoger A. Faulkner * Calculate size of required buffer (which is size of the
2061c7ddb37SRoger A. Faulkner * input string (|word|) plus all string literals below;
2071c7ddb37SRoger A. Faulkner * this value MUST be adjusted each time the literals are
2081c7ddb37SRoger A. Faulkner * changed!!).
209da2e3ebdSchin */
2101c7ddb37SRoger A. Faulkner bufflen = 165 + strlen(word);
2111c7ddb37SRoger A. Faulkner buff = alloca(bufflen);
2121c7ddb37SRoger A. Faulkner i = 0;
213da2e3ebdSchin
2141c7ddb37SRoger A. Faulkner /* Start filling the buffer */
2151c7ddb37SRoger A. Faulkner buff[0] = '\0';
2161c7ddb37SRoger A. Faulkner currbuffp = buff;
217da2e3ebdSchin
2181c7ddb37SRoger A. Faulkner if (flags & WRDE_UNDEF)
2191c7ddb37SRoger A. Faulkner currbuffp = mystpcpy(currbuffp, "set -o nounset\n");
2201c7ddb37SRoger A. Faulkner if ((flags & WRDE_SHOWERR) == 0) {
221da2e3ebdSchin /*
2221c7ddb37SRoger A. Faulkner * The newline ('\n') is neccesary to make sure that
2231c7ddb37SRoger A. Faulkner * the redirection to /dev/null is already active in
2241c7ddb37SRoger A. Faulkner * the case the printf below contains a syntax
2251c7ddb37SRoger A. Faulkner * error...
226da2e3ebdSchin */
2271c7ddb37SRoger A. Faulkner currbuffp = mystpcpy(currbuffp, "exec 2>/dev/null\n");
2281c7ddb37SRoger A. Faulkner }
2291c7ddb37SRoger A. Faulkner /* Squish stdin */
2301c7ddb37SRoger A. Faulkner currbuffp = mystpcpy(currbuffp, "exec 0</dev/null\n");
231da2e3ebdSchin
2321c7ddb37SRoger A. Faulkner if (flags & WRDE_NOCMD) {
2331c7ddb37SRoger A. Faulkner /*
2341c7ddb37SRoger A. Faulkner * Switch to restricted shell (rksh) mode here to
2351c7ddb37SRoger A. Faulkner * put the word expansion into a "cage" which
2361c7ddb37SRoger A. Faulkner * prevents users from executing external commands
2371c7ddb37SRoger A. Faulkner * (outside those listed by ${PATH} (which we set
2381c7ddb37SRoger A. Faulkner * explicitly to /usr/no/such/path/element/)).
2391c7ddb37SRoger A. Faulkner */
2401c7ddb37SRoger A. Faulkner currbuffp = mystpcpy(currbuffp,
2411c7ddb37SRoger A. Faulkner "export PATH=/usr/no/such/path/element/ ; "
2421c7ddb37SRoger A. Faulkner "set -o restricted\n");
2431c7ddb37SRoger A. Faulkner }
244da2e3ebdSchin
2451c7ddb37SRoger A. Faulkner (void) snprintf(currbuffp, bufflen,
2461c7ddb37SRoger A. Faulkner "print -f '%%s\\000' -- %s", word);
247da2e3ebdSchin
2481c7ddb37SRoger A. Faulkner args[i++] = strrchr(path, '/') + 1;
2491c7ddb37SRoger A. Faulkner args[i++] = "-c";
2501c7ddb37SRoger A. Faulkner args[i++] = buff;
2511c7ddb37SRoger A. Faulkner args[i++] = NULL;
252da2e3ebdSchin
2531c7ddb37SRoger A. Faulkner if ((error = posix_spawnattr_init(&attr)) != 0) {
2541c7ddb37SRoger A. Faulkner errno = error;
2551c7ddb37SRoger A. Faulkner goto cleanup;
2561c7ddb37SRoger A. Faulkner }
2571c7ddb37SRoger A. Faulkner if ((error = posix_spawn_file_actions_init(&fact)) != 0) {
2581c7ddb37SRoger A. Faulkner (void) posix_spawnattr_destroy(&attr);
2591c7ddb37SRoger A. Faulkner errno = error;
2601c7ddb37SRoger A. Faulkner goto cleanup;
2611c7ddb37SRoger A. Faulkner }
262da2e3ebdSchin
2631c7ddb37SRoger A. Faulkner /*
2641c7ddb37SRoger A. Faulkner * Set up pipe from shell stdout to "fp" for us
2651c7ddb37SRoger A. Faulkner */
2661c7ddb37SRoger A. Faulkner if (pipe(pv) < 0) {
2671c7ddb37SRoger A. Faulkner error = errno;
2681c7ddb37SRoger A. Faulkner (void) posix_spawnattr_destroy(&attr);
2691c7ddb37SRoger A. Faulkner (void) posix_spawn_file_actions_destroy(&fact);
2701c7ddb37SRoger A. Faulkner errno = error;
2711c7ddb37SRoger A. Faulkner goto cleanup;
272da2e3ebdSchin }
273da2e3ebdSchin
2741c7ddb37SRoger A. Faulkner /*
2751c7ddb37SRoger A. Faulkner * Spawn shell
2761c7ddb37SRoger A. Faulkner */
2771c7ddb37SRoger A. Faulkner error = posix_spawnattr_setflags(&attr,
2781c7ddb37SRoger A. Faulkner POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP);
2791c7ddb37SRoger A. Faulkner if (error == 0)
2801c7ddb37SRoger A. Faulkner error = posix_spawn_file_actions_adddup2(&fact, pv[1], 1);
2811c7ddb37SRoger A. Faulkner if (error == 0 && pv[0] != 1)
2821c7ddb37SRoger A. Faulkner error = posix_spawn_file_actions_addclose(&fact, pv[0]);
2831c7ddb37SRoger A. Faulkner if (error == 0 && pv[1] != 1)
2841c7ddb37SRoger A. Faulkner error = posix_spawn_file_actions_addclose(&fact, pv[1]);
2851c7ddb37SRoger A. Faulkner if (error == 0 && !(flags & WRDE_SHOWERR))
2861c7ddb37SRoger A. Faulkner error = posix_spawn_file_actions_addopen(&fact, 2,
2871c7ddb37SRoger A. Faulkner "/dev/null", O_WRONLY, 0);
2881c7ddb37SRoger A. Faulkner
2891c7ddb37SRoger A. Faulkner if (error == 0)
2901c7ddb37SRoger A. Faulkner error = posix_spawn(&pid, path, &fact, &attr,
2911c7ddb37SRoger A. Faulkner (char *const *)args, (char *const *)envp);
2921c7ddb37SRoger A. Faulkner (void) posix_spawnattr_destroy(&attr);
2931c7ddb37SRoger A. Faulkner (void) posix_spawn_file_actions_destroy(&fact);
294da2e3ebdSchin (void) close(pv[1]);
2951c7ddb37SRoger A. Faulkner if (error) {
2961c7ddb37SRoger A. Faulkner (void) close(pv[0]);
2971c7ddb37SRoger A. Faulkner errno = error;
2981c7ddb37SRoger A. Faulkner goto cleanup;
2991c7ddb37SRoger A. Faulkner }
300da2e3ebdSchin
301da2e3ebdSchin if ((fp = fdopen(pv[0], "rF")) == NULL) {
3021c7ddb37SRoger A. Faulkner error = errno;
303da2e3ebdSchin (void) close(pv[0]);
3041c7ddb37SRoger A. Faulkner errno = error;
305da2e3ebdSchin goto wait_cleanup;
306da2e3ebdSchin }
307da2e3ebdSchin
308da2e3ebdSchin /*
309da2e3ebdSchin * Read words from shell, separated with '\0'.
310da2e3ebdSchin * Since there is no way to disable IFS splitting,
311da2e3ebdSchin * it would be possible to separate the output with '\n'.
312da2e3ebdSchin */
313da2e3ebdSchin cp = line = malloc(BUFSZ);
314da2e3ebdSchin if (line == NULL) {
3151c7ddb37SRoger A. Faulkner error = errno;
316da2e3ebdSchin (void) fclose(fp);
3171c7ddb37SRoger A. Faulkner errno = error;
318da2e3ebdSchin goto wait_cleanup;
319da2e3ebdSchin }
320da2e3ebdSchin eob = line + BUFSZ;
321da2e3ebdSchin
322da2e3ebdSchin rv = 0;
3231c7ddb37SRoger A. Faulkner flockfile(fp);
3241c7ddb37SRoger A. Faulkner while ((i = getc_unlocked(fp)) != EOF) {
325da2e3ebdSchin *cp++ = (char)i;
326da2e3ebdSchin if (i == '\0') {
327da2e3ebdSchin cp = line;
328da2e3ebdSchin if ((rv = append(&wptmp, cp)) != 0) {
329da2e3ebdSchin break;
330da2e3ebdSchin }
331da2e3ebdSchin }
332da2e3ebdSchin if (cp == eob) {
333da2e3ebdSchin size_t bs = (eob - line);
334da2e3ebdSchin char *nl;
335da2e3ebdSchin
336da2e3ebdSchin if ((nl = realloc(line, bs + BUFSZ)) == NULL) {
337da2e3ebdSchin rv = WRDE_NOSPACE;
338da2e3ebdSchin break;
339da2e3ebdSchin }
340da2e3ebdSchin line = nl;
341da2e3ebdSchin cp = line + bs;
342da2e3ebdSchin eob = cp + BUFSZ;
343da2e3ebdSchin }
344da2e3ebdSchin }
3451c7ddb37SRoger A. Faulkner funlockfile(fp);
346da2e3ebdSchin
347da2e3ebdSchin wptmp.we_wordp[wptmp.we_wordc] = NULL;
348da2e3ebdSchin
349da2e3ebdSchin free(line);
350da2e3ebdSchin (void) fclose(fp); /* kill shell if still writing */
351da2e3ebdSchin
352da2e3ebdSchin wait_cleanup:
3531c7ddb37SRoger A. Faulkner while (waitpid(pid, &status, 0) == -1) {
3541c7ddb37SRoger A. Faulkner if (errno != EINTR) {
3551c7ddb37SRoger A. Faulkner if (rv == 0)
3561c7ddb37SRoger A. Faulkner rv = WRDE_ERRNO;
3571c7ddb37SRoger A. Faulkner break;
3581c7ddb37SRoger A. Faulkner }
3591c7ddb37SRoger A. Faulkner }
3601c7ddb37SRoger A. Faulkner if (rv == 0)
361da2e3ebdSchin rv = WEXITSTATUS(status); /* shell WRDE_* status */
362da2e3ebdSchin
363da2e3ebdSchin cleanup:
364da2e3ebdSchin if (rv == 0)
365da2e3ebdSchin *wp = wptmp;
3661c7ddb37SRoger A. Faulkner else if (tmpalloc)
3671c7ddb37SRoger A. Faulkner wordfree(&wptmp);
368da2e3ebdSchin
3691c7ddb37SRoger A. Faulkner if (env)
3701c7ddb37SRoger A. Faulkner free(env);
3711c7ddb37SRoger A. Faulkner if (wd)
3721c7ddb37SRoger A. Faulkner free(wd);
373da2e3ebdSchin /*
3741c7ddb37SRoger A. Faulkner * Map ksh93 errors to |wordexp()| errors
375da2e3ebdSchin */
3761c7ddb37SRoger A. Faulkner switch (rv) {
3771c7ddb37SRoger A. Faulkner case 1:
3781c7ddb37SRoger A. Faulkner rv = WRDE_BADVAL;
3791c7ddb37SRoger A. Faulkner break;
3801c7ddb37SRoger A. Faulkner case 127:
3811c7ddb37SRoger A. Faulkner rv = WRDE_BADCHAR;
3821c7ddb37SRoger A. Faulkner break;
3831c7ddb37SRoger A. Faulkner }
384ec6bbcf8Sraf
385ec6bbcf8Sraf (void) pthread_setcancelstate(cancel_state, NULL);
386da2e3ebdSchin return (rv);
387da2e3ebdSchin }
388da2e3ebdSchin
3897c478bd9Sstevel@tonic-gate /*
390da2e3ebdSchin * Append a word to the wordexp_t structure, growing it as necessary.
3917c478bd9Sstevel@tonic-gate */
3927c478bd9Sstevel@tonic-gate static int
append(wordexp_t * wp,char * str)3937c478bd9Sstevel@tonic-gate append(wordexp_t *wp, char *str)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate char *cp;
3967c478bd9Sstevel@tonic-gate char **nwp;
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate * We will be adding one entry and later adding
4007c478bd9Sstevel@tonic-gate * one more NULL. So we need 2 more free slots.
4017c478bd9Sstevel@tonic-gate */
4027c478bd9Sstevel@tonic-gate if ((wp->we_wordp + wp->we_wordc) ==
403da2e3ebdSchin (wp->we_wordv + wp->we_wordn - 1)) {
4047c478bd9Sstevel@tonic-gate nwp = realloc(wp->we_wordv,
405da2e3ebdSchin (wp->we_wordn + INITIAL) * sizeof (char *));
4067c478bd9Sstevel@tonic-gate if (nwp == NULL)
4077c478bd9Sstevel@tonic-gate return (WRDE_NOSPACE);
4087c478bd9Sstevel@tonic-gate wp->we_wordn += INITIAL;
4097c478bd9Sstevel@tonic-gate wp->we_wordv = nwp;
4107c478bd9Sstevel@tonic-gate wp->we_wordp = wp->we_wordv + wp->we_offs;
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate if ((cp = strdup(str)) == NULL)
4137c478bd9Sstevel@tonic-gate return (WRDE_NOSPACE);
4147c478bd9Sstevel@tonic-gate wp->we_wordp[wp->we_wordc++] = cp;
4157c478bd9Sstevel@tonic-gate return (0);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate * Free all space owned by wordexp_t.
4207c478bd9Sstevel@tonic-gate */
4217c478bd9Sstevel@tonic-gate void
wordfree(wordexp_t * wp)4227c478bd9Sstevel@tonic-gate wordfree(wordexp_t *wp)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate size_t i;
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate if (wp->we_wordv == NULL)
4277c478bd9Sstevel@tonic-gate return;
4287c478bd9Sstevel@tonic-gate for (i = wp->we_offs; i < wp->we_offs + wp->we_wordc; i++)
4297c478bd9Sstevel@tonic-gate free(wp->we_wordv[i]);
4307c478bd9Sstevel@tonic-gate free((void *)wp->we_wordv);
4317c478bd9Sstevel@tonic-gate wp->we_wordc = 0;
4327c478bd9Sstevel@tonic-gate wp->we_wordv = NULL;
4337c478bd9Sstevel@tonic-gate }
434