tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / netlib / popen.c
blob7dd0e5f621db74072672a2af2b761e6ccf3da09f
1 /* $Id$
3 * popen.c - Unix comaptible popen() and pclose()
5 * Author: Rick Schaeffer <ricks@isc-br.isc-br.com>
6 * Pavel Fedin <sonic_amiga@rambler.ru>
7 */
9 /****** net.lib/popen *******************************************************
10 NAME
11 popen, pclose - initiate I/O to/from a process
13 SYNOPSIS
14 #include <stdio.h>
16 FILE *popen(command, type)
17 char *command, *type;
19 pclose(stream)
20 FILE *stream;
22 DESCRIPTION
23 The arguments to popen are pointers to null-terminated
24 strings containing respectively a command line and an
25 I/O mode, either "r" for reading or "w" for writing. It
26 creates a pipe between the calling process and the command
27 to be executed. The value returned is a stream pointer that
28 can be used (as appropriate) to write to the standard input
29 of the command or read from its standard output.
31 A stream opened by popen **MUST** be closed by pclose, which
32 waits for the associated process to terminate and returns
33 the exit status of the command.
35 Because stdio files are shared, a type "r" command may be
36 used as an input filter, and a type "w" as an output filter.
38 DIAGNOSTICS
39 Popen returns a null pointer if files or processes cannot be
40 created.
42 Pclose returns -1 if stream is not associated with a
43 `popened' command.
45 AUTHOR
46 Original version by Rick Schaeffer <ricks@isc-br.isc-br.com>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <stdarg.h>
54 #include <exec/types.h>
55 #include <exec/memory.h>
56 #include <dos/dos.h>
57 #include <dos/dosextens.h>
58 #include <dos/record.h>
59 #include <dos/dostags.h>
61 #include <proto/exec.h>
62 #include <proto/dos.h>
63 #include <clib/alib_protos.h>
65 #include <errno.h>
67 #include "conf.h"
69 extern char *mktemp(char *);
71 struct POmsg {
72 struct Message POm;
73 int rc;
74 char *cmd;
75 struct Library *DOSBase;
79 struct pstruct {
80 FILE *fptr;
81 struct POmsg childmsg;
84 #define MAXPIPES 6
85 static struct pstruct poarray[MAXPIPES];
87 static int childprocess(void);
89 FILE *popen(const char *cmd, const char *mode)
91 static char tempname[] = "pipe:pXXX.XXX";
92 char *pname,redir[20];
93 short i;
94 int pmode;
95 struct pstruct *poptr;
96 struct Process *child;
97 struct CommandLineInterface *cli;
98 ULONG stacksize;
99 struct Process *thistask;
100 FILE *fptr;
102 /* First, get pointers to our process and cli structs */
103 thistask = (struct Process *) FindTask(NULL);
104 cli = Cli();
105 poptr = NULL;
107 /* now find an open pipe (we currently only allow 6 simultaneously
108 open pipes) */
109 for (i=0; i<MAXPIPES; i++) {
110 if (poarray[i].fptr == NULL) {
111 poptr = &poarray[i];
112 break;
115 if (poptr == NULL) {
116 fprintf(stderr,"popen: Unable to find an open pipe\n");
117 errno = EMFILE;
118 return(NULL);
120 if (strcmp(mode,"r") == 0)
121 pmode = MODE_NEWFILE;
122 else if (strcmp(mode,"w") == 0)
123 pmode = MODE_OLDFILE;
124 else {
125 fprintf(stderr,"popen: Mode must be 'r' or 'w'\n");
126 errno = EINVAL;
127 return(NULL);
130 /* Try to make a guaranteed unique file name for the pipe */
131 strcpy(redir,tempname);
132 redir[5] = 'a' + i;
134 pname = mktemp(redir); /* set up a pipe: file name */
136 /* Now get the child's stack and priority set up */
137 if (cli)
138 stacksize = cli->cli_DefaultStack << 2;
139 else
140 stacksize = thistask->pr_StackSize;
142 /* Now open our side of the pipe */
143 fptr = fopen(pname,mode);
144 if (fptr == NULL) {
145 fprintf(stderr,"popen: Unable to open pipe file %s\n",pname);
146 return(NULL);
149 /* create the command. since the "System" function runs through
150 the default shell, we need to tell it not to fail so that we
151 ALWAYS get back the exit status. This wouldn't be necessary
152 if the CLI created by the System function inherited the parent's
153 FAILAT level.
154 The pipe file is passed as redirection to shell, which the
155 SystemTags() will parse. For some reason the default "more"
156 could not get it's input properly if redirection was not used.
158 poptr->childmsg.cmd = malloc(strlen(cmd) + 15 + 20);
159 sprintf(poptr->childmsg.cmd, "failat 9999\n%s %c%s\n",
160 cmd, (pmode == MODE_NEWFILE) ? '>' : '<', pname);
162 /* Create a port that we can get the child's exit status through */
163 poptr->childmsg.POm.mn_ReplyPort = CreateMsgPort();
164 poptr->childmsg.POm.mn_Node.ln_Type = NT_MESSAGE;
165 poptr->childmsg.POm.mn_Node.ln_Pri = 0;
166 if (poptr->childmsg.POm.mn_ReplyPort == 0) {
167 fclose(fptr);
168 fprintf(stderr,"popen: Couldn't create message port\n");
169 errno = ENOMEM;
170 return(NULL);
173 /* Now we can start the new process. NOTE: this is actually going
174 to create a process consisting ONLY of the function "childprocess"
175 which can be seen below. childprocess() then runs the command
176 passed in the startup message.
178 child = CreateNewProcTags(
179 NP_Entry, (IPTR) childprocess,
180 NP_Input, Input(),
181 NP_Output, Output(),
182 NP_CloseInput, FALSE,
183 NP_CloseOutput, FALSE,
184 NP_StackSize, stacksize,
185 NP_Cli, TRUE,
186 #ifdef __MORPHOS__
187 NP_CodeType, CODETYPE_PPC,
188 #endif
189 TAG_DONE
192 poptr->childmsg.DOSBase = (struct Library *)DOSBase;
194 /* now pass the child the startup message */
195 PutMsg(&child->pr_MsgPort,(struct Message *) &poptr->childmsg);
197 return(poptr->fptr = fptr);
200 FILE *popenl(const char *arg0, ...)
202 va_list ap;
203 char argbuf[512], *mode;
205 strcpy(argbuf, arg0);
206 va_start(ap, arg0);
207 while(1)
209 char *s = va_arg(ap, char *);
211 if(s == NULL)
213 strcat(argbuf, "\n");
214 break;
215 } /* if */
217 strcat(argbuf, " ");
219 if(strchr(s, ' '))
221 strcat(argbuf, "\"");
222 strcat(argbuf, s);
223 strcat(argbuf, "\"");
225 else
227 strcat(argbuf, s);
228 } /* if */
230 mode = va_arg(ap, char *);
231 va_end(ap);
233 return(popen(argbuf, mode));
235 } /* popenl */
237 int pclose(FILE *fptr)
239 short i;
241 /* Figure out which pipe we used for this file */
242 for (i=0; i<MAXPIPES; i++)
243 if (poarray[i].fptr == fptr)
244 break;
245 if (i >= MAXPIPES) {
246 fprintf(stderr,"popen: DISASTER...couldn't find file pointer in pclose\n");
247 exit(1);
250 /* close the file */
251 fclose(fptr);
253 /* now wait for the exit status */
254 WaitPort(poarray[i].childmsg.POm.mn_ReplyPort);
255 poarray[i].fptr = NULL;
257 /* clean things up */
258 DeletePort(poarray[i].childmsg.POm.mn_ReplyPort);
259 free(poarray[i].childmsg.cmd);
260 return(poarray[i].childmsg.rc);
263 /* SAS/C autoinitialization for cleanup! */
264 void STDARGS DESTRUCTOR _STD_4000_popen(void)
266 short i;
268 /* Close all the open pipes! */
269 for(i=0; i<MAXPIPES; i++)
271 if(poarray[i].fptr)
273 pclose(poarray[i].fptr);
274 } /* if */
275 } /* for */
277 } /* _STD_4000_popen */
279 char *mktemp(char * template)
281 register char *cp;
282 register unsigned long val;
283 BPTR lock;
285 cp = template;
286 cp += strlen(cp);
287 for (val = (unsigned long) FindTask(0L) ; ; )
288 if (*--cp == 'X') {
289 *cp = val%10 + '0';
290 val /= 10;
291 } else if (*cp != '.')
292 break;
294 if (*++cp != 0) {
295 *cp = 'A';
296 while (lock = Lock(template, ACCESS_READ))
298 UnLock(lock);
299 if (*cp == 'Z') {
300 *template = 0;
301 break;
303 ++*cp;
305 } else {
306 if (lock = Lock(template, ACCESS_READ)) {
307 UnLock(lock);
308 *template = 0;
311 return template;
314 /* WATCH OUT! This only works without __saveds because of the special
315 SAS/C 6.1 tricks I use! Check the output with omd! */
316 static int INTERRUPT childprocess(void)
318 struct ExecBase *SysBase = *((struct ExecBase **)4);
319 struct Library *DOSBase;
320 struct Process *me;
321 struct POmsg *startupmsg;
322 int i = RETURN_FAIL;
324 /* find our process structure */
325 me = (struct Process *) FindTask(NULL);
327 /* Wait for the parent to kick us off */
328 WaitPort(&me->pr_MsgPort);
330 /* Get the command to execute */
331 startupmsg = (struct POmsg *) GetMsg(&me->pr_MsgPort);
333 DOSBase = startupmsg->DOSBase;
335 if(DOSBase)
337 /* Now run the command. stdin and stdout are already set up */
338 i = SystemTags(startupmsg->cmd,
339 SYS_UserShell, 1,
340 TAG_DONE);
341 } /* if */
343 if(i > 0)
345 /* UNIX compatibility ... */
346 i <<= 8;
347 } /* if */
349 startupmsg->rc = i;
350 /* pass the exit code back to the parent */
351 ReplyMsg((struct Message *) startupmsg);
352 return(0);