Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / posix / wordexp.c
blobdcda3d2f6caeb49b359a86b1ca197a129118e3a9
1 /* Copyright (C) 2002 by Red Hat, Incorporated. All rights reserved.
3 * Permission to use, copy, modify, and distribute this software
4 * is freely granted, provided that this notice is preserved.
5 */
6 #ifndef _NO_WORDEXP
8 #include <sys/param.h>
9 #include <sys/stat.h>
11 #include <ctype.h>
12 #include <dirent.h>
13 #include <errno.h>
14 #include <glob.h>
15 #include <pwd.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <sys/wait.h>
21 #include <sys/queue.h>
23 #include <wordexp.h>
24 #include "wordexp2.h"
26 #define MAXLINELEN 500
28 /* Note: This implementation of wordexp requires a version of bash
29 that supports the --wordexp and --protected arguments to be present
30 on the system. It does not support the WRDE_UNDEF flag. */
31 int
32 wordexp(const char *__restrict words, wordexp_t *__restrict pwordexp, int flags)
34 FILE *f = NULL;
35 FILE *f_err = NULL;
36 char tmp[MAXLINELEN];
37 int i = 0;
38 int offs = 0;
39 char *iter;
40 pid_t pid;
41 int num_words = 0;
42 int num_bytes = 0;
43 int fd[2];
44 int fd_err[2];
45 int err = WRDE_NOSPACE;
46 ext_wordv_t *wordv = NULL;
47 char *eword;
48 struct ewords_entry *entry;
50 if (pwordexp == NULL)
52 return WRDE_NOSPACE;
55 if (flags & WRDE_REUSE)
56 wordfree(pwordexp);
58 if ((flags & WRDE_APPEND) == 0)
60 pwordexp->we_wordc = 0;
61 pwordexp->we_wordv = NULL;
64 if (flags & WRDE_DOOFFS)
66 offs = pwordexp->we_offs;
68 if (pwordexp->we_wordv)
69 wordv = WE_WORDV_TO_EXT_WORDV(pwordexp->we_wordv);
70 wordv = (ext_wordv_t *)realloc(wordv, sizeof(ext_wordv_t) + (offs + pwordexp->we_wordc) * sizeof(char *));
71 if (!wordv)
72 return err;
73 if (!pwordexp->we_wordv)
74 SLIST_INIT(&wordv->list);
75 pwordexp->we_wordv = wordv->we_wordv;
77 for (i = 0; i < offs; i++)
78 pwordexp->we_wordv[i] = NULL;
81 if (pipe(fd))
82 return err;
83 if (pipe(fd_err))
85 close(fd[0]);
86 close(fd[1]);
87 return err;
89 pid = fork();
91 if (pid == -1)
93 /* In "parent" process, but fork failed */
94 close(fd_err[0]);
95 close(fd_err[1]);
96 close(fd[0]);
97 close(fd[1]);
98 return err;
100 else if (pid > 0)
102 /* In parent process. */
104 /* Close write end of parent's pipe. */
105 close(fd[1]);
106 close(fd_err[1]);
108 /* f_err is the standard error from the shell command. */
109 if (!(f_err = fdopen(fd_err[0], "r")))
110 goto cleanup;
112 /* Check for errors. */
113 if (fgets(tmp, MAXLINELEN, f_err))
115 if (strstr(tmp, "EOF"))
116 err = WRDE_SYNTAX;
117 else if (strstr(tmp, "`\n'") || strstr(tmp, "`|'")
118 || strstr(tmp, "`&'") || strstr(tmp, "`;'")
119 || strstr(tmp, "`<'") || strstr(tmp, "`>'")
120 || strstr(tmp, "`('") || strstr(tmp, "`)'")
121 || strstr(tmp, "`{'") || strstr(tmp, "`}'"))
122 err = WRDE_BADCHAR;
123 else if (strstr(tmp, "command substitution"))
124 err = WRDE_CMDSUB;
125 else
126 err = WRDE_SYNTAX;
128 if (flags & WRDE_SHOWERR)
130 fputs(tmp, stderr);
131 while(fgets(tmp, MAXLINELEN, f_err))
132 fputs(tmp, stderr);
135 goto cleanup;
138 /* f is the standard output from the shell command. */
139 if (!(f = fdopen(fd[0], "r")))
140 goto cleanup;
142 /* Get number of words expanded by shell. */
143 if (!fgets(tmp, MAXLINELEN, f))
144 goto cleanup;
146 if((iter = strchr(tmp, '\n')))
147 *iter = '\0';
149 num_words = atoi(tmp);
151 if (pwordexp->we_wordv)
152 wordv = WE_WORDV_TO_EXT_WORDV(pwordexp->we_wordv);
153 wordv = (ext_wordv_t *)realloc(wordv, sizeof(ext_wordv_t) + (offs + pwordexp->we_wordc + num_words) * sizeof(char *));
154 if (!wordv)
155 return err;
156 if (!pwordexp->we_wordv)
157 SLIST_INIT(&wordv->list);
158 pwordexp->we_wordv = wordv->we_wordv;
160 /* Get number of bytes required for storage of all num_words words. */
161 if (!fgets(tmp, MAXLINELEN, f))
162 goto cleanup;
164 if((iter = strchr(tmp, '\n')))
165 *iter = '\0';
167 num_bytes = atoi(tmp);
169 if (!(entry = (struct ewords_entry *)malloc(sizeof(struct ewords_entry) + num_bytes + num_words)))
170 goto cleanup;
171 SLIST_INSERT_HEAD(&wordv->list, entry, next);
173 /* Get expansion from the shell output. */
174 if (!fread(entry->ewords, 1, num_bytes + num_words, f))
175 goto cleanup;
176 entry->ewords[num_bytes + num_words] = 0;
178 /* Store each entry in pwordexp's we_wordv vector. */
179 eword = entry->ewords;
180 for(i = 0; i < num_words; i++, eword = iter)
182 if (!eword)
183 break;
184 pwordexp->we_wordv[offs + pwordexp->we_wordc + i] = eword;
185 if ((iter = strchr(eword, '\n')))
186 *iter++ = '\0';
189 pwordexp->we_wordv[offs + pwordexp->we_wordc + i] = NULL;
190 pwordexp->we_wordc += num_words;
191 if (i == num_words)
192 err = WRDE_SUCCESS;
194 cleanup:
195 if (f)
196 fclose(f);
197 else
198 close(fd[0]);
199 if (f_err)
200 fclose(f_err);
201 else
202 close(fd_err[0]);
204 /* Wait for child to finish. */
205 waitpid (pid, NULL, 0);
207 return err;
209 else
211 /* In child process. */
213 /* Close read end of child's pipe. */
214 close(fd[0]);
215 close(fd_err[0]);
217 /* Pipe standard output to parent process via fd. */
218 if (fd[1] != STDOUT_FILENO)
220 if (dup2(fd[1], STDOUT_FILENO) == -1)
221 _exit(EXIT_FAILURE);
222 /* fd[1] no longer required. */
223 close(fd[1]);
226 /* Pipe standard error to parent process via fd_err. */
227 if (fd_err[1] != STDERR_FILENO)
229 if (dup2(fd_err[1], STDERR_FILENO) == -1)
230 _exit(EXIT_FAILURE);
231 /* fd_err[1] no longer required. */
232 close(fd_err[1]);
235 if (flags & WRDE_NOCMD)
236 execl("/bin/bash", "bash", "--protected", "--wordexp", words, (char *)0);
237 else
238 execl("/bin/bash", "bash", "--wordexp", words, (char *)0);
239 _exit(EXIT_FAILURE);
241 return WRDE_SUCCESS;
243 #endif /* !_NO_WORDEXP */