2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
9 #include <aros/debug.h>
10 #include <utility/tagitem.h>
11 #include <dos/dostags.h>
12 #include <proto/utility.h>
13 #include <dos/dosextens.h>
14 #include <aros/asmcall.h>
15 #include <exec/ports.h>
17 #include "dos_newcliproc.h"
18 #include "dos_intern.h"
19 #include "fs_driver.h"
21 /*****************************************************************************
25 #include <proto/dos.h>
27 AROS_LH2(LONG
, SystemTagList
,
30 AROS_LHA(CONST_STRPTR
, command
, D1
),
31 AROS_LHA(struct TagItem
*, tags
, D2
),
34 struct DosLibrary
*, DOSBase
, 101, Dos
)
37 Execute a command via a shell. As defaults, the process will use the
38 current Input() and Output(), and the current directory as well as the
39 path will be inherited from your process. If no path is specified, this
40 path will be used to find the command.
42 Normally, the boot shell is used but other shells may be specified
43 via tags. The tags are passed through to CreateNewProc() except those
44 that conflict with SystemTagList(). Currently, these are
62 command - program and arguments as a string
63 tags - see <dos/dostags.h>. Note that both SystemTagList() tags and
64 tags for CreateNewProc() may be passed.
67 The return code of the command executed or -1 if the command could
68 not run because the shell couldn't be created. If the command is not
69 found, the shell will return an error code, usually RETURN_ERROR.
72 You must close the input and output filehandles yourself (if needed)
73 after System() returns if they were specified via SYS_Input or
74 SYS_Output (also, see below).
76 You may NOT use the same filehandle for both SYS_Input and SYS_Output.
77 If you want them to be the same CON: window, set SYS_Input to a
78 filehandle on the CON: window and set SYS_Output to NULL. Then the
79 shell will automatically set the output by opening CONSOLE: on that
82 If you specified SYS_Asynch, both the input and the output filehandles
83 will be closed when the command is finished (even if this was your
84 Input() and Output()).
91 Execute(), CreateNewProc(), Input(), Output(), <dos/dostags.h>
95 *****************************************************************************/
99 struct Process
*me
= (struct Process
*)FindTask(NULL
);
104 BPTR shellseg
= BNULL
;
105 STRPTR resShell
= BNULL
;
106 STRPTR shellName
= "Custom Shell";
108 BOOL sis_opened
= FALSE
;
109 BOOL cis_opened
= FALSE
;
110 BOOL sos_opened
= FALSE
;
111 BOOL ses_opened
= FALSE
;
113 BOOL isCLI
= TRUE
; /* Default is BCPL compatible CLI */
115 BOOL isCLI
= FALSE
; /* Default is C style Shell */
118 BOOL isCustom
= FALSE
;
119 BOOL isAsynch
= FALSE
;
120 BOOL isBackground
= TRUE
;
121 LONG cliType
= CLI_INVALID
;
125 struct TagItem
*tags2
= tags
;
126 struct TagItem
*newtags
, *tag
;
128 ASSERT_VALID_PROCESS(me
);
129 D(bug("SystemTagList('%s',%p)\n", command
, tags
));
134 while ((tag
= NextTagItem(&tags2
)))
136 D(bug("Tag=%08x Data=%08x\n", tag
->ti_Tag
, tag
->ti_Data
));
139 case SYS_ScriptInput
:
140 cis
= (BPTR
)tag
->ti_Data
;
144 sis
= (BPTR
)tag
->ti_Data
;
148 sos
= (BPTR
)tag
->ti_Data
;
152 ses
= (BPTR
)tag
->ti_Data
;
155 case SYS_CustomShell
:
156 resShell
= (STRPTR
)tag
->ti_Data
;
162 isBoot
= !tag
->ti_Data
;
167 isAsynch
= tag
->ti_Data
? TRUE
: FALSE
;
171 isBackground
= tag
->ti_Data
? TRUE
: FALSE
;
175 cliType
= (LONG
)tag
->ti_Data
;
180 /* Validate cliType */
188 isBackground
= FALSE
;
192 isBackground
= FALSE
;
202 cliType
= isAsynch
? CLI_ASYSTEM
: CLI_SYSTEM
;
204 cliType
= isAsynch
? CLI_NEWCLI
: CLI_BOOT
;
211 /* Set up the streams */
212 if (sis
== (BPTR
)SYS_DupStream
)
214 sis
= OpenFromLock(DupLockFromFH(Input()));
220 sis
= Open("NIL:", MODE_OLDFILE
);
225 D(bug("[SystemTagList] cli_StandardInput: %p\n", sis
));
227 if (cis
== BNULL
|| cis
== (BPTR
)SYS_DupStream
)
229 D(bug("[SystemTagList] cli_CurrentInput: %p\n", cis
));
231 if (sos
== (BPTR
)SYS_DupStream
)
233 sos
= OpenFromLock(DupLockFromFH(Output()));
238 D(bug("[SystemTagList] cli_StandardOutput: %p\n", sos
));
240 if (ses
== (BPTR
)SYS_DupStream
)
242 ses
= OpenFromLock(DupLockFromFH(me
->pr_CES
));
247 D(bug("[SystemTagList] cli_StandardError: %p\n", ses
));
249 /* Inject the arguments, adding a trailing '\n'
250 * if the user did not.
255 commandlen
= strlen(command
);
257 STRPTR cmdcopy
= NULL
;
260 if (command
[commandlen
-1] != '\n') {
261 cmdcopy
= AllocVec(commandlen
+ 2, MEMF_ANY
);
262 CopyMem(command
, cmdcopy
, commandlen
);
263 cmdcopy
[commandlen
++] = '\n';
264 cmdcopy
[commandlen
] = 0;
268 ok
= vbuf_inject(cis
, command
, commandlen
, DOSBase
);
277 /* Seglist of default shell is stored in RootNode when loaded */
278 D(bug("[SystemTagList] Loading standard %s\n", isCLI
? "CLI" : "shell"));
280 shellseg
= findseg_cli(isBoot
, DOSBase
);
282 shellseg
= findseg_shell(isBoot
, DOSBase
);
284 * Set shell process name.
290 } else if (resShell
!= BNULL
) {
293 /* Get the custom shell from the DOS resident list */
294 D(bug("[SystemTagList] Loading custom shell\n"));
296 seg
= FindSegment(resShell
, NULL
, TRUE
);
298 shellseg
= seg
->seg_Seg
;
301 shellName
= resShell
;
304 if (!shellseg
&& isCLI
) {
305 /* We wanted the CLI shell, but it's not available.
306 * Let's try to use the Shell instead.
308 D(bug("[SystemTagList] No CLI. Attempting to use shell instead\n"));
309 shellseg
= findseg_shell(isBoot
, DOSBase
);
314 D(bug("[SystemTagList] No shell available\n"));
321 D(bug("[SystemTagList] BCPL 'CLI' shell selected\n"));
322 /* On the m68k AOS, the "CLI" shell was always a BCPL
323 * program, that ran like a BCPL DOS packet handler.
325 extern void BCPL_RunHandler(void);
326 entry
= BCPL_RunHandler
;
331 D(bug("[SystemTagList] C 'shell' shell selected\n"));
332 /* Use the standard C entry point */
336 newtags
= CloneTagItems(tags
);
339 struct Process
*cliproc
;
341 struct TagItem proctags
[] =
343 { NP_Priority
, me
->pr_Task
.tc_Node
.ln_Pri
}, /* 0 */
344 { NP_Name
, (IPTR
)shellName
}, /* 1 */
345 { NP_Input
, (IPTR
)BNULL
}, /* 2 */
346 { NP_Output
, (IPTR
)BNULL
}, /* 3 */
347 { NP_Error
, (IPTR
)ses
}, /* 4 */
348 { NP_CloseInput
, FALSE
}, /* 5 */
349 { NP_CloseOutput
, FALSE
}, /* 6 */
350 { NP_CloseError
, (isAsynch
|| ses_opened
)
351 ? TRUE
: FALSE
, }, /* 7 */
352 { NP_Cli
, ((cliType
== CLI_NEWCLI
) || (cliType
== CLI_ASYSTEM
))
353 ? TRUE
: FALSE
}, /* 8 */
354 { NP_WindowPtr
, isAsynch
? (IPTR
)NULL
:
355 (IPTR
)me
->pr_WindowPtr
}, /* 9 */
356 { NP_Seglist
, (IPTR
)shellseg
}, /* 10 */
357 { NP_FreeSeglist
, FALSE
}, /* 11 */
358 { NP_Synchronous
, FALSE
}, /* 12 */
359 { NP_Entry
, (IPTR
)entry
}, /* 13 */
360 { NP_CurrentDir
, (IPTR
)BNULL
}, /* 14 */
361 { NP_ConsoleTask
, (IPTR
)BNULL
, }, /* 15 */
362 { TAG_END
, 0 } /* 16 */
383 struct DosPacket
*dp
;
385 FilterTagItems(newtags
, filterList
, TAGFILTER_NOT
);
387 proctags
[sizeof(proctags
)/(sizeof(proctags
[0])) - 1].ti_Tag
= TAG_MORE
;
388 proctags
[sizeof(proctags
)/(sizeof(proctags
[0])) - 1].ti_Data
= (IPTR
)newtags
;
390 dp
= AllocDosObject(DOS_STDPKT
, NULL
);
392 cliproc
= CreateNewProc(proctags
);
397 struct FileHandle
*fh
= NULL
;
399 D(bug("[SystemTagList] cliType = %d (background=%d, asynch=%d)\n", cliType
, isBackground
, isAsynch
));
401 /* Trickery needed for BCPL user shells.
402 * This is needed for the trimmed AROS m68k
403 * ROMs that don't have shell.resource, and
404 * load the CLI from a BCPL L:Shell-Seg, like
405 * the one on Workbench 1.3
408 extern void BCPL_CliInit_NEWCLI(void);
409 extern void BCPL_CliInit_RUN(void);
410 extern void BCPL_CliInit_SYSTEM(void);
411 extern void BCPL_CliInit_ASYSTEM(void);
412 extern void BCPL_CliInit_SYSTEM(void);
413 extern void BCPL_CliInit_BOOT(void);
415 case CLI_NEWCLI
: dp
->dp_Type
= (LONG
)BCPL_CliInit_NEWCLI
; break;
416 case CLI_RUN
: dp
->dp_Type
= (LONG
)BCPL_CliInit_RUN
; break;
417 case CLI_SYSTEM
: dp
->dp_Type
= (LONG
)BCPL_CliInit_SYSTEM
; break;
418 case CLI_ASYSTEM
: dp
->dp_Type
= (LONG
)BCPL_CliInit_ASYSTEM
; break;
419 case CLI_BOOT
: dp
->dp_Type
= (LONG
)BCPL_CliInit_BOOT
; break;
422 } else /* Fallthough to the next line for user shells */
424 dp
->dp_Type
= cliType
;
426 dp
->dp_Arg2
= (IPTR
)sis
; /* Input */
427 dp
->dp_Arg3
= (IPTR
)sos
; /* Output */
428 dp
->dp_Arg4
= (IPTR
)cis
; /* Arguments & Script*/
430 /* The rest of the packet depends on the cliType. */
431 if (cliType
== CLI_NEWCLI
) {
432 /* CliInitNewcli style */
434 dp
->dp_Arg1
= (IPTR
)(me
->pr_CurrentDir
? DupLock(me
->pr_CurrentDir
) : BNULL
);
436 /* CliInitRun style */
438 dp
->dp_Arg1
= (IPTR
)(__is_process(me
) ? MKBADDR(Cli()) : BNULL
);
439 dp
->dp_Arg5
= (IPTR
)(me
->pr_CurrentDir
? DupLock(me
->pr_CurrentDir
) : BNULL
);
443 /* Migrate the CIS handle to the new process */
444 if (!isAsynch
&& IsInteractive(sis
)) {
447 if (dopacket(&oldSignal
, fh
->fh_Type
, ACTION_CHANGE_SIGNAL
, (SIPTR
)fh
->fh_Arg1
, (SIPTR
)&cliproc
->pr_MsgPort
, 0, 0, 0, 0, 0) == DOSFALSE
)
451 SendPkt(dp
, &cliproc
->pr_MsgPort
, &me
->pr_MsgPort
);
455 if (fh
&& oldSignal
) {
456 DoPkt(fh
->fh_Type
, ACTION_CHANGE_SIGNAL
, (SIPTR
)fh
->fh_Arg1
, oldSignal
, 0, 0, 0);
460 SetIoErr(dp
->dp_Res2
);
470 FreeDosObject(DOS_STDPKT
, dp
);
472 FreeTagItems(newtags
);
476 if (sis_opened
) Close(sis
);
477 if (cis_opened
) Close(cis
);
478 if (sos_opened
) Close(sos
);
479 if (ses_opened
) Close(ses
);
484 } /* SystemTagList */