1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1990-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * return job initialization commands
26 */
27
28#if _WIN32
29#undef	_BLD_DLL
30#define _BLD_DLL	1
31#endif
32
33#include "colib.h"
34
35#include <ctype.h>
36#include <fs3d.h>
37#include <ls.h>
38
39static void
40exid(Sfio_t* sp, const char* pre, const char* name, const char* pos)
41{
42	int	c;
43
44	sfputr(sp, pre, -1);
45	if ((c = *name++) && c != '=')
46	{
47		if (isdigit(c))
48			sfputc(sp, '_');
49		do
50		{
51			if (!isalnum(c))
52				c = '_';
53			sfputc(sp, c);
54		} while ((c = *name++) && c != '=');
55	}
56	else
57		sfputc(sp, '_');
58	sfputr(sp, pos, -1);
59}
60
61/*
62 * add n to the export list
63 * old!=0 formats in old style
64 * coex!=0 for CO_ENV_EXPORT
65 * if n prefixed by % then coquote conversion enabled
66 */
67
68static void
69putexport(Coshell_t* co, Sfio_t* sp, char* n, int old, int coex, int flags)
70{
71	int		cvt;
72	char*		v;
73	Coexport_t*	ex;
74
75	if (cvt = *n == '%')
76		n++;
77
78	/*
79	 * currently limited to valid identifer env var names
80	 */
81
82	if (!co->export || !dtmatch(co->export, n))
83	{
84		if (old)
85			cvt = 0;
86		if ((v = getenv(n)) && *v || coex && ((flags & CO_EXPORT) || co->export && dtsize(co->export) > 0))
87		{
88			if (!old)
89				sfprintf(sp, "\\\n");
90			exid(sp, " ", n, "='");
91			if (coex && (flags & CO_EXPORT))
92				v = "(*)";
93			if (v)
94				coquote(sp, v, cvt);
95			if (coex && !(flags & CO_EXPORT))
96			{
97				v = v ? ":" : "";
98				for (ex = (Coexport_t*)dtfirst(co->export); ex; ex = (Coexport_t*)dtnext(co->export, ex))
99				{
100					sfprintf(sp, "%s%s", v, ex->name);
101					exid(sp, v, ex->name, "");
102					v = ":";
103				}
104			}
105			sfputc(sp, '\'');
106			if (old)
107				exid(sp, "\nexport ", n, "\n");
108		}
109	}
110}
111
112/*
113 * return job initialization commands
114 */
115
116char*
117coinitialize(Coshell_t* co, int flags)
118{
119	register char*	s;
120	int		n;
121	int		m;
122	int		old;
123	int		sync;
124	char*		t;
125	long		p;
126	Coexport_t*	ex;
127	Sfio_t*		sp;
128	Sfio_t*		tp;
129	struct stat	st;
130
131	sync = co->init.sync;
132	co->init.sync = 0;
133
134	/*
135	 * pwd
136	 */
137
138	if (stat(".", &st))
139		return 0;
140	if (!state.pwd || st.st_ino != co->init.pwd_ino || st.st_dev != co->init.pwd_dev)
141	{
142		co->init.pwd_dev = st.st_dev;
143		co->init.pwd_ino = st.st_ino;
144		if (state.pwd)
145			free(state.pwd);
146		if (!(state.pwd = getcwd(NiL, 0)))
147		{
148			if (errno != EINVAL || !(state.pwd = newof(0, char, PATH_MAX, 0)))
149				return 0;
150			if (!getcwd(state.pwd, PATH_MAX))
151			{
152				free(state.pwd);
153				state.pwd = 0;
154				return 0;
155			}
156		}
157		if (!(flags & CO_INIT))
158			sync = 1;
159	}
160
161	/*
162	 * umask
163	 */
164
165	umask(n = umask(co->init.mask));
166	if (co->init.mask != n)
167	{
168		co->init.mask = n;
169		if (!(flags & CO_INIT))
170			sync = 1;
171	}
172	if (!co->init.script || sync)
173	{
174		/*
175		 * co_export[] vars
176		 */
177
178		if (!(sp = sfstropen()))
179			return 0;
180		tp = 0;
181		old = !(flags & (CO_KSH|CO_SERVER));
182		if (!old)
183			sfprintf(sp, "export");
184		if (sync)
185		{
186			if (flags & CO_EXPORT)
187				s = "(*)";
188			else
189			{
190				for (n = 0; s = co_export[n]; n++)
191					putexport(co, sp, s, old, !n, flags);
192				s = getenv(co_export[0]);
193			}
194			if (s)
195			{
196				if (*s == '(')
197				{
198					register char**	ep = environ;
199					register char*	e;
200					char*		v;
201					char*		es;
202					char*		xs;
203
204					if (v = strchr(s, ':'))
205						*v = 0;
206					while (e = *ep++)
207						if ((t = strsubmatch(e, s, 1)) && (*t == '=' || !*t && (t = strchr(e, '='))))
208						{
209							m = (int)(t - e);
210							if (!strneq(e, "PATH=", 5) && !strneq(e, "_=", 2))
211							{
212								for (n = 0; xs = co_export[n]; n++)
213								{
214									es = e;
215									while (*xs && *es == *xs)
216									{
217										es++;
218										xs++;
219									}
220									if (*es == '=' && !*xs)
221										break;
222								}
223								if (!xs)
224								{
225									if (!old)
226										sfprintf(sp, "\\\n");
227									exid(sp, " ", e, "='");
228									coquote(sp, e + m + 1, 0);
229									sfputc(sp, '\'');
230									if (old)
231										exid(sp, "\nexport ", e, "\n");
232								}
233							}
234						}
235					if (v)
236					{
237						*v++ = ':';
238						s = v;
239					}
240				}
241				if (*s)
242					for (;;)
243					{
244						if (t = strchr(s, ':'))
245							*t = 0;
246						putexport(co, sp, s, old, 0, 0);
247						if (!(s = t))
248							break;
249						*s++ = ':';
250					}
251			}
252			if (co->export)
253				for (ex = (Coexport_t*)dtfirst(co->export); ex; ex = (Coexport_t*)dtnext(co->export, ex))
254				{
255					if (!old)
256						sfprintf(sp, "\\\n");
257					exid(sp, " ", ex->name, "='");
258					coquote(sp, ex->value, 0);
259					sfputc(sp, '\'');
260					if (old)
261						exid(sp, "\nexport ", ex->name, "\n");
262				}
263		}
264
265		/*
266		 * PATH
267		 */
268
269		if (!old)
270			sfprintf(sp, "\\\n");
271		sfprintf(sp, " PATH='");
272		n = PATH_MAX;
273		if (!(t = sfstrrsrv(sp, n)))
274		{
275		bad:
276			sfstrclose(sp);
277			if (tp)
278				sfstrclose(tp);
279			return 0;
280		}
281		t += n / 2;
282		if (!(flags & CO_CROSS) && !pathpath("ignore", NiL, PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, t, n / 2) && pathpath("bin/ignore", "", PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, t, n / 2))
283		{
284			*strrchr(t, '/') = 0;
285			sfputc(sp, ':');
286			coquote(sp, t, !old);
287			sfputc(sp, ':');
288			s = pathbin();
289		}
290		else
291		{
292			s = pathbin();
293			if (!(flags & CO_CROSS))
294			{
295				if (!sync && (*s == ':' || *s == '.' && *(s + 1) == ':'))
296				{
297					sfstrseek(sp, 0, SEEK_SET);
298					goto done;
299				}
300				sfputc(sp, ':');
301			}
302		}
303		for (;;)
304		{
305			if (*s == ':')
306				s++;
307			else if (*s == '.' && *(s + 1) == ':')
308				s += 2;
309			else
310				break;
311		}
312		if (!(flags & CO_CROSS))
313			tp = 0;
314		else if (!(tp = sfstropen()))
315			goto bad;
316		else
317		{
318			while (n = *s++)
319			{
320				if (n == ':')
321				{
322					while (*s == ':')
323						s++;
324					if (!*s)
325						break;
326					if (*s == '.')
327					{
328						if (!*(s + 1))
329							break;
330						if (*(s + 1) == ':')
331						{
332							s++;
333							continue;
334						}
335					}
336				}
337				sfputc(tp, n);
338			}
339			if (!(s = costash(tp)))
340				goto bad;
341		}
342		coquote(sp, s, !old);
343		if (tp)
344			sfstrclose(tp);
345		sfputc(sp, '\'');
346		if (old)
347			sfprintf(sp, "\nexport PATH");
348		sfputc(sp, '\n');
349		if (sync)
350		{
351			/*
352			 * VPATH
353			 */
354
355			p = (int)sfstrtell(sp);
356			sfprintf(sp, "vpath ");
357			n = PATH_MAX;
358			if (fs3d(FS3D_TEST))
359				for (;;)
360				{
361					if (!(t = sfstrrsrv(sp, n)))
362						goto bad;
363					if ((m = mount(NiL, t, FS3D_GET|FS3D_ALL|FS3D_SIZE(n), NiL)) > 0)
364						m = n;
365					else
366					{
367						if (!m)
368							sfstrseek(sp, strlen(t), SEEK_CUR);
369						break;
370					}
371				}
372			else
373			{
374				m = 0;
375				sfprintf(sp, "- /#option/2d");
376			}
377			if (m)
378				sfstrseek(sp, p, SEEK_SET);
379			else
380				sfprintf(sp, " 2>/dev/null || :\n");
381			sfprintf(sp, "umask 0%o\ncd '%s'\n", co->init.mask, state.pwd);
382		}
383	done:
384		if (!(flags & CO_SERVER))
385		{
386			sfprintf(sp, "%s%s=%05d${!%s-$$}\n", old ? "" : "export ", CO_ENV_TEMP, getpid(), (flags & CO_OSH) ? "" : ":");
387			if (old)
388				sfprintf(sp, "export %s\n", CO_ENV_TEMP);
389		}
390		sfputc(sp, 0);
391		n = (int)sfstrtell(sp);
392		if (co->vm)
393		{
394			if (co->init.script)
395				vmfree(co->vm, co->init.script);
396			if (!(co->init.script = vmnewof(co->vm, 0, char, n, 1)))
397				goto bad;
398		}
399		else
400		{
401			if (co->init.script)
402				free(co->init.script);
403			if (!(co->init.script = newof(0, char, n, 1)))
404				goto bad;
405		}
406		memcpy(co->init.script, sfstrbase(sp), n);
407		sfstrclose(sp);
408	}
409	else if (!co->init.script)
410	{
411		if (co->init.script = co->vm ? vmnewof(co->vm, 0, char, 1, 0) : newof(0, char, 1, 0))
412			*co->init.script = 0;
413	}
414	return co->init.script;
415}
416
417/*
418 * return generic job initialization commands
419 */
420
421char*
422coinit(int flags)
423{
424	if (!state.generic)
425	{
426		if (!(state.generic = newof(0, Coshell_t, 1, 0)))
427			return 0;
428		state.generic->init.sync = 1;
429	}
430	return coinitialize(state.generic, flags);
431}
432