2
* ***************************************************************************
3
* MALOC = < Minimal Abstraction Layer for Object-oriented C >
4
* Copyright (C) 1994--2000 Michael Holst
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License as published by the
8
* Free Software Foundation; either version 2 of the License, or (at your
9
* option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
* See the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License along
17
* with this program; if not, write to the Free Software Foundation, Inc.,
18
* 675 Mass Ave, Cambridge, MA 02139, USA.
20
* rcsid="$Id: vpup.c,v 1.8 2002/10/01 21:29:45 mholst Exp $"
21
* ***************************************************************************
25
* ***************************************************************************
28
* Purpose: Handle the following useful features of a shell like bash:
30
* (1) input/output redirection from/into files
31
* (2) pipes of arbitrary length and complexity
32
* (3) execv/execvp of the actual user commands
34
* Notes: These five routines were twisted somewhat from the examples
35
* in the book "Practical Unix Programming" by Robbins and Robbins.
36
* The five routines are:
38
* VPUBLIC Vpup_execCmd
39
* VPRIVATE Vpup_makeargv
40
* VPRIVATE Vpup_parseDelim
42
* VPRIVATE Vpup_connPipe
44
* Author: Michael Holst
45
* ***************************************************************************
51
VEMBED(rcsid="$Id: vpup.c,v 1.8 2002/10/01 21:29:45 mholst Exp $")
53
/* define VPUP_SHELL 1 */
55
#if !defined(HAVE_WINSOCK_H) && defined(VPUP_SHELL)
56
VPRIVATE int Vpup_makeargv(char *s, const char *delimiters, char ***argvp);
57
VPRIVATE int Vpup_parseDelim(char *s, char delimiter, char **v);
58
VPRIVATE int Vpup_reDir(char *infilename, char *outfilename);
59
VPRIVATE int Vpup_connPipe(char *cmd, int *frontfd, int *backfd);
63
* ***************************************************************************
64
* Class Vsig: Inlineable methods
65
* ***************************************************************************
67
#if !defined(VINLINE_MALOC)
69
#endif /* if !defined(VINLINE_MALOC) */
71
* ***************************************************************************
72
* Class Vsig: Non-inlineable methods
73
* ***************************************************************************
76
#if !defined(HAVE_WINSOCK_H) && defined(VPUP_SHELL)
78
* ***************************************************************************
79
* Routine: Vpup_execCmd
81
* Purpose: Execute a shell command.
83
* Author: Michael Holst
84
* ***************************************************************************
86
VPUBLIC void Vpup_execCmd(const char *PR, int argc, char **argv, char *inbuf)
101
if ((nextcmd = inbuf) == VNULL) exit(1);
106
if (cmd == VNULL) break;
108
/* if last in pipeline, do not fork another */
109
if ((nextcmd = strchr(nextcmd, VPIPE_SYMBOL)) == VNULL) {
113
/* else fork a child to execute next pipeline command */
115
*nextcmd = VNULL_SYMBOL;
117
if (pipe(backfd)== -1) {
120
} else if ((child_pid = fork()) == -1) {
126
/* the child execs the command */
127
if (child_pid == 0) {
128
if (Vpup_connPipe(cmd, frontfd, backfd) == -1) {
131
} else if (Vpup_makeargv(cmd, VBLANK_STRING, &chargv) > 0) {
132
if (execvp(chargv[0], chargv) == -1) {
134
/* Vnm_system("play sorry.au"); */
140
/* the parent closes front pipe and makes back pipe, front */
143
frontfd[0] = backfd[0];
144
frontfd[1] = backfd[1];
152
* ***************************************************************************
153
* Routine: Vpup_makeargv
155
* Purpose: Create a set of tokens from the input buffer.
157
* Author: Michael Holst
158
* ***************************************************************************
160
VPRIVATE int Vpup_makeargv(char *s, const char *delimiters, char ***argvp)
168
/* snew is real start of string after skipping leading delimiters */
169
snew = s + strspn(s, delimiters);
171
/* try to create space for a copy of snew in t */
172
if ((t = calloc(strlen(snew) + 1, sizeof(char))) == VNULL) {
176
/* if space creation successful, parse the string */
179
/* count the number of tokens in snew */
181
if (strtok(t, delimiters) == VNULL)
184
for (numtokens=1; strtok(VNULL,delimiters) != VNULL; numtokens++);
186
/* create an argument array to contain ptrs to tokens */
187
size = (unsigned int)(numtokens + 1);
188
if ((*argvp = calloc(size, sizeof(char *))) == VNULL) {
192
/* if successful, insert pointers to tokens into the array */
196
**argvp = strtok(t, delimiters);
197
for (i=1; i<numtokens+1; i++)
198
*((*argvp)+i) = strtok(VNULL, delimiters);
209
* ***************************************************************************
210
* Routine: Vpup_parseDelim
214
* Author: Michael Holst
215
* ***************************************************************************
217
VPRIVATE int Vpup_parseDelim(char *s, char delimiter, char **v)
224
/* Find position of the delimiting character */
226
if ((p = strchr(s, delimiter)) != NULL) {
228
/* Split off the token following delimiter */
229
if ((q = (char *)malloc(strlen(p + 1) + 1)) == NULL)
234
if ((*v = strtok(q, VDELIM_SET)) == NULL) error = -1;
236
strcpy(p, p + offset + 1);
243
* ***************************************************************************
244
* Routine: Vpup_reDir
246
* Purpose: Do a redirection.
248
* Author: Michael Holst
249
* ***************************************************************************
251
VPRIVATE int Vpup_reDir(char *infilename, char *outfilename)
256
/* redirect standard in to infilename */
257
if (infilename != VNULL) {
258
if ((indes = open(infilename, O_RDONLY, VSTDMODE)) == -1)
260
if (dup2(indes, STDIN_FILENO) == -1) {
267
/* redirect standard out to outfilename */
268
if (outfilename != VNULL) {
269
if ((outdes=open(outfilename,O_WRONLY|O_CREAT|O_TRUNC,VSTDMODE))==-1)
271
if (dup2(outdes, STDOUT_FILENO) == -1) {
281
* ***************************************************************************
282
* Routine: Vpup_connPipe
284
* Purpose: Connect up some pipes.
286
* Author: Michael Holst
287
* ***************************************************************************
289
VPRIVATE int Vpup_connPipe(char *cmd, int *frontfd, int *backfd)
292
char *infilename, *outfilename;
294
/* look for stdin redirect */
295
if (Vpup_parseDelim(cmd, VRDIN_SYMBOL, &infilename) == -1)
298
/* no redirection allowed at front of pipeline */
299
else if (infilename != VNULL && frontfd[0] != -1)
302
/* look for stdout redirect */
303
else if (Vpup_parseDelim(cmd, VRDOUT_SYMBOL, &outfilename) == -1)
306
/* no redirection allowed at back of pipeline */
307
else if (outfilename != VNULL && backfd[1] != -1)
310
/* do any required redirections */
311
else if (Vpup_reDir(infilename, outfilename) == -1)
314
/* now connect up appropriate pipes */
316
if (frontfd[0] != -1) {
317
if (dup2(frontfd[0], STDIN_FILENO) == -1)
320
if (backfd[1] != -1) {
321
if (dup2(backfd[1], STDOUT_FILENO) == -1)
326
/* close unneeded file descriptors */
336
* ***************************************************************************
337
* Routine: Vpup_execCmd
339
* Purpose: A simple shell command exec.
341
* Author: Michael Holst
342
* ***************************************************************************
344
VPUBLIC void Vpup_execCmd(const char *PR, int argc, char **argv, char *inbuf)
348
#endif /* if !defined(HAVE_WINSOCK_H) */