arosc.library: Properly rename __GM_GetBase() to __aros_getbase()
[AROS.git] / compiler / clib / __arosc_nixmain.c
blob69eb25a98f0773d4de8ea9ca1b477562485d56cd
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: special main function for code which has to use special *nix features.
6 This function gets called from a function with a similar name statically
7 linked with the program. This is so to make the program not depend on a
8 particular libc version.
10 Lang: english
13 #include LC_LIBDEFS_FILE
15 #include <proto/exec.h>
16 #include <proto/dos.h>
17 #include <exec/lists.h>
18 #include <dos/dos.h>
19 #include <aros/startup.h>
21 #define DEBUG 0
22 #include <aros/debug.h>
24 #include <setjmp.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <sys/param.h>
29 #include "__arosc_privdata.h"
30 #include "__upath.h"
32 static BOOL clone_vars(struct MinList *old_vars);
33 static void restore_vars(struct MinList *old_vars);
34 static void free_vars(struct MinList *vars);
35 static void update_PATH(void);
37 int __arosc_nixmain(int (*main)(int argc, char *argv[]), int argc, char *argv[])
39 struct aroscbase *aroscbase = __aros_getbase(), *paroscbase;
40 char *old_argv0 = NULL;
41 char *new_argv0 = NULL;
42 struct MinList old_vars;
44 D(bug("__arosc_nixmain: @begin, Task=%x\n", FindTask(NULL)));
46 /* Trigger *nix path handling on. */
47 aroscbase->acb_doupath = 1;
49 /* argv[0] usually contains the name of the program, possibly with the full
50 path to it. Here we translate that path, which is an AmigaDOS-style path,
51 into an unix-style one. */
52 if (argv && argv[0] && !aroscbase->acb_parent_does_upath)
54 new_argv0 = strdup(__path_a2u(argv[0]));
55 if (new_argv0 == NULL)
56 return RETURN_FAIL;
58 old_argv0 = argv[0];
59 argv[0] = new_argv0;
62 /* Here we clone environment variables. We do this because
63 if we've been invoked as a coroutine via dos.library/RunCommand()
64 rather than as a newly created process, then we share our env variables
65 with the caller, but we do not want that. It's kind of wasteful to do
66 it even if we've been started as a fresh process, though, so if we can
67 we avoid it.
68 The cloning does not need to be performed if flags of parent have VFORK_PARENT
69 or EXEC_PARENT flags */
70 paroscbase = __GM_GetBaseParent(aroscbase);
71 D(bug("__arosc_nixmain: paroscbase = %x, Task=%x\n", paroscbase, FindTask(NULL)));
72 if (!paroscbase || !(paroscbase->acb_flags & (VFORK_PARENT | EXEC_PARENT)))
74 D(bug("__arosc_nixmain: Cloning LocalVars"));
75 if (!clone_vars(&old_vars))
77 __arosc_startup_error = RETURN_FAIL;
78 goto err_vars;
82 /* If the PATH variable is not defined, then define it to be what CLI's path list
83 points to. */
84 if (!getenv("PATH"))
85 update_PATH();
87 /* Call the real main. */
88 if (setjmp(__arosc_startup_jmp_buf) == 0)
90 __arosc_startup_error = (*main)(argc, argv);
92 else
93 D(bug("__arosc_nixmain: setjmp() != 0\n"));
95 D(bug("__arosc_nixmain: paroscbase = %x, Task=%x\n", paroscbase, FindTask(NULL)));
96 if (!paroscbase || !(paroscbase->acb_flags & (VFORK_PARENT | EXEC_PARENT)))
97 restore_vars(&old_vars);
99 err_vars:
101 /* Restore the old argv[0]. */
102 if (old_argv0 != NULL)
104 free(new_argv0);
105 argv[0] = (char *)old_argv0;
108 D(bug("__arosc_nixmain: @end, Task=%x\n", FindTask(NULL)));
110 return __arosc_startup_error;
113 /* Clone the process' environment variables list. Once this function returns,
114 the _cloned_ vars are used in place of the old ones.
116 Returns the old list's content in the old_vars argument. Use this list only as
117 argument to restore_vars() and for _nothing_ else.
119 If this function fails, then FALSE is returned, otherwise TRUE is returned.
121 One might argue that the whole affair is solved the wrong way around, that is
122 clone_vars() should return the _cloned_ list and restore_vars() should be really
123 named replace_vars() and take the cloned list as argument and replace the current
124 one with that one, but doing it this way means breaking any programs which saved
125 vars list's internals before invoking this program, although that is not even guaranteed
126 to work normally, as the called program could change the env list anytime... Well,
127 in either case it doesn't do much of a difference, since the same amount of operations
128 would be performed, only the order would change. */
130 BOOL clone_vars(struct MinList *old_vars)
132 struct MinList l;
133 struct LocalVar *lv, *newVar;
134 struct Process *me;
136 NEWLIST(&l);
138 me = (struct Process *)FindTask(NULL);
139 /* Copied and adapted from rom/dos/createnewproc.c. Perhaps there should
140 be a public function for this? */
141 ForeachNode(&me->pr_LocalVars, lv)
143 size_t copyLength;
145 if (lv->lv_Len == 0)
146 continue;
148 copyLength = strlen(lv->lv_Node.ln_Name) + 1 + sizeof(struct LocalVar);
150 newVar = (struct LocalVar *)AllocVec(copyLength, MEMF_PUBLIC);
151 if (newVar == NULL)
153 free_vars(&l);
154 return FALSE;
157 memcpy(newVar, lv, copyLength);
158 newVar->lv_Node.ln_Name = (char *)newVar + sizeof(struct LocalVar);
159 newVar->lv_Value = AllocMem(lv->lv_Len, MEMF_PUBLIC);
161 if (newVar->lv_Value == NULL)
163 FreeVec(newVar);
164 free_vars(&l);
165 return FALSE;
168 memcpy(newVar->lv_Value, lv->lv_Value, lv->lv_Len);
170 ADDTAIL(&l, newVar);
173 *old_vars = me->pr_LocalVars;
174 me->pr_LocalVars = l;
176 l.mlh_Head->mln_Pred = (struct MinNode *)&me->pr_LocalVars.mlh_Head;
177 l.mlh_TailPred->mln_Succ = (struct MinNode *)&me->pr_LocalVars.mlh_Tail;
179 return TRUE;
182 /* Restores the old env var's list content */
183 static void restore_vars(struct MinList *old_vars)
185 struct Process *me = (struct Process *)FindTask(NULL);
187 free_vars(&me->pr_LocalVars);
188 me->pr_LocalVars = *old_vars;
191 /* taken from rom/dos/createnewproc.c. */
192 static void free_vars(struct MinList *vars)
194 struct LocalVar *varNode;
195 struct Node *tempNode;
197 ForeachNodeSafe(vars, varNode, tempNode)
199 FreeMem(varNode->lv_Value, varNode->lv_Len);
200 Remove((struct Node *)varNode);
201 FreeVec(varNode);
205 /* setenv("PATH", current_cli_path, 1) */
206 static void update_PATH(void)
208 typedef struct
210 BPTR next;
211 BPTR lock;
212 } PathEntry;
214 #define PE(x) ((PathEntry *)(BADDR(x)))
216 UBYTE aname[PATH_MAX]; /* PATH_MAX ought to be enough; it would be too complicated
217 handling aname dynamically (thanks to our sucky dos.library). */
218 char *PATH = NULL;
219 size_t PATH_len = 0;
220 PathEntry *cur;
221 struct CommandLineInterface *cli = Cli();
223 /* No cli, no luck. */
224 if (cli == NULL)
225 return;
229 cur = PE(cli->cli_CommandDir);
230 cur != NULL;
231 cur = PE(cur->next)
234 char *new_PATH;
235 const char *uname;
236 size_t uname_len;
238 if (NameFromLock(cur->lock, aname, sizeof(aname)) == DOSFALSE)
239 continue;
241 D(bug("aname = %s\n", aname));
243 uname = __path_a2u((const char *)aname);
244 if (!uname)
245 continue;
246 uname_len = strlen(uname);
248 D(bug("uname = %s\n", uname));
250 new_PATH = realloc(PATH, PATH_len + uname_len + 1);
251 if (!new_PATH)
252 continue;
253 PATH = new_PATH;
255 memcpy(PATH + PATH_len, uname, uname_len);
256 PATH_len += uname_len;
257 PATH[PATH_len++] = ':';
259 D(bug("PATH_len = %d, PATH = %.*s\n", PATH_len, PATH_len, PATH));
262 if (PATH)
264 PATH[PATH_len ? (PATH_len - 1) : 0] = '\0';
266 setenv("PATH", PATH, 1);