/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * This code is MKS code ported to Solaris originally with minimum * modifications so that upgrades from MKS would readily integrate. * The MKS basis for this modification was: * * $Id: wordexp.c 1.22 1994/11/21 18:24:50 miked * * Additional modifications have been made to this code to make it * 64-bit clean. */ /* * wordexp, wordfree -- POSIX.2 D11.2 word expansion routines. * * Copyright 1985, 1992 by Mortice Kern Systems Inc. All rights reserved. * Modified by Roland Mainz to support ksh93. * */ #pragma ident "%Z%%M% %I% %E% SMI" #pragma weak _wordexp = wordexp #pragma weak _wordfree = wordfree /* Safeguard against mistakes in the Makefiles */ #ifndef WORDEXP_KSH93 #error "WORDEXP_KSH93 not set. Please check the Makefile flags." #endif #include "lint.h" #include #include #include #include #include #include #if WORDEXP_KSH93 #include #endif /* WORDEXP_KSH93 */ #include #include #include #include #include #include #include #include #define INITIAL 8 /* initial pathv allocation */ #define BUFSZ 256 /* allocation unit of the line buffer */ /* Local prototypes */ static int append(wordexp_t *, char *); #if WORDEXP_KSH93 /* * |mystpcpy| - like |strcpy()| but returns the end of the buffer * We'll add this later (and a matching multibyte/widechar version) * as normal libc function. * * Copy string s2 to s1. s1 must be large enough. * return s1-1 (position of string terminator ('\0') in destination buffer). */ static char * mystpcpy(char *s1, const char *s2) { while (*s1++ = *s2++) ; return (s1-1); } /* * Do word expansion. * We built a mini-script in |buff| which takes care of all details, * including stdin/stdout/stderr redirection, WRDE_NOCMD mode and * the word expansion itself. */ int wordexp(const char *word, wordexp_t *wp, int flags) { char *args[10]; wordexp_t wptmp; size_t si; int i; pid_t pid; char *line, *eob, *cp; /* word from shell */ int rv = WRDE_ERRNO; int status; int pv[2]; /* pipe from shell stdout */ FILE *fp; /* pipe read stream */ int serrno, tmpalloc; int cancel_state; /* * Do absolute minimum necessary for the REUSE flag. Eventually * want to be able to actually avoid excessive malloc calls. */ if (flags & WRDE_REUSE) wordfree(wp); /* * Initialize wordexp_t * * XPG requires that the struct pointed to by wp not be modified * unless wordexp() either succeeds, or fails on WRDE_NOSPACE. * So we work with wptmp, and only copy wptmp to wp if one of the * previously mentioned conditions is satisfied. */ wptmp = *wp; /* * Man page says: * 2. All of the calls must set WRDE_DOOFFS, or all must not * set it. * Therefore, if it's not set, we_offs will always be reset. */ if ((flags & WRDE_DOOFFS) == 0) wptmp.we_offs = 0; /* * If we get APPEND|REUSE, how should we do? * We allocate the buffer anyway to avoid segfault. */ tmpalloc = 0; if ((flags & WRDE_APPEND) == 0 || (flags & WRDE_REUSE)) { wptmp.we_wordc = 0; wptmp.we_wordn = wptmp.we_offs + INITIAL; wptmp.we_wordv = (char **)malloc( sizeof (char *) * wptmp.we_wordn); if (wptmp.we_wordv == NULL) return (WRDE_NOSPACE); wptmp.we_wordp = wptmp.we_wordv + wptmp.we_offs; for (si = 0; si < wptmp.we_offs; si++) wptmp.we_wordv[si] = NULL; tmpalloc = 1; } /* * The UNIX98 Posix conformance test suite requires * wordexp() to not be a cancellation point. */ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); /* * Set up pipe from shell stdout to "fp" for us */ if (pipe(pv) < 0) goto cleanup; /* * Fork/exec shell */ if ((pid = fork()) == -1) { serrno = errno; (void) close(pv[0]); (void) close(pv[1]); errno = serrno; goto cleanup; } if (pid == 0) { /* child */ /* * Calculate size of required buffer (which is size of the * input string (|word|) plus all string literals below; * this value MUST be adjusted each time the literals are * changed!!!!). */ size_t bufflen = 124+strlen(word); /* Length of |buff| */ char *buff = alloca(bufflen); char *currbuffp; /* Current position of '\0' in |buff| */ int i; const char *path; (void) dup2(pv[1], 1); (void) close(pv[0]); (void) close(pv[1]); path = "/usr/bin/ksh93"; i = 0; /* Start filling the buffer */ buff[0] = '\0'; currbuffp = buff; if (flags & WRDE_UNDEF) currbuffp = mystpcpy(currbuffp, "set -o nounset ; "); if ((flags & WRDE_SHOWERR) == 0) { /* * The newline ('\n') is neccesary to make sure that * the redirection to /dev/null is already active in * the case the printf below contains a syntax * error... */ currbuffp = mystpcpy(currbuffp, "exec 2>/dev/null\n"); } /* Squish stdin */ currbuffp = mystpcpy(currbuffp, "exec 0we_wordp + wp->we_wordc) == (wp->we_wordv + wp->we_wordn - 1)) { nwp = realloc(wp->we_wordv, (wp->we_wordn + INITIAL) * sizeof (char *)); if (nwp == NULL) return (WRDE_NOSPACE); wp->we_wordn += INITIAL; wp->we_wordv = nwp; wp->we_wordp = wp->we_wordv + wp->we_offs; } if ((cp = strdup(str)) == NULL) return (WRDE_NOSPACE); wp->we_wordp[wp->we_wordc++] = cp; return (0); } /* * Free all space owned by wordexp_t. */ void wordfree(wordexp_t *wp) { size_t i; if (wp->we_wordv == NULL) return; for (i = wp->we_offs; i < wp->we_offs + wp->we_wordc; i++) free(wp->we_wordv[i]); free((void *)wp->we_wordv); wp->we_wordc = 0; wp->we_wordv = NULL; }