2 Copyright © 1995-2016, 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
80 handler. Note that SYS_Error also follows this rule, so passing it
81 set to NULL will automatically set the error by opening CONSOLE: on
84 If you specified SYS_Asynch, both the input and the output filehandles
85 will be closed when the command is finished (even if this was your
86 Input() and Output()).
93 Execute(), CreateNewProc(), Input(), Output(), <dos/dostags.h>
97 *****************************************************************************/
101 struct Process
*me
= (struct Process
*)FindTask(NULL
);
106 BPTR shellseg
= BNULL
;
107 STRPTR resShell
= BNULL
;
108 STRPTR shellName
= "Custom Shell";
110 BOOL sis_opened
= FALSE
;
111 BOOL cis_opened
= FALSE
;
112 BOOL sos_opened
= FALSE
;
113 BOOL ses_opened
= FALSE
;
115 BOOL isCLI
= TRUE
; /* Default is BCPL compatible CLI */
117 BOOL isCLI
= FALSE
; /* Default is C style Shell */
120 BOOL isCustom
= FALSE
;
121 BOOL isAsynch
= FALSE
;
122 BOOL isBackground
= TRUE
;
123 LONG cliType
= CLI_INVALID
;
127 struct TagItem
*tags2
= tags
;
128 struct TagItem
*newtags
, *tag
;
130 ASSERT_VALID_PROCESS(me
);
131 D(bug("SystemTagList('%s',%p)\n", command
, tags
));
136 while ((tag
= NextTagItem(&tags2
)))
138 D(bug("Tag=%08x Data=%08x\n", tag
->ti_Tag
, tag
->ti_Data
));
141 case SYS_ScriptInput
:
142 cis
= (BPTR
)tag
->ti_Data
;
146 sis
= (BPTR
)tag
->ti_Data
;
150 sos
= (BPTR
)tag
->ti_Data
;
154 ses
= (BPTR
)tag
->ti_Data
;
157 case SYS_CustomShell
:
158 resShell
= (STRPTR
)tag
->ti_Data
;
164 isBoot
= !tag
->ti_Data
;
169 isAsynch
= tag
->ti_Data
? TRUE
: FALSE
;
173 isBackground
= tag
->ti_Data
? TRUE
: FALSE
;
177 cliType
= (LONG
)tag
->ti_Data
;
182 /* Validate cliType */
190 isBackground
= FALSE
;
194 isBackground
= FALSE
;
204 cliType
= isAsynch
? CLI_ASYSTEM
: CLI_SYSTEM
;
206 cliType
= isAsynch
? CLI_NEWCLI
: CLI_BOOT
;
213 /* Set up the streams */
214 if (sis
== (BPTR
)SYS_DupStream
)
216 sis
= OpenFromLock(DupLockFromFH(Input()));
222 sis
= Open("NIL:", MODE_OLDFILE
);
227 D(bug("[SystemTagList] cli_StandardInput: %p\n", sis
));
229 if (cis
== BNULL
|| cis
== (BPTR
)SYS_DupStream
)
231 D(bug("[SystemTagList] cli_CurrentInput: %p\n", cis
));
233 if (sos
== (BPTR
)SYS_DupStream
)
235 sos
= OpenFromLock(DupLockFromFH(Output()));
240 D(bug("[SystemTagList] cli_StandardOutput: %p\n", sos
));
242 if (ses
== (BPTR
)SYS_DupStream
)
244 ses
= OpenFromLock(DupLockFromFH(me
->pr_CES
));
249 D(bug("[SystemTagList] cli_StandardError: %p\n", ses
));
251 /* Inject the arguments, adding a trailing '\n'
252 * if the user did not.
257 commandlen
= strlen(command
);
259 STRPTR cmdcopy
= NULL
;
262 if (command
[commandlen
-1] != '\n') {
263 cmdcopy
= AllocVec(commandlen
+ 2, MEMF_ANY
);
264 CopyMem(command
, cmdcopy
, commandlen
);
265 cmdcopy
[commandlen
++] = '\n';
266 cmdcopy
[commandlen
] = 0;
270 ok
= vbuf_inject(cis
, command
, commandlen
, DOSBase
);
279 /* Seglist of default shell is stored in RootNode when loaded */
280 D(bug("[SystemTagList] Loading standard %s\n", isCLI
? "CLI" : "shell"));
282 shellseg
= findseg_cli(isBoot
, DOSBase
);
284 shellseg
= findseg_shell(isBoot
, DOSBase
);
286 * Set shell process name.
292 } else if (resShell
!= BNULL
) {
295 /* Get the custom shell from the DOS resident list */
296 D(bug("[SystemTagList] Loading custom shell\n"));
298 seg
= FindSegment(resShell
, NULL
, TRUE
);
300 shellseg
= seg
->seg_Seg
;
303 shellName
= resShell
;
306 if (!shellseg
&& isCLI
) {
307 /* We wanted the CLI shell, but it's not available.
308 * Let's try to use the Shell instead.
310 D(bug("[SystemTagList] No CLI. Attempting to use shell instead\n"));
311 shellseg
= findseg_shell(isBoot
, DOSBase
);
316 D(bug("[SystemTagList] No shell available\n"));
323 D(bug("[SystemTagList] BCPL 'CLI' shell selected\n"));
324 /* On the m68k AOS, the "CLI" shell was always a BCPL
325 * program, that ran like a BCPL DOS packet handler.
327 extern void BCPL_RunHandler(void);
328 entry
= BCPL_RunHandler
;
333 D(bug("[SystemTagList] C 'shell' shell selected\n"));
334 /* Use the standard C entry point */
338 newtags
= CloneTagItems(tags
);
341 struct Process
*cliproc
;
343 /* Note: SystemTagList + CliInitNewcli/CliInitRun + AROS_CLI macro manage
344 * the creation and destruction of pr_CIS/pr_COS/pr_CES. CreateNewProc
345 * logic is not used in such case.
347 struct TagItem proctags
[] =
349 { NP_Priority
, me
->pr_Task
.tc_Node
.ln_Pri
}, /* 0 */
350 { NP_Name
, (IPTR
)shellName
}, /* 1 */
351 { NP_Input
, (IPTR
)BNULL
}, /* 2 */
352 { NP_Output
, (IPTR
)BNULL
}, /* 3 */
353 { NP_Error
, (IPTR
)BNULL
}, /* 4 */
354 { NP_CloseInput
, FALSE
}, /* 5 */
355 { NP_CloseOutput
, FALSE
}, /* 6 */
356 { NP_CloseError
, FALSE
}, /* 7 */
357 { NP_Cli
, ((cliType
== CLI_NEWCLI
) || (cliType
== CLI_ASYSTEM
))
358 ? TRUE
: FALSE
}, /* 8 */
359 { NP_WindowPtr
, isAsynch
? (IPTR
)NULL
:
360 (IPTR
)me
->pr_WindowPtr
}, /* 9 */
361 { NP_Seglist
, (IPTR
)shellseg
}, /* 10 */
362 { NP_FreeSeglist
, FALSE
}, /* 11 */
363 { NP_Synchronous
, FALSE
}, /* 12 */
364 { NP_Entry
, (IPTR
)entry
}, /* 13 */
365 { NP_CurrentDir
, (IPTR
)BNULL
}, /* 14 */
366 { NP_ConsoleTask
, (IPTR
)BNULL
, }, /* 15 */
367 { TAG_END
, 0 } /* 16 */
388 struct DosPacket
*dp
;
390 FilterTagItems(newtags
, filterList
, TAGFILTER_NOT
);
392 proctags
[sizeof(proctags
)/(sizeof(proctags
[0])) - 1].ti_Tag
= TAG_MORE
;
393 proctags
[sizeof(proctags
)/(sizeof(proctags
[0])) - 1].ti_Data
= (IPTR
)newtags
;
395 dp
= AllocDosObject(DOS_STDPKT
, NULL
);
397 cliproc
= CreateNewProc(proctags
);
402 struct FileHandle
*fh
= NULL
;
403 struct ExtArg
*ea
= AllocMem(sizeof(struct ExtArg
), MEMF_PUBLIC
| MEMF_CLEAR
);
406 if (isAsynch
|| ses_opened
)
407 ea
->ea_Flags
|= EAF_CLOSECES
;
409 D(bug("[SystemTagList] cliType = %d (background=%d, asynch=%d)\n", cliType
, isBackground
, isAsynch
));
411 /* Trickery needed for BCPL user shells.
412 * This is needed for the trimmed AROS m68k
413 * ROMs that don't have shell.resource, and
414 * load the CLI from a BCPL L:Shell-Seg, like
415 * the one on Workbench 1.3
418 extern void BCPL_CliInit_NEWCLI(void);
419 extern void BCPL_CliInit_RUN(void);
420 extern void BCPL_CliInit_SYSTEM(void);
421 extern void BCPL_CliInit_ASYSTEM(void);
422 extern void BCPL_CliInit_SYSTEM(void);
423 extern void BCPL_CliInit_BOOT(void);
425 case CLI_NEWCLI
: dp
->dp_Type
= (LONG
)BCPL_CliInit_NEWCLI
; break;
426 case CLI_RUN
: dp
->dp_Type
= (LONG
)BCPL_CliInit_RUN
; break;
427 case CLI_SYSTEM
: dp
->dp_Type
= (LONG
)BCPL_CliInit_SYSTEM
; break;
428 case CLI_ASYSTEM
: dp
->dp_Type
= (LONG
)BCPL_CliInit_ASYSTEM
; break;
429 case CLI_BOOT
: dp
->dp_Type
= (LONG
)BCPL_CliInit_BOOT
; break;
432 } else /* Fallthough to the next line for user shells */
434 dp
->dp_Type
= cliType
;
436 dp
->dp_Arg2
= (IPTR
)sis
; /* Input */
437 dp
->dp_Arg3
= (IPTR
)sos
; /* Output */
438 dp
->dp_Arg7
= (IPTR
)ea
; /* AROS extension information*/
439 dp
->dp_Arg4
= (IPTR
)cis
; /* Arguments & Script*/
441 /* The rest of the packet depends on the cliType. */
442 if (cliType
== CLI_NEWCLI
) {
443 /* CliInitNewcli style */
445 dp
->dp_Arg1
= (IPTR
)(me
->pr_CurrentDir
? DupLock(me
->pr_CurrentDir
) : BNULL
);
447 /* CliInitRun style */
449 dp
->dp_Arg1
= (IPTR
)(__is_process(me
) ? MKBADDR(Cli()) : BNULL
);
450 dp
->dp_Arg5
= (IPTR
)(me
->pr_CurrentDir
? DupLock(me
->pr_CurrentDir
) : BNULL
);
454 /* Migrate the CIS handle to the new process */
455 if (!isAsynch
&& IsInteractive(sis
)) {
458 if (dopacket(&oldSignal
, fh
->fh_Type
, ACTION_CHANGE_SIGNAL
, (SIPTR
)fh
->fh_Arg1
, (SIPTR
)&cliproc
->pr_MsgPort
, 0, 0, 0, 0, 0) == DOSFALSE
)
462 SendPkt(dp
, &cliproc
->pr_MsgPort
, &me
->pr_MsgPort
);
466 if (fh
&& oldSignal
) {
467 DoPkt(fh
->fh_Type
, ACTION_CHANGE_SIGNAL
, (SIPTR
)fh
->fh_Arg1
, oldSignal
, 0, 0, 0);
471 SetIoErr(dp
->dp_Res2
);
481 FreeDosObject(DOS_STDPKT
, dp
);
483 FreeTagItems(newtags
);
487 if (sis_opened
) Close(sis
);
488 if (cis_opened
) Close(cis
);
489 if (sos_opened
) Close(sos
);
490 if (ses_opened
) Close(ses
);
495 } /* SystemTagList */