Improvements to comments and other minor changes.
[AROS.git] / rom / dos / systemtaglist.c
blobfe9d4dbb88b763114cf254d55c60c8c741b33c38
1 /*
2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: English
7 */
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 /*****************************************************************************
23 NAME */
25 #include <proto/dos.h>
27 AROS_LH2(LONG, SystemTagList,
29 /* SYNOPSIS */
30 AROS_LHA(CONST_STRPTR , command, D1),
31 AROS_LHA(struct TagItem *, tags, D2),
33 /* LOCATION */
34 struct DosLibrary *, DOSBase, 101, Dos)
36 /* FUNCTION
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
46 NP_Seglist
47 NP_FreeSeglist
48 NP_Entry
49 NP_Input
50 NP_Error
51 NP_Output
52 NP_CloseInput
53 NP_CloseOutput
54 NP_CloseError
55 NP_HomeDir
56 NP_Cli
57 NP_Arguments
58 NP_Synchrounous
59 NP_UserData
61 INPUTS
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.
66 RESULT
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.
71 NOTES
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
82 that handler.
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()).
88 EXAMPLE
90 BUGS
92 SEE ALSO
93 Execute(), CreateNewProc(), Input(), Output(), <dos/dostags.h>
95 INTERNALS
97 *****************************************************************************/
99 AROS_LIBFUNC_INIT
101 struct Process *me = (struct Process *)FindTask(NULL);
102 BPTR cis = BNULL;
103 BPTR sis;
104 BPTR sos;
105 BPTR ses = BNULL;
106 BPTR shellseg = BNULL;
107 STRPTR resShell = BNULL;
108 STRPTR shellName = "Custom Shell";
109 APTR entry;
110 BOOL sis_opened = FALSE;
111 BOOL cis_opened = FALSE;
112 BOOL sos_opened = FALSE;
113 BOOL ses_opened = FALSE;
114 #ifdef __mc68000
115 BOOL isCLI = TRUE; /* Default is BCPL compatible CLI */
116 #else
117 BOOL isCLI = FALSE; /* Default is C style Shell */
118 #endif
119 BOOL isBoot = TRUE;
120 BOOL isCustom = FALSE;
121 BOOL isAsynch = FALSE;
122 BOOL isBackground = TRUE;
123 LONG cliType = CLI_INVALID;
124 ULONG commandlen;
125 LONG rc = -1;
127 struct TagItem *tags2 = tags;
128 struct TagItem *newtags, *tag;
130 ASSERT_VALID_PROCESS(me);
131 D(bug("SystemTagList('%s',%p)\n", command, tags));
133 sis = Input();
134 sos = Output();
136 while ((tag = NextTagItem(&tags2)))
138 D(bug("Tag=%08x Data=%08x\n", tag->ti_Tag, tag->ti_Data));
139 switch (tag->ti_Tag)
141 case SYS_ScriptInput:
142 cis = (BPTR)tag->ti_Data;
143 break;
145 case SYS_Input:
146 sis = (BPTR)tag->ti_Data;
147 break;
149 case SYS_Output:
150 sos = (BPTR)tag->ti_Data;
151 break;
153 case SYS_Error:
154 ses = (BPTR)tag->ti_Data;
155 break;
157 case SYS_CustomShell:
158 resShell = (STRPTR)tag->ti_Data;
159 isCustom = TRUE;
160 isCLI = FALSE;
161 break;
163 case SYS_UserShell:
164 isBoot = !tag->ti_Data;
165 isCustom = FALSE;
166 break;
168 case SYS_Asynch:
169 isAsynch = tag->ti_Data ? TRUE : FALSE;
170 break;
172 case SYS_Background:
173 isBackground = tag->ti_Data ? TRUE : FALSE;
174 break;
176 case SYS_CliType:
177 cliType = (LONG)tag->ti_Data;
178 break;
182 /* Validate cliType */
183 switch (cliType) {
184 case CLI_SYSTEM:
185 isAsynch = FALSE;
186 isBackground = TRUE;
187 break;
188 case CLI_BOOT:
189 isAsynch = TRUE;
190 isBackground = FALSE;
191 break;
192 case CLI_NEWCLI:
193 isAsynch = TRUE;
194 isBackground = FALSE;
195 break;
196 case CLI_RUN:
197 case CLI_ASYSTEM:
198 isAsynch = TRUE;
199 isBackground = TRUE;
200 break;
201 case CLI_INVALID:
202 /* default */
203 if (isBackground)
204 cliType = isAsynch ? CLI_ASYSTEM : CLI_SYSTEM;
205 else
206 cliType = isAsynch ? CLI_NEWCLI : CLI_BOOT;
207 break;
208 default:
209 /* invalid */
210 goto end;
213 /* Set up the streams */
214 if (sis == (BPTR)SYS_DupStream)
216 sis = OpenFromLock(DupLockFromFH(Input()));
217 if (!sis) goto end;
219 sis_opened = TRUE;
221 if (sis == BNULL) {
222 sis = Open("NIL:", MODE_OLDFILE);
223 if (!sis) goto end;
225 sis_opened = TRUE;
227 D(bug("[SystemTagList] cli_StandardInput: %p\n", sis));
229 if (cis == BNULL || cis == (BPTR)SYS_DupStream)
230 cis = sis;
231 D(bug("[SystemTagList] cli_CurrentInput: %p\n", cis));
233 if (sos == (BPTR)SYS_DupStream)
235 sos = OpenFromLock(DupLockFromFH(Output()));
236 if (!sos) goto end;
238 sos_opened = TRUE;
240 D(bug("[SystemTagList] cli_StandardOutput: %p\n", sos));
242 if (ses == (BPTR)SYS_DupStream)
244 ses = OpenFromLock(DupLockFromFH(me->pr_CES));
245 if (!ses) goto end;
247 ses_opened = TRUE;
249 D(bug("[SystemTagList] cli_StandardError: %p\n", ses));
251 /* Inject the arguments, adding a trailing '\n'
252 * if the user did not.
254 if (command == NULL)
255 command = "";
257 commandlen = strlen(command);
258 if (commandlen) {
259 STRPTR cmdcopy = NULL;
260 BOOL ok;
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;
267 command = cmdcopy;
270 ok = vbuf_inject(cis, command, commandlen, DOSBase);
271 FreeVec(cmdcopy);
273 if (!ok)
274 goto end;
277 /* Load the shell */
278 if (!isCustom) {
279 /* Seglist of default shell is stored in RootNode when loaded */
280 D(bug("[SystemTagList] Loading standard %s\n", isCLI? "CLI" : "shell"));
281 if (isCLI)
282 shellseg = findseg_cli(isBoot, DOSBase);
283 else
284 shellseg = findseg_shell(isBoot, DOSBase);
286 * Set shell process name.
288 if (isCLI)
289 shellName = "CLI";
290 else
291 shellName = "Shell";
292 } else if (resShell != BNULL) {
293 struct Segment *seg;
295 /* Get the custom shell from the DOS resident list */
296 D(bug("[SystemTagList] Loading custom shell\n"));
297 Forbid();
298 seg = FindSegment(resShell, NULL, TRUE);
299 if (seg)
300 shellseg = seg->seg_Seg;
301 Permit();
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);
312 isCLI = FALSE;
315 if (!shellseg) {
316 D(bug("[SystemTagList] No shell available\n"));
317 goto end;
320 #ifdef __mc68000
321 if (isCLI)
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;
330 else
331 #endif
333 D(bug("[SystemTagList] C 'shell' shell selected\n"));
334 /* Use the standard C entry point */
335 entry = NULL;
338 newtags = CloneTagItems(tags);
339 if (newtags)
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 */
370 Tag filterList[] =
372 NP_Seglist,
373 NP_FreeSeglist,
374 NP_Entry,
375 NP_Input,
376 NP_Output,
377 NP_CloseInput,
378 NP_CloseOutput,
379 NP_CloseError,
380 NP_HomeDir,
381 NP_Cli,
382 NP_Arguments,
383 NP_Synchronous,
384 NP_UserData,
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);
396 if (dp) {
397 cliproc = CreateNewProc(proctags);
399 if (cliproc)
401 SIPTR oldSignal = 0;
402 struct FileHandle *fh = NULL;
403 struct ExtArg *ea = AllocMem(sizeof(struct ExtArg), MEMF_PUBLIC | MEMF_CLEAR);
405 ea->ea_CES = ses;
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));
410 #ifdef __mc68000
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
417 if (isCLI) {
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);
424 switch (cliType) {
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;
430 default: goto end;
432 } else /* Fallthough to the next line for user shells */
433 #endif
434 dp->dp_Type = cliType;
435 dp->dp_Res2 = 0;
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 */
444 dp->dp_Res1 = 1;
445 dp->dp_Arg1 = (IPTR)(me->pr_CurrentDir ? DupLock(me->pr_CurrentDir) : BNULL);
446 } else {
447 /* CliInitRun style */
448 dp->dp_Res1 = 0;
449 dp->dp_Arg1 = (IPTR)(__is_process(me) ? MKBADDR(Cli()) : BNULL);
450 dp->dp_Arg5 = (IPTR)(me->pr_CurrentDir ? DupLock(me->pr_CurrentDir) : BNULL);
451 dp->dp_Arg6 = 1;
454 /* Migrate the CIS handle to the new process */
455 if (!isAsynch && IsInteractive(sis)) {
456 fh = BADDR(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)
459 oldSignal = 0;
462 SendPkt(dp, &cliproc->pr_MsgPort, &me->pr_MsgPort);
463 if (WaitPkt() != dp)
464 Alert(AN_QPktFail);
466 if (fh && oldSignal) {
467 DoPkt(fh->fh_Type, ACTION_CHANGE_SIGNAL, (SIPTR)fh->fh_Arg1, oldSignal, 0, 0, 0);
470 rc = dp->dp_Res1;
471 SetIoErr(dp->dp_Res2);
473 cis_opened = FALSE;
474 if (isAsynch) {
475 sis_opened =
476 sos_opened =
477 ses_opened = FALSE;
481 FreeDosObject(DOS_STDPKT, dp);
483 FreeTagItems(newtags);
486 end:
487 if (sis_opened) Close(sis);
488 if (cis_opened) Close(cis);
489 if (sos_opened) Close(sos);
490 if (ses_opened) Close(ses);
492 return rc;
494 AROS_LIBFUNC_EXIT
495 } /* SystemTagList */