Tell CreateNewProc() not to close I/O streams when the detached program
[AROS.git] / compiler / startup / detach.c
blobda48e6ebb117d371ce7d0816371c697e9b1c2387
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Common startup code
6 Lang: english
8 Use: To make a program detach itself from the launching CLI, use
9 detach.o as your program's start file, before any other usual start
10 file.
12 If you want the detached process to have a name different than the
13 detacher's one, define the following variable in your program's
14 source code:
16 STRPTR __detached_name = "My Preferred Program Name";
18 You can also decide to control exactly when to detach your program
19 from the shell. To do so, simply use the function
21 Detach();
23 declared in
25 <aros/detach.h>
27 when you want to detach the program. Not using this function will
28 result in your program being detached from the shell before the main()
29 function is reached.
31 #define DEBUG 0
33 #include <aros/config.h>
34 #include <dos/dos.h>
35 #include <dos/stdio.h>
36 #include <proto/exec.h>
37 #include <proto/dos.h>
38 #include <aros/asmcall.h>
39 #include <aros/debug.h>
40 #include <aros/symbolsets.h>
41 #include <aros/startup.h>
43 int __detached_manages_detach;
44 int __detacher_go_away;
45 STRPTR __detached_name;
46 LONG __detached_return_value;
47 struct Process *__detacher_process;
49 AROS_UFP3S(LONG, __detach_trampoline,
50 AROS_UFPA(char *,argstr,A0),
51 AROS_UFPA(ULONG,argsize,D0),
52 AROS_UFPA(struct ExecBase *,SysBase,A6));
54 static void __startup_detach(struct ExecBase *SysBase)
56 struct CommandLineInterface *cli;
57 struct Process *newproc;
58 BPTR mysegment = BNULL;
59 STRPTR detached_name;
61 D(bug("Entering __startup_detach()\n"));
63 cli = Cli();
64 /* Without a CLI detaching makes no sense, just jump to
65 the real program. */
66 if (!cli)
68 D(bug("Wasn't started from cli.\n"));
69 __startup_entries_next();
71 else
73 D(bug("Was started from cli.\n"));
74 mysegment = cli->cli_Module;
75 cli->cli_Module = BNULL;
76 BPTR in, out;
78 detached_name = __detached_name ? __detached_name : (STRPTR) FindTask(NULL)->tc_Node.ln_Name;
80 in = OpenFromLock(DupLockFromFH(Input()));
81 out = OpenFromLock(DupLockFromFH(Output()));
82 if (IsInteractive(in))
83 SetVBuf(in, NULL, BUF_LINE, -1);
84 if (IsInteractive(out))
85 SetVBuf(out, NULL, BUF_LINE, -1);
88 struct TagItem tags[] =
90 { NP_Seglist, (IPTR)mysegment },
91 { NP_Entry, (IPTR)&__detach_trampoline },
92 { NP_Name, (IPTR)detached_name },
93 { NP_Arguments, (IPTR)__argstr },
94 { NP_Input, (IPTR)in },
95 { NP_CloseInput,FALSE },
96 { NP_Output, (IPTR)out },
97 { NP_CloseOutput,FALSE },
98 { NP_Cli, TRUE },
99 { TAG_DONE, 0 }
102 __detacher_process = (struct Process *)FindTask(NULL);
104 /* CreateNewProc() will take care of freeing the seglist */
105 newproc = CreateNewProc(tags);
108 D(bug("Process \"%s\" = 0x%x.\n", detached_name, newproc));
109 if (!newproc)
111 cli->cli_Module = mysegment;
112 __detached_return_value = RETURN_ERROR;
114 else
115 while (!__detacher_go_away) Wait(SIGF_SINGLE);
117 D(bug("__detached_return_value = %d.\n", __detached_return_value));
118 if (__detached_return_value != RETURN_OK)
120 PutStr(FindTask(NULL)->tc_Node.ln_Name); PutStr(": Failed to detach.\n");
123 if (newproc)
125 Forbid();
126 Signal(&newproc->pr_Task, SIGF_SINGLE);
129 __startup_error = __detached_return_value;
132 D(bug("Leaving __startup_detach\n"));
135 ADD2SET(__startup_detach, PROGRAM_ENTRIES, -100);
137 void __Detach(LONG retval);
139 AROS_ENTRY(LONG, __detach_trampoline,
140 AROS_UFHA(char *,argstr,A0),
141 AROS_UFHA(ULONG,argsize,D0),
142 struct ExecBase *,SysBase)
144 AROS_USERFUNC_INIT
146 LONG retval = RETURN_OK;
148 D(bug("Entering __detach_trampoline()\n"));
150 /* We have a CLI that is not 'attached' to a Shell,
151 * and to get WB 1.3's C:Status to list us properly,
152 * we need to set cli_Module to something.
154 Cli()->cli_Module = (BPTR)-1;
156 /* The program has two options: either take care of telling the detacher
157 process when exactly to go away, via the Detach() function, or let this
158 startup code take care of it. If __detached_manages_detach is TRUE, then
159 the detached process handles it, otherwise we handle it. */
161 if (!__detached_manages_detach)
162 __Detach(RETURN_OK);
164 __startup_entries_next();
166 /* At this point the detacher process might still be around,
167 If the program forgot to detach, or if it couldn't, but in any
168 case we need to tell the detacher to go away. */
169 __Detach(retval);
171 D(bug("Leaving __detach_trampoline\n"));
173 return 0;
175 AROS_USERFUNC_EXIT
178 void __Detach(LONG retval)
180 D(bug("Entering __Detach(%d)\n", retval));
182 if (__detacher_process != NULL)
184 __detached_return_value = retval;
185 __detacher_go_away = TRUE;
187 SetSignal(0, SIGF_SINGLE);
188 /* Tell the detacher process it can now go away */
189 Signal(&__detacher_process->pr_Task, SIGF_SINGLE);
191 /* Wait for it to say "goodbye" */
192 Wait(SIGF_SINGLE);
193 __detacher_process = NULL;
195 Close(Input());
196 SelectInput(BNULL);
197 Close(Output());
198 SelectOutput(BNULL);
201 D(bug("Leaving __Detach\n"));