2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: subshell.c /main/3 1995/11/01 16:51:36 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF *
29 * AT&T BELL LABORATORIES *
30 * AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN *
31 * ACCORDANCE WITH APPLICABLE AGREEMENTS *
33 * Copyright (c) 1995 AT&T Corp. *
34 * Unpublished & Not for Publication *
35 * All Rights Reserved *
37 * The copyright notice above does not evidence any *
38 * actual or intended publication of such source code *
40 * This software was created by the *
41 * Advanced Software Technology Department *
42 * AT&T Bell Laboratories *
44 * For further information contact *
45 * {research,attmail}!dgk *
47 ***************************************************************/
49 /* : : generated by proto : : */
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__ "C"
59 #define __PROTO__(x) x
61 #define __PARAM__(n,o) n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
74 #define __PROTO__(x) ()
75 #define __OTORP__(x) x
76 #define __PARAM__(n,o) o
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__ ...
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a) va_start(p,a)
92 #define __VA_START__(p,a) va_start(p)
102 #include "variables.h"
107 * The following structure is used for command substitution and (...)
109 static struct subshell
111 struct subshell *prev; /* previous subshell data */
112 struct subshell *pipe; /* subshell where output goes to pipe on fork */
113 Hashtab_t *var; /* variable table at time of subshell */
114 Hashtab_t *svar; /* save shell variable table */
115 struct errorcontext *errcontext;
116 Shopt_t options;/* save shell options */
117 pid_t subpid; /* child process id */
118 Sfio_t* saveout;/*saved standard output */
119 char *pwd; /* present working directory */
120 int mask; /* present umask */
121 short tmpfd; /* saved tmp file descriptor */
124 unsigned char fdstatus;
130 * This routine will turn the sftmp() file into a real /tmp file
132 void sh_subtmpfile __PARAM__((void), ()){
133 if(sfset(sfstdout,0,0)&SF_STRING)
136 register struct checkpt *pp = (struct checkpt*)sh.jmplist;
137 register struct subshell *sp = subshell_data->pipe;
138 /* save file descriptor 1 if open */
139 if((sp->tmpfd = fd = fcntl(1,F_DUPFD,10)) >= 0)
141 fcntl(fd,F_SETFD,FD_CLOEXEC);
142 sh.fdstatus[fd] = sh.fdstatus[1]|IOCLEX;
145 /* popping a discipline forces a /tmp file create */
146 sfdisc(sfstdout,SF_POPDISC);
147 sh.fdstatus[fd=sffileno(sfstdout)] = IOREAD|IOWRITE;
154 sh.fdstatus[1] = sh.fdstatus[fd];
155 sh.fdstatus[fd] = IOCLOSE;
158 sfset(sfstdout,SF_SHARE|SF_PUBLIC,1);
159 sfpool(sfstdout,sh.outpool,SF_WRITE);
160 if(pp && pp->olist && pp->olist->strm == sfstdout)
166 * This routine creates a temp file if necessary and creates a subshell.
167 * The parent routine longjmps back to sh_subshell()
168 * The child continues possibly with its standard output replaced by temp file
170 void sh_subfork __PARAM__((void), ()){
171 register struct subshell *sp = subshell_data;
173 /* see whether inside $(...) */
176 if(pid = sh_fork(0,NIL(int*)))
178 /* this is the parent part of the fork */
181 siglongjmp(*sh.jmplist,SH_JMPSUB);
185 /* this is the child part of the fork */
186 /* setting subpid to 1 causes subshell to exit when reached */
187 sh_onstate(SH_FORKED|SH_NOLOG);
188 sh_offstate(SH_MONITOR);
196 * This routine will make a copy of the given node in the
197 * layer created by the most recent subshell_fork if the
198 * node hasn't already been copied
200 Namval_t *sh_assignok __PARAM__((register Namval_t *np,int add), (np, add)) __OTORP__(register Namval_t *np;int add;){
201 register Namval_t *mp;
202 if(nv_isnull(np) && !add) /* don't bother with this */
204 /* don't bother to save if in newer scope */
205 if(nv_search((char*)np,subshell_data->var,HASH_BUCKET)!=np)
207 mp = nv_search((char*)np,subshell_data->svar,NV_ADD|HASH_BUCKET);
208 if(mp->nvflag || mp->nvalue.cp) /* see if already saved */
212 /* mark so that it can be restored */
213 nv_onattr(mp,NV_NOFREE);
216 nv_setsize(mp,nv_size(np));
217 mp->nvenv = np->nvenv;
218 mp->nvfun = np->nvfun;
219 mp->nvalue.cp = np->nvalue.cp;
220 mp->nvflag = np->nvflag;
221 nv_onattr(np,NV_NOFREE);
226 * restore the variables
228 static void nv_restore __PARAM__((struct subshell *sp), (sp)) __OTORP__(struct subshell *sp;){
229 register Namval_t *mp, *np;
230 register Hashpos_t *pos = hashscan(sp->svar,0);
231 while(np=(Namval_t*)hashnext(pos))
233 if(mp = nv_search((char*)np,sp->var,HASH_BUCKET))
236 nv_setsize(mp,nv_size(np));
237 mp->nvenv = np->nvenv;
238 mp->nvfun = np->nvfun;
239 mp->nvalue.cp = np->nvalue.cp;
240 mp->nvflag = np->nvflag;
243 np->nvflag = NV_DEFAULT;
251 * Run command tree <t> in a virtual sub-shell
252 * If comsub is not null, then output will be placed in temp file (or buffer)
253 * If comsub is not null, the return value will be a stream consisting of
254 * output of command <t>. Otherwise, NULL will be returned.
257 Sfio_t *sh_subshell __PARAM__((union anynode *t, int flags, int comsub), (t, flags, comsub)) __OTORP__(union anynode *t; int flags; int comsub;){
258 struct subshell sub_data;
259 register struct subshell *sp = &sub_data;
261 int savecurenv = sh.curenv;
265 struct sh_scoped savst;
266 struct dolnod *argsav=0;
268 argsav = sh_arguse();
269 sh.curenv = ++subenv;
271 sh_pushcontext(&buff,SH_JMPSUB);
273 sp->prev = subshell_data;
275 sp->errcontext = &buff.err;
276 sp->var = sh.var_tree;
277 sp->options = sh.options;
281 sp->pwd = (sh.pwd?strdup(sh.pwd):0);
282 umask(sp->mask=umask(0));
284 /* save trap table */
286 if((nsig=sh.st.trapmax*sizeof(char*))>0 || sh.st.trapcom[0])
288 nsig += sizeof(char*);
289 memcpy(savstak=stakalloc(nsig),(char*)&sh.st.trapcom[0],nsig);
290 /* this nonsense needed for $(trap) */
291 sh.st.otrapcom = (char**)savstak;
294 sp->svar = hashalloc(sh.var_tree,HASH_set,HASH_ALLOCATE,0);
295 jmpval = sigsetjmp(buff.buff,0);
300 /* disable job control */
301 sp->jobcontrol = job.jobcontrol;
302 sp->monitor = (sh_isstate(SH_MONITOR)!=0);
304 sh_offstate(SH_MONITOR);
306 /* save sfstdout and status */
307 sp->saveout = sfswap(sfstdout,NIL(Sfio_t*));
308 sp->fdstatus = sh.fdstatus[1];
310 /* use sftmp() file for standard output */
311 iop = sftmp(IOBSIZE+1);
312 sfswap(iop,sfstdout);
313 sh.fdstatus[1] = IOWRITE;
317 sp->pipe = sp->prev->pipe;
322 if(jmpval!=SH_JMPSUB && sh.st.trapcom[0] && sh.subshell)
324 /* trap on EXIT not handled by child */
325 char *trap=sh.st.trapcom[0];
326 sh.st.trapcom[0] = 0; /* prevent recursion */
327 sh.oldexit = sh.exitval;
331 sh_popcontext(&buff);
332 if(sh.subshell==0) /* must be child process */
334 if(jmpval==SH_JMPSCRIPT)
335 siglongjmp(*sh.jmplist,jmpval);
340 /* re-enable job control */
341 job.jobcontrol = sp->jobcontrol;
343 sh_onstate(SH_MONITOR);
344 /* move tmp file to iop and restore sfstdout */
345 iop = sfswap(sfstdout,NIL(Sfio_t*));
348 int fd=sfsetfd(iop,3);
350 error(ERROR_system(1),e_toomany);
351 sh.sftable[fd] = iop;
352 fcntl(fd,F_SETFD,FD_CLOEXEC);
353 sh.fdstatus[fd] = (sh.fdstatus[1]|IOCLEX);
354 sh.fdstatus[1] = IOCLOSE;
356 sfswap(sp->saveout,sfstdout);
357 /* check if standard output was preserved */
361 fcntl(sp->tmpfd,F_DUPFD,1);
364 sh.fdstatus[1] = sp->fdstatus;
367 job_wait(sp->subpid);
369 sfseek(iop,(off_t)0,SEEK_SET);
372 sh.options = sp->options;
374 sh_argfree(argsav,0);
377 sh.jobenv = sh.curenv = savecurenv;
379 memcpy((char*)&sh.st.trapcom[0],savstak,nsig);
383 sh.options = sp->options;
384 subshell_data = sp->prev;
385 if(!sh.pwd || strcmp(sp->pwd,sh.pwd))
388 Namval_t *pwdnod = nv_scoped(PWDNOD);
390 chdir(sh.pwd=sp->pwd);
391 if(nv_isattr(pwdnod,NV_NOFREE))
392 pwdnod->nvalue.cp = (const char*)sp->pwd;
395 free((__V_*)sp->pwd);
397 if(sh.topfd != buff.topfd)
398 sh_iorestore(buff.topfd);
399 if(sh.exitval > SH_EXITSIG)
400 sh_fault(sh.exitval&SH_EXITMASK);