Formerly ../hurd/hurdkill.c.~5~
[kopensolaris-gnu/glibc.git] / posix / wordexp.c
1 /* Copyright (C) 1992 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <sys/types.h>
21 #include <wordexp.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <sys/wait.h>
25 #include <signal.h>
26
27
28 /* We do word expansion with a pipe to the shell.
29    The shell command `sh [-P] [-u] -w "words ..."' expands words.
30    If -P, command substitution is an error.
31    If -u, reference to an undefined variable is an error.
32    The shell writes on its stdout:
33         %u\0    Number of words.
34         %u\0    Number of bytes in all words together (not counting \0s).
35         word1\0
36         word2\0
37         ...
38         wordN\0
39    */
40
41 #define SHELL_PATH      "/bin/sh"
42 #define SHELL_NAME      "sh"
43
44
45 int
46 DEFUN(wordexp, (string, pwordexp, flags),
47       CONST char *string AND wordexp_t *pwordexp AND int flags)
48 {
49   int error;
50   pid_t pid;
51   int d[2];
52   int status;
53
54   FILE *f;
55   size_t wordc, start, buflen;
56   char *buf;
57
58   /* Create the pipe through which we will communicate to the shell.  */
59   if (pipe (d) < 0)
60     return -1;
61
62   pid = fork ();
63   if (pid < 0)
64     return -1;
65
66   if (pid == 0)
67     {
68       /* Child.  Run the shell.  */
69
70       CONST char *argv[5];
71
72       close (d[STDIN_FILENO]);
73       dup2 (d[STDOUT_FILENO], STDOUT_FILENO);
74       if (!(flags & WRDE_SHOWERR))
75         close (STDERR_FILENO);
76
77       i = 0;
78       argv[i++] = SHELL_NAME;
79       if (flags & WRDE_NOCMD)
80         argv[i++] = "-P";
81       if (flags & WRDE_UNDEF)
82         argv[i++] = "-u";
83       argv[i++] = "-w";
84       argv[i++] = string;
85       argv[i++] = NULL;
86
87       execv (SHELL_PATH, argv);
88       _exit (WRDE_NOSPACE);
89     }
90
91   /* Parent.  */
92
93   buf = NULL;
94   error = WRDE_NOSPACE;
95
96   close (d[STDOUT_FILENO]);
97   f = fdopen (d[STDIN_FILENO]);
98   if (f == NULL)
99     goto lose;
100
101   /* Read the number of words and number of bytes from the shell.  */
102   if (fscanf (f, "%u", &wordc) != 1 || getc (f) != '\0' ||
103       fscanf (f, "%u", &buflen) != 1 || getc (f) != '\0')
104     goto lose;
105
106   /* Read the words from the shell, and wait for it to return.  */
107   buflen += wordc;
108   buf = malloc (buflen);
109   if (buf == NULL ||
110       fread (buf, buflen, 1, f) != 1 ||
111       waitpid (pid, &status, 0) != pid)
112     goto lose;
113
114   if (WIFEXITED (status))
115     {
116       if (WEXITSTATUS (status) != 0)
117         {
118           error = WEXITSTATUS (status);
119           goto lose;
120         }
121     }
122   else
123     goto lose;
124
125   /* Pack the structure.  */
126
127   start = 0;
128   if (flags & WRDE_DOOFFS)
129     start += pwordexp->we_offs;
130   if (flags & WRDE_APPEND)
131     start += pwordexp->we_wordc;
132   wordc = start + wordc + 1;
133
134   if (flags & WRDE_APPEND)
135     wordv = (char **) realloc ((PTR) pwordexp->we_wordv,
136                                wordc * sizeof (char *));
137   else
138     wordv = (char **) malloc (wordc * sizeof (char *));
139   if (wordv == NULL)
140     goto lose;
141
142   if (flags & WRDE_DOOFFS)
143     for (i = 0; i < pwordexp->we_offs; ++i)
144       wordv[i] = NULL;
145
146   for (i = start; i < wordc; ++i)
147     {
148       pwordexp->we_wordv[i] = buf;
149       buf = strchr (buf, '\0') + 1;
150     }
151   wordv[i] = NULL;
152
153   if (flags & WRDE_REUSE)
154     {
155       free (pwordexp->we_wordv[0]);
156       if (!(flags & WRDE_APPEND))
157         free (pwordexp->we_wordv);
158     }
159
160   pwordexp->we_wordc = wordc;
161   pwordexp->we_wordv = wordv;
162
163   return 0;
164
165  lose:
166   {
167     int save;
168     save = errno;
169     (void) kill (pid, SIGKILL);
170     free (buf);
171     (void) waitpid (pid, (int *) NULL, 0);
172     errno = save;
173     return error;
174   }
175 }
176
177
178 void
179 DEFUN(wordexp, (pwordexp), wordexp_t *pwordexp)
180 {
181   /* All the other elts point into the first.  */
182   free (pwordexp->we_wordv[0]);
183   free (pwordexp->we_wordv);
184 }