revert between 56095 -> 55830 in arch
[AROS.git] / compiler / posixc / __posixc_nixmain.c
blob7c89910d8b287a58b7f4e92ea6932437a3d00eda
1 /*
2 Copyright © 1995-2014, 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 "__upath.h"
31 static BOOL clone_vars(struct MinList *old_vars);
32 static void restore_vars(struct MinList *old_vars);
33 static void free_vars(struct MinList *vars);
34 static void update_PATH(void);
36 int __posixc_nixmain(int (*main)(int argc, char *argv[]), int argc, char *argv[])
38 struct PosixCIntBase *PosixCBase, *pPosixCBase;
39 int *errorptr = __stdc_get_errorptr();
40 char *old_argv0 = NULL;
41 char *new_argv0 = NULL;
42 struct MinList old_vars;
44 D(bug("__posixc_nixmain: @begin, Task=%x\n", FindTask(NULL)));
45 PosixCBase = (struct PosixCIntBase *)__aros_getbase_PosixCBase();
47 /* Trigger *nix path handling on. */
48 PosixCBase->doupath = 1;
50 /* argv[0] usually contains the name of the program, possibly with the full
51 path to it. Here we translate that path, which is an AmigaDOS-style path,
52 into a unix-style one. */
53 if (argv && argv[0])
55 new_argv0 = strdup(__path_a2u(argv[0]));
56 if (new_argv0 == NULL)
57 return RETURN_FAIL;
59 old_argv0 = argv[0];
60 argv[0] = new_argv0;
63 /* Here we clone environment variables. We do this because
64 if we've been invoked as a coroutine via dos.library/RunCommand()
65 rather than as a newly created process, then we share our env variables
66 with the caller, but we do not want that. It's kind of wasteful to do
67 it even if we've been started as a fresh process, though, so if we can
68 we avoid it.
69 The cloning does not need to be performed if flags of parent have VFORK_PARENT
70 or EXEC_PARENT flags */
71 pPosixCBase = __GM_GetBaseParent(PosixCBase);
72 D(bug("__posixc_nixmain: pPosixCBase = %x, Task=%x\n", pPosixCBase, FindTask(NULL)));
73 if (!pPosixCBase || !(pPosixCBase->flags & (VFORK_PARENT | EXEC_PARENT)))
75 D(bug("__posixc_nixmain: Cloning LocalVars"));
76 if (!clone_vars(&old_vars))
78 if (errorptr)
79 *errorptr = RETURN_FAIL;
80 goto err_vars;
84 /* If the PATH variable is not defined, then define it to be what CLI's path list
85 points to. */
86 if (!getenv("PATH"))
87 update_PATH();
89 /* Call the real main. */
90 jmp_buf exitjmp, dummyjmp;
91 if (setjmp(exitjmp) == 0)
93 int ret;
95 __stdc_set_exitjmp(exitjmp, dummyjmp);
97 ret = (*main)(argc, argv);
98 if (errorptr)
99 *errorptr = ret;
101 else
102 D(bug("__posixc_nixmain: setjmp() != 0\n"));
104 D(bug("__posixc_nixmain: pPosixCBase = %x, Task=%x\n", pPosixCBase, FindTask(NULL)));
105 if (!pPosixCBase || !(pPosixCBase->flags & (VFORK_PARENT | EXEC_PARENT)))
106 restore_vars(&old_vars);
108 err_vars:
110 /* Restore the old argv[0]. */
111 if (old_argv0 != NULL)
113 free(new_argv0);
114 argv[0] = (char *)old_argv0;
117 D(bug("__posixc_nixmain: @end, Task=%x\n", FindTask(NULL)));
119 return (errorptr != NULL) ? *errorptr : 0;
122 /* Clone the process' environment variables list. Once this function returns,
123 the _cloned_ vars are used in place of the old ones.
125 Returns the old list's content in the old_vars argument. Use this list only as
126 argument to restore_vars() and for _nothing_ else.
128 If this function fails, then FALSE is returned, otherwise TRUE is returned.
130 One might argue that the whole affair is solved the wrong way around, that is
131 clone_vars() should return the _cloned_ list and restore_vars() should be really
132 named replace_vars() and take the cloned list as argument and replace the current
133 one with that one, but doing it this way means breaking any programs which saved
134 vars list's internals before invoking this program, although that is not even guaranteed
135 to work normally, as the called program could change the env list anytime... Well,
136 in either case it doesn't do much of a difference, since the same amount of operations
137 would be performed, only the order would change. */
139 BOOL clone_vars(struct MinList *old_vars)
141 struct MinList l;
142 struct LocalVar *lv, *newVar;
143 struct Process *me;
145 NEWLIST(&l);
147 me = (struct Process *)FindTask(NULL);
148 /* Copied and adapted from rom/dos/createnewproc.c. Perhaps there should
149 be a public function for this? */
150 ForeachNode(&me->pr_LocalVars, lv)
152 size_t copyLength = strlen(lv->lv_Node.ln_Name) + 1 + sizeof(struct LocalVar);
154 newVar = (struct LocalVar *)AllocVec(copyLength, MEMF_PUBLIC);
155 if (newVar == NULL)
157 free_vars(&l);
158 return FALSE;
161 memcpy(newVar, lv, copyLength);
162 newVar->lv_Node.ln_Name = (char *)newVar + sizeof(struct LocalVar);
163 if (lv->lv_Len)
165 newVar->lv_Value = AllocMem(lv->lv_Len, MEMF_PUBLIC);
167 if (newVar->lv_Value == NULL)
169 FreeVec(newVar);
170 free_vars(&l);
171 return FALSE;
174 memcpy(newVar->lv_Value, lv->lv_Value, lv->lv_Len);
176 else
178 /* lv_Len of 0 is a valid case for empty string, lv_Value is NULL */
179 newVar->lv_Value = NULL;
182 ADDTAIL(&l, newVar);
185 *old_vars = me->pr_LocalVars;
186 me->pr_LocalVars = l;
188 l.mlh_Head->mln_Pred = (struct MinNode *)&me->pr_LocalVars.mlh_Head;
189 l.mlh_TailPred->mln_Succ = (struct MinNode *)&me->pr_LocalVars.mlh_Tail;
191 return TRUE;
194 /* Restores the old env var's list content */
195 static void restore_vars(struct MinList *old_vars)
197 struct Process *me = (struct Process *)FindTask(NULL);
199 free_vars(&me->pr_LocalVars);
200 me->pr_LocalVars = *old_vars;
203 /* taken from rom/dos/createnewproc.c. */
204 static void free_vars(struct MinList *vars)
206 struct LocalVar *varNode;
207 struct Node *tempNode;
209 ForeachNodeSafe(vars, varNode, tempNode)
211 FreeMem(varNode->lv_Value, varNode->lv_Len);
212 Remove((struct Node *)varNode);
213 FreeVec(varNode);
217 /* setenv("PATH", current_cli_path, 1) */
218 static void update_PATH(void)
220 typedef struct
222 BPTR next;
223 BPTR lock;
224 } PathEntry;
226 #define PE(x) ((PathEntry *)(BADDR(x)))
228 UBYTE aname[PATH_MAX]; /* PATH_MAX ought to be enough; it would be too complicated
229 handling aname dynamically (thanks to our sucky dos.library). */
230 char *PATH = NULL;
231 size_t PATH_len = 0;
232 PathEntry *cur;
233 struct CommandLineInterface *cli = Cli();
235 /* No cli, no luck. */
236 if (cli == NULL)
237 return;
241 cur = PE(cli->cli_CommandDir);
242 cur != NULL;
243 cur = PE(cur->next)
246 char *new_PATH;
247 const char *uname;
248 size_t uname_len;
250 if (NameFromLock(cur->lock, aname, sizeof(aname)) == DOSFALSE)
251 continue;
253 D(bug("aname = %s\n", aname));
255 uname = __path_a2u((const char *)aname);
256 if (!uname)
257 continue;
258 uname_len = strlen(uname);
260 D(bug("uname = %s\n", uname));
262 new_PATH = realloc(PATH, PATH_len + uname_len + 1);
263 if (!new_PATH)
264 continue;
265 PATH = new_PATH;
267 memcpy(PATH + PATH_len, uname, uname_len);
268 PATH_len += uname_len;
269 PATH[PATH_len++] = ':';
271 D(bug("PATH_len = %d, PATH = %.*s\n", PATH_len, PATH_len, PATH));
274 if (PATH)
276 PATH[PATH_len ? (PATH_len - 1) : 0] = '\0';
278 setenv("PATH", PATH, 1);