compiler/clib: Don't hide access to aroscbase behind a #define.
[AROS.git] / compiler / clib / __arosc_nixmain.c
blob42286327cec7528b86263090ade1421604fc2ab4
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 = __GM_GetBase(), *paroscbase;
40 char *old_argv0 = NULL;
41 char *new_argv0 = NULL;
42 struct MinList old_vars;
44 /* Trigger *nix path handling on. */
45 aroscbase->acb_doupath = 1;
47 /* argv[0] usually contains the name of the program, possibly with the full
48 path to it. Here we translate that path, which is an AmigaDOS-style path,
49 into an unix-style one. */
50 if (argv && argv[0] && !aroscbase->acb_parent_does_upath)
52 new_argv0 = strdup(__path_a2u(argv[0]));
53 if (new_argv0 == NULL)
54 return RETURN_FAIL;
56 old_argv0 = argv[0];
57 argv[0] = new_argv0;
60 /* Here we clone environment variables. We do this because
61 if we've been invoked as a coroutine via dos.library/RunCommand()
62 rather than as a newly created process, then we share our env variables
63 with the caller, but we do not want that. It's kind of wasteful to do
64 it even if we've been started as a fresh process, though, so if we can
65 we avoid it.
66 The cloning does not need to be performed if flags of parent have VFORK_PARENT
67 or EXEC_PARENT flags */
68 paroscbase = __GM_GetBaseParent(aroscbase);
69 if (!paroscbase || !(paroscbase->acb_flags & (VFORK_PARENT | EXEC_PARENT)))
71 D(bug("__arosc_nixmain: Cloning LocalVars"));
72 if (!clone_vars(&old_vars))
74 __arosc_startup_error = RETURN_FAIL;
75 goto err_vars;
79 /* If the PATH variable is not defined, then define it to be what CLI's path list
80 points to. */
81 if (!getenv("PATH"))
82 update_PATH();
84 /* Call the real main. */
85 if (setjmp(__arosc_startup_jmp_buf) == 0)
87 __arosc_startup_error = (*main)(argc, argv);
91 if (!paroscbase || !(paroscbase->acb_flags & (VFORK_PARENT | EXEC_PARENT)))
92 restore_vars(&old_vars);
94 err_vars:
96 /* Restore the old argv[0]. */
97 if (old_argv0 != NULL)
99 free(new_argv0);
100 argv[0] = (char *)old_argv0;
103 return __arosc_startup_error;
106 /* Clone the process' environment variables list. Once this function returns,
107 the _cloned_ vars are used in place of the old ones.
109 Returns the old list's content in the old_vars argument. Use this list only as
110 argument to restore_vars() and for _nothing_ else.
112 If this function fails, then FALSE is returned, otherwise TRUE is returned.
114 One might argue that the whole affair is solved the wrong way around, that is
115 clone_vars() should return the _cloned_ list and restore_vars() should be really
116 named replace_vars() and take the cloned list as argument and replace the current
117 one with that one, but doing it this way means breaking any programs which saved
118 vars list's internals before invoking this program, although that is not even guaranteed
119 to work normally, as the called program could change the env list anytime... Well,
120 in either case it doesn't do much of a difference, since the same amount of operations
121 would be performed, only the order would change. */
123 BOOL clone_vars(struct MinList *old_vars)
125 struct MinList l;
126 struct LocalVar *lv, *newVar;
127 struct Process *me;
129 NEWLIST(&l);
131 me = (struct Process *)FindTask(NULL);
132 /* Copied and adapted from rom/dos/createnewproc.c. Perhaps there should
133 be a public function for this? */
134 ForeachNode(&me->pr_LocalVars, lv)
136 size_t copyLength;
138 if (lv->lv_Len == 0)
139 continue;
141 copyLength = strlen(lv->lv_Node.ln_Name) + 1 + sizeof(struct LocalVar);
143 newVar = (struct LocalVar *)AllocVec(copyLength, MEMF_PUBLIC);
144 if (newVar == NULL)
146 free_vars(&l);
147 return FALSE;
150 memcpy(newVar, lv, copyLength);
151 newVar->lv_Node.ln_Name = (char *)newVar + sizeof(struct LocalVar);
152 newVar->lv_Value = AllocMem(lv->lv_Len, MEMF_PUBLIC);
154 if (newVar->lv_Value == NULL)
156 FreeVec(newVar);
157 free_vars(&l);
158 return FALSE;
161 memcpy(newVar->lv_Value, lv->lv_Value, lv->lv_Len);
163 ADDTAIL(&l, newVar);
166 *old_vars = me->pr_LocalVars;
167 me->pr_LocalVars = l;
169 l.mlh_Head->mln_Pred = (struct MinNode *)&me->pr_LocalVars.mlh_Head;
170 l.mlh_TailPred->mln_Succ = (struct MinNode *)&me->pr_LocalVars.mlh_Tail;
172 return TRUE;
175 /* Restores the old env var's list content */
176 static void restore_vars(struct MinList *old_vars)
178 struct Process *me = (struct Process *)FindTask(NULL);
180 free_vars(&me->pr_LocalVars);
181 me->pr_LocalVars = *old_vars;
184 /* taken from rom/dos/createnewproc.c. */
185 static void free_vars(struct MinList *vars)
187 struct LocalVar *varNode;
188 struct Node *tempNode;
190 ForeachNodeSafe(vars, varNode, tempNode)
192 FreeMem(varNode->lv_Value, varNode->lv_Len);
193 Remove((struct Node *)varNode);
194 FreeVec(varNode);
198 /* setenv("PATH", current_cli_path, 1) */
199 static void update_PATH(void)
201 typedef struct
203 BPTR next;
204 BPTR lock;
205 } PathEntry;
207 #define PE(x) ((PathEntry *)(BADDR(x)))
209 UBYTE aname[PATH_MAX]; /* PATH_MAX ought to be enough; it would be too complicated
210 handling aname dynamically (thanks to our sucky dos.library). */
211 char *PATH = NULL;
212 size_t PATH_len = 0;
213 PathEntry *cur;
214 struct CommandLineInterface *cli = Cli();
216 /* No cli, no luck. */
217 if (cli == NULL)
218 return;
222 cur = PE(cli->cli_CommandDir);
223 cur != NULL;
224 cur = PE(cur->next)
227 char *new_PATH;
228 const char *uname;
229 size_t uname_len;
231 if (NameFromLock(cur->lock, aname, sizeof(aname)) == DOSFALSE)
232 continue;
234 D(bug("aname = %s\n", aname));
236 uname = __path_a2u((const char *)aname);
237 if (!uname)
238 continue;
239 uname_len = strlen(uname);
241 D(bug("uname = %s\n", uname));
243 new_PATH = realloc(PATH, PATH_len + uname_len + 1);
244 if (!new_PATH)
245 continue;
246 PATH = new_PATH;
248 memcpy(PATH + PATH_len, uname, uname_len);
249 PATH_len += uname_len;
250 PATH[PATH_len++] = ':';
252 D(bug("PATH_len = %d, PATH = %.*s\n", PATH_len, PATH_len, PATH));
255 if (PATH)
257 PATH[PATH_len ? (PATH_len - 1) : 0] = '\0';
259 setenv("PATH", PATH, 1);