Check that initial lock is a directory.
[AROS.git] / rom / dos / systemtaglist.c
blob81ce3b593f35aa6d375d78d665baca41ad8c85a4
1 /*
2 Copyright © 1995-2014, 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.
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()).
86 EXAMPLE
88 BUGS
90 SEE ALSO
91 Execute(), CreateNewProc(), Input(), Output(), <dos/dostags.h>
93 INTERNALS
95 *****************************************************************************/
97 AROS_LIBFUNC_INIT
99 struct Process *me = (struct Process *)FindTask(NULL);
100 BPTR cis = BNULL;
101 BPTR sis;
102 BPTR sos;
103 BPTR ses = BNULL;
104 BPTR shellseg = BNULL;
105 STRPTR resShell = BNULL;
106 STRPTR shellName = "Custom Shell";
107 APTR entry;
108 BOOL sis_opened = FALSE;
109 BOOL cis_opened = FALSE;
110 BOOL sos_opened = FALSE;
111 BOOL ses_opened = FALSE;
112 #ifdef __mc68000
113 BOOL isCLI = TRUE; /* Default is BCPL compatible CLI */
114 #else
115 BOOL isCLI = FALSE; /* Default is C style Shell */
116 #endif
117 BOOL isBoot = TRUE;
118 BOOL isCustom = FALSE;
119 BOOL isAsynch = FALSE;
120 BOOL isBackground = TRUE;
121 LONG cliType = CLI_INVALID;
122 ULONG commandlen;
123 LONG rc = -1;
125 struct TagItem *tags2 = tags;
126 struct TagItem *newtags, *tag;
128 ASSERT_VALID_PROCESS(me);
129 D(bug("SystemTagList('%s',%p)\n", command, tags));
131 sis = Input();
132 sos = Output();
134 while ((tag = NextTagItem(&tags2)))
136 D(bug("Tag=%08x Data=%08x\n", tag->ti_Tag, tag->ti_Data));
137 switch (tag->ti_Tag)
139 case SYS_ScriptInput:
140 cis = (BPTR)tag->ti_Data;
141 break;
143 case SYS_Input:
144 sis = (BPTR)tag->ti_Data;
145 break;
147 case SYS_Output:
148 sos = (BPTR)tag->ti_Data;
149 break;
151 case SYS_Error:
152 ses = (BPTR)tag->ti_Data;
153 break;
155 case SYS_CustomShell:
156 resShell = (STRPTR)tag->ti_Data;
157 isCustom = TRUE;
158 isCLI = FALSE;
159 break;
161 case SYS_UserShell:
162 isBoot = !tag->ti_Data;
163 isCustom = FALSE;
164 break;
166 case SYS_Asynch:
167 isAsynch = tag->ti_Data ? TRUE : FALSE;
168 break;
170 case SYS_Background:
171 isBackground = tag->ti_Data ? TRUE : FALSE;
172 break;
174 case SYS_CliType:
175 cliType = (LONG)tag->ti_Data;
176 break;
180 /* Validate cliType */
181 switch (cliType) {
182 case CLI_SYSTEM:
183 isAsynch = FALSE;
184 isBackground = TRUE;
185 break;
186 case CLI_BOOT:
187 isAsynch = TRUE;
188 isBackground = FALSE;
189 break;
190 case CLI_NEWCLI:
191 isAsynch = TRUE;
192 isBackground = FALSE;
193 break;
194 case CLI_RUN:
195 case CLI_ASYSTEM:
196 isAsynch = TRUE;
197 isBackground = TRUE;
198 break;
199 case CLI_INVALID:
200 /* default */
201 if (isBackground)
202 cliType = isAsynch ? CLI_ASYSTEM : CLI_SYSTEM;
203 else
204 cliType = isAsynch ? CLI_NEWCLI : CLI_BOOT;
205 break;
206 default:
207 /* invalid */
208 goto end;
211 /* Set up the streams */
212 if (sis == (BPTR)SYS_DupStream)
214 sis = OpenFromLock(DupLockFromFH(Input()));
215 if (!sis) goto end;
217 sis_opened = TRUE;
219 if (sis == BNULL) {
220 sis = Open("NIL:", MODE_OLDFILE);
221 if (!sis) goto end;
223 sis_opened = TRUE;
225 D(bug("[SystemTagList] cli_StandardInput: %p\n", sis));
227 if (cis == BNULL || cis == (BPTR)SYS_DupStream)
228 cis = sis;
229 D(bug("[SystemTagList] cli_CurrentInput: %p\n", cis));
231 if (sos == (BPTR)SYS_DupStream)
233 sos = OpenFromLock(DupLockFromFH(Output()));
234 if (!sos) goto end;
236 sos_opened = TRUE;
238 D(bug("[SystemTagList] cli_StandardOutput: %p\n", sos));
240 if (ses == (BPTR)SYS_DupStream)
242 ses = OpenFromLock(DupLockFromFH(me->pr_CES));
243 if (!ses) goto end;
245 ses_opened = TRUE;
247 D(bug("[SystemTagList] cli_StandardError: %p\n", ses));
249 /* Inject the arguments, adding a trailing '\n'
250 * if the user did not.
252 if (command == NULL)
253 command = "";
255 commandlen = strlen(command);
256 if (commandlen) {
257 STRPTR cmdcopy = NULL;
258 BOOL ok;
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;
265 command = cmdcopy;
268 ok = vbuf_inject(cis, command, commandlen, DOSBase);
269 FreeVec(cmdcopy);
271 if (!ok)
272 goto end;
275 /* Load the shell */
276 if (!isCustom) {
277 /* Seglist of default shell is stored in RootNode when loaded */
278 D(bug("[SystemTagList] Loading standard %s\n", isCLI? "CLI" : "shell"));
279 if (isCLI)
280 shellseg = findseg_cli(isBoot, DOSBase);
281 else
282 shellseg = findseg_shell(isBoot, DOSBase);
284 * Set shell process name.
286 if (isCLI)
287 shellName = "CLI";
288 else
289 shellName = "Shell";
290 } else if (resShell != BNULL) {
291 struct Segment *seg;
293 /* Get the custom shell from the DOS resident list */
294 D(bug("[SystemTagList] Loading custom shell\n"));
295 Forbid();
296 seg = FindSegment(resShell, NULL, TRUE);
297 if (seg)
298 shellseg = seg->seg_Seg;
299 Permit();
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);
310 isCLI = FALSE;
313 if (!shellseg) {
314 D(bug("[SystemTagList] No shell available\n"));
315 goto end;
318 #ifdef __mc68000
319 if (isCLI)
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;
328 else
329 #endif
331 D(bug("[SystemTagList] C 'shell' shell selected\n"));
332 /* Use the standard C entry point */
333 entry = NULL;
336 newtags = CloneTagItems(tags);
337 if (newtags)
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 */
365 Tag filterList[] =
367 NP_Seglist,
368 NP_FreeSeglist,
369 NP_Entry,
370 NP_Input,
371 NP_Output,
372 NP_CloseInput,
373 NP_CloseOutput,
374 NP_CloseError,
375 NP_HomeDir,
376 NP_Cli,
377 NP_Arguments,
378 NP_Synchronous,
379 NP_UserData,
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);
391 if (dp) {
392 cliproc = CreateNewProc(proctags);
394 if (cliproc)
396 SIPTR oldSignal = 0;
397 struct FileHandle *fh = NULL;
399 D(bug("[SystemTagList] cliType = %d (background=%d, asynch=%d)\n", cliType, isBackground, isAsynch));
400 #ifdef __mc68000
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
407 if (isCLI) {
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);
414 switch (cliType) {
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;
420 default: goto end;
422 } else /* Fallthough to the next line for user shells */
423 #endif
424 dp->dp_Type = cliType;
425 dp->dp_Res2 = 0;
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 */
433 dp->dp_Res1 = 1;
434 dp->dp_Arg1 = (IPTR)(me->pr_CurrentDir ? DupLock(me->pr_CurrentDir) : BNULL);
435 } else {
436 /* CliInitRun style */
437 dp->dp_Res1 = 0;
438 dp->dp_Arg1 = (IPTR)(__is_process(me) ? MKBADDR(Cli()) : BNULL);
439 dp->dp_Arg5 = (IPTR)(me->pr_CurrentDir ? DupLock(me->pr_CurrentDir) : BNULL);
440 dp->dp_Arg6 = 1;
443 /* Migrate the CIS handle to the new process */
444 if (!isAsynch && IsInteractive(sis)) {
445 fh = BADDR(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)
448 oldSignal = 0;
451 SendPkt(dp, &cliproc->pr_MsgPort, &me->pr_MsgPort);
452 if (WaitPkt() != dp)
453 Alert(AN_QPktFail);
455 if (fh && oldSignal) {
456 DoPkt(fh->fh_Type, ACTION_CHANGE_SIGNAL, (SIPTR)fh->fh_Arg1, oldSignal, 0, 0, 0);
459 rc = dp->dp_Res1;
460 SetIoErr(dp->dp_Res2);
462 cis_opened = FALSE;
463 if (isAsynch) {
464 sis_opened =
465 sos_opened =
466 ses_opened = FALSE;
470 FreeDosObject(DOS_STDPKT, dp);
472 FreeTagItems(newtags);
475 end:
476 if (sis_opened) Close(sis);
477 if (cis_opened) Close(cis);
478 if (sos_opened) Close(sos);
479 if (ses_opened) Close(ses);
481 return rc;
483 AROS_LIBFUNC_EXIT
484 } /* SystemTagList */