2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
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.
13 #include LC_LIBDEFS_FILE
15 #include <proto/exec.h>
16 #include <proto/dos.h>
17 #include <exec/lists.h>
19 #include <aros/startup.h>
22 #include <aros/debug.h>
27 #include <sys/param.h>
29 #include "__arosc_privdata.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 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
)
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
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
;
82 /* If the PATH variable is not defined, then define it to be what CLI's path list
87 /* Call the real main. */
88 if (setjmp(__arosc_startup_jmp_buf
) == 0)
90 __arosc_startup_error
= (*main
)(argc
, argv
);
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
);
101 /* Restore the old argv[0]. */
102 if (old_argv0
!= NULL
)
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
)
133 struct LocalVar
*lv
, *newVar
;
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
)
148 copyLength
= strlen(lv
->lv_Node
.ln_Name
) + 1 + sizeof(struct LocalVar
);
150 newVar
= (struct LocalVar
*)AllocVec(copyLength
, MEMF_PUBLIC
);
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
)
168 memcpy(newVar
->lv_Value
, lv
->lv_Value
, lv
->lv_Len
);
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
;
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
);
205 /* setenv("PATH", current_cli_path, 1) */
206 static void update_PATH(void)
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). */
221 struct CommandLineInterface
*cli
= Cli();
223 /* No cli, no luck. */
229 cur
= PE(cli
->cli_CommandDir
);
238 if (NameFromLock(cur
->lock
, aname
, sizeof(aname
)) == DOSFALSE
)
241 D(bug("aname = %s\n", aname
));
243 uname
= __path_a2u((const char *)aname
);
246 uname_len
= strlen(uname
);
248 D(bug("uname = %s\n", uname
));
250 new_PATH
= realloc(PATH
, PATH_len
+ uname_len
+ 1);
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
));
264 PATH
[PATH_len
? (PATH_len
- 1) : 0] = '\0';
266 setenv("PATH", PATH
, 1);