Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / ksh93 / sh / main.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $XConsortium: main.c /main/3 1995/11/01 16:49:31 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
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             *
32 *                                                              *
33 *                Copyright (c) 1995 AT&T Corp.                 *
34 *              Unpublished & Not for Publication               *
35 *                     All Rights Reserved                      *
36 *                                                              *
37 *       The copyright notice above does not evidence any       *
38 *      actual or intended publication of such source code      *
39 *                                                              *
40 *               This software was created by the               *
41 *           Advanced Software Technology Department            *
42 *                    AT&T Bell Laboratories                    *
43 *                                                              *
44 *               For further information contact                *
45 *                    {research,attmail}!dgk                    *
46 *                                                              *
47 ***************************************************************/
48
49 /* : : generated by proto : : */
50
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__      "C"
55 #else
56 #define __MANGLE__
57 #endif
58 #define __STDARG__
59 #define __PROTO__(x)    x
60 #define __OTORP__(x)
61 #define __PARAM__(n,o)  n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
64 #define const
65 #endif
66 #define signed
67 #define void            int
68 #define volatile
69 #define __V_            char
70 #else
71 #define __V_            void
72 #endif
73 #else
74 #define __PROTO__(x)    ()
75 #define __OTORP__(x)    x
76 #define __PARAM__(n,o)  o
77 #define __MANGLE__
78 #define __V_            char
79 #define const
80 #define signed
81 #define void            int
82 #define volatile
83 #endif
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__      ...
86 #else
87 #define __VARARG__
88 #endif
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a)       va_start(p,a)
91 #else
92 #define __VA_START__(p,a)       va_start(p)
93 #endif
94 #endif
95 #include        <ast.h>
96 #include        <sfio.h>
97 #include        <stak.h>
98 #include        <ls.h>
99 #include        "defs.h"
100 #include        "variables.h"
101 #include        "path.h"
102 #include        "io.h"
103 #include        "jobs.h"
104 #include        "shnodes.h"
105 #include        "history.h"
106 #include        "timeout.h"
107 #include        "FEATURE/time"
108 #include        "FEATURE/pstat"
109 #include        "FEATURE/execargs"
110 #include        "FEATURE/externs"
111 #ifdef  _hdr_nc
112 #   include     <nc.h>
113 #endif  /* _hdr_nc */
114
115 #define CMD_LENGTH      64
116
117 /* These routines are referenced by this module */
118 static void     exfile __PROTO__((Sfio_t*,int));
119 static void     chkmail __PROTO__((char*));
120 #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
121     static void fixargs __PROTO__((char**,int));
122 #else
123 #   define fixargs(a,b)
124 #endif
125
126 extern __MANGLE__ char  **environ;
127
128 static struct stat lastmail;
129 static time_t   mailtime;
130 static char     beenhere = 0;
131
132 #ifdef _lib_sigvec
133     void clearsigmask __PARAM__((register int sig), (sig)) __OTORP__(register int sig;){
134         struct sigvec vec;
135         if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask)
136         {
137                 vec.sv_mask = 0;
138                 sigvec(sig,&vec,NIL(struct sigvec*));
139         }
140     }
141 #endif /* _lib_sigvec */
142
143 main __PARAM__((int ac, char *av[]), (ac, av)) __OTORP__(int ac; char *av[];){
144         register char   *name;
145         register int    fdin;
146         register Sfio_t  *iop;
147         register int    rshflag;        /* set for restricted shell */
148         struct checkpt buff;
149         int prof;
150         char *command;
151 #ifdef _lib_sigvec
152         /* This is to clear mask that my be left on by rlogin */
153         clearsigmask(SIGALRM);
154         clearsigmask(SIGHUP);
155         clearsigmask(SIGCHLD);
156 #endif /* _lib_sigvec */
157 #ifdef  _hdr_nc
158         _NutConf(_NC_SET_SUFFIXED_SEARCHING, 1);
159 #endif  /* _hdr_nc */
160         fixargs(av,0);
161         prof = sh_init(ac,av);
162         time(&mailtime);
163         if(rshflag=sh_isoption(SH_RESTRICTED))
164                 sh_offoption(SH_RESTRICTED);
165         sh_pushcontext(&buff,SH_JMPSCRIPT);
166         sh_userinit();
167         if(sigsetjmp(buff.buff,0))
168         {
169                 /* begin script execution here */
170                 memset(sh.st.trapcom,0,(sh.st.trapmax+1)*sizeof(char*));
171                 sh_offoption(~(SH_TRACKALL|SH_EMACS|SH_GMACS|SH_VIRAW|SH_VI));
172                 if(sh.arglist)
173                         sh_argreset(sh.arglist,NIL(struct dolnod*));
174                 sh.envlist=0;
175                 sh.shname = error_info.id = strdup(sh.st.dolv[0]);
176                 sh_offstate(SH_FORKED);
177         }
178         sh.fn_depth = sh.dot_depth = 0;
179         command = error_info.id;
180         /* set pidname '$$' */
181         sh.pid = getpid();
182         srand(sh.pid&0x7fff);
183         sh.ppid = getppid();
184         if(nv_isnull(PS4NOD))
185                 nv_putval(PS4NOD,e_traceprompt,NV_RDONLY);
186         path_pwd(1);
187         iop = (Sfio_t*)0;
188         if((beenhere++)==0)
189         {
190                 sh_onstate(SH_PROFILE);
191                 if(sh.ppid==1)
192                         sh.login_sh++;
193                 /* decide whether shell is interactive */
194                 if(sh_isoption(SH_TFLAG|SH_CFLAG)==0 && sh_isoption(SH_SFLAG) &&
195                         tty_check(0) && tty_check(ERRIO))
196                 {
197                         sh_onoption(SH_INTERACTIVE|SH_BGNICE);
198                 }
199                 if(sh_isoption(SH_INTERACTIVE))
200                 {
201 #ifdef SIGXCPU
202                         signal(SIGXCPU,SIG_DFL);
203 #endif /* SIGXCPU */
204 #ifdef SIGXFSZ
205                         signal(SIGXFSZ,SIG_DFL);
206 #endif /* SIGXFSZ */
207                         sh_onoption(SH_MONITOR);
208                 }
209                 job_init(sh.login_sh >= 2);
210                 if(sh.login_sh >= 2)
211                 {
212                         /*      system profile  */
213                         if((fdin=path_open(e_sysprofile,"")) >= 0)
214                         {
215                                 error_info.id = (char*)e_sysprofile;
216                                 exfile(iop,fdin);       /* file exists */
217                         }
218                         if(prof &&  (fdin=path_open(sh_mactry((char*)e_profile),"")) >= 0)
219                         {
220                                 error_info.id = path_basename(e_profile);
221                                 exfile(iop,fdin);
222                         }
223                 }
224                 /* make sure PWD is set up correctly */
225                 path_pwd(1);
226                 name = "";
227                 if(sh_isoption(SH_INTERACTIVE) && !sh_isoption(SH_NOEXEC))
228                 {
229                         if(prof)
230                                 name = sh_mactry(nv_getval(ENVNOD));
231                         else if(sh_isoption(SH_PRIVILEGED))
232                                 name = (char*)e_suidprofile;
233                 }
234                 if(*name && (fdin = path_open(name,"")) >= 0)
235                 {
236                         char *cp, *saveid = error_info.id;
237                         cp = error_info.id = strdup(name);
238                         exfile(iop,fdin);
239                         error_info.id = saveid;
240                         free(cp);
241                 }
242                 sh.st.cmdname = error_info.id = command;
243                 sh_offstate(SH_PROFILE);
244                 if(rshflag)
245                         sh_onoption(SH_RESTRICTED);
246                 /* open input file if specified */
247                 if(sh.comdiv)
248                 {
249                 shell_c:
250                         iop = sfnew(NIL(Sfio_t*),sh.comdiv,strlen(sh.comdiv),0,SF_STRING|SF_READ);
251                 }
252                 else
253                 {
254                         name = error_info.id;
255                         error_info.id = sh.shname;
256                         if(sh_isoption(SH_SFLAG))
257                                 fdin = 0;
258                         else
259                         {
260                                 char *sp;
261                                 /* open stream should have been passed into shell */
262                                 if(strmatch(name,e_devfdNN))
263                                 {
264                                         struct stat statb;
265                                         fdin = atoi(name+8);
266                                         if(fstat(fdin,&statb)<0)
267                                                 error(ERROR_system(1),e_open,error_info.id);
268                                         name = error_info.id;
269                                         sh_offoption(SH_XTRACE|SH_VERBOSE);
270                                 }
271                                 else
272                                 {
273                                         sp = path_absolute(name,NIL(char*));
274                                         if(sp==0 || (fdin=sh_open(sp,O_RDONLY,0))<0)
275                                                 /* for compatibility with bsh */
276                                                 if((fdin=sh_open(name,O_RDONLY,0))<0)
277                                                 {
278                                                         if(sp || errno!=ENOENT)
279                                                                 error(ERROR_system(ERROR_NOEXEC),e_open,name);
280                                                         /* try sh -c 'name "$@"' */
281                                                         sh_onoption(SH_CFLAG);
282                                                         sh.comdiv = (char*)malloc(strlen(name)+7);
283                                                         name = strcopy(sh.comdiv,name);
284                                                         if(sh.st.dolc)
285                                                                 strcopy(name," \"$@\"");
286                                                         goto shell_c;
287                                                 }
288                                                 if(fdin==0)
289                                                         fdin = sh_iomovefd(fdin);
290                                 }
291                                 sh.readscript = sh.shname;
292                         }
293                         error_info.id = name;
294                         sh.comdiv--;
295 #ifdef SHOPT_ACCT
296                         sh_accinit();
297                         if(fdin != 0)
298                                 sh_accbegin(error_info.id);
299 #endif  /* SHOPT_ACCT */
300                 }
301                 if(!sh_isoption(SH_INTERACTIVE))
302                 {
303                         /* eliminate local aliases and functions */
304                         nv_scan(sh.alias_tree,sh_envnolocal,NV_EXPORT,0);
305                         nv_scan(sh.fun_tree,sh_envnolocal,NV_EXPORT,0);
306                 }
307         }
308         else
309         {
310                 fdin = sh.infd;
311                 fixargs(sh.st.dolv,1);
312         }
313         sh_onstate(sh_isoption(SH_INTERACTIVE));
314         nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY);
315         exfile(iop,fdin);
316         sh_done(0);
317         /* NOTREACHED */
318 }
319
320 /*
321  * iop is not null when the input is a string
322  * fdin is the input file descriptor 
323  */
324
325 static void     exfile __PARAM__((register Sfio_t *iop,register int fno), (iop, fno)) __OTORP__(register Sfio_t *iop;register int fno;){
326         time_t curtime;
327         union anynode *t;
328         int maxtry=IOMAXTRY, tdone=0, execflags;
329         int states,jmpval;
330         struct checkpt buff;
331         sh_pushcontext(&buff,SH_JMPERREXIT);
332         /* open input stream */
333         if(!iop)
334         {
335                 if(fno > 0)
336                 {
337                         fno = sh_iomovefd(fno);
338                         fcntl(fno,F_SETFD,FD_CLOEXEC);
339                         sh.fdstatus[fno] |= IOCLEX;
340                         iop = sh_iostream(fno);
341                 }
342                 else
343                         iop = sfstdin;
344         }
345         else
346                 fno = -1;
347         sh.infd = fno;
348         if(sh_isstate(SH_INTERACTIVE))
349         {
350                 if(nv_isnull(PS1NOD))
351                         nv_putval(PS1NOD,(sh.euserid?e_stdprompt:e_supprompt),NV_RDONLY);
352                 sh_sigdone();
353                 if(sh_histinit())
354                         sh_onoption(SH_HISTORY);
355         }
356         else
357         {
358                 if(!sh_isstate(SH_PROFILE))
359                 {
360                         buff.mode = SH_JMPEXIT;
361                         sh_onoption(SH_TRACKALL);
362                         sh_offoption(SH_MONITOR);
363                 }
364                 sh_offstate(SH_INTERACTIVE|SH_MONITOR|SH_HISTORY);
365                 sh_offoption(SH_HISTORY);
366         }
367         states = sh_isstate(~0);
368         jmpval = sigsetjmp(buff.buff,0);
369         if(jmpval)
370         {
371                 sh_iorestore(0);
372                 hist_flush(sh.hist_ptr);
373                 sfsync(sh.outpool);
374                 sh.st.execbrk = sh.st.breakcnt = 0;
375                 /* check for return from profile or env file */
376                 if(sh_isstate(SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT))
377                         goto done;
378                 if(!sh_isoption(SH_INTERACTIVE) || sh_isstate(SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close() >=0))
379                 {
380                         sh_offstate(SH_INTERACTIVE|SH_MONITOR);
381                         goto done;
382                 }
383                 /* make sure that we own the terminal */
384 #ifdef SIGTSTP
385                 tcsetpgrp(job.fd,sh.pid);
386 #endif /* SIGTSTP */
387         }
388         /* error return here */
389         sfclrerr(iop);
390         sh_setstate(states);
391         sh.st.optindex = 1;
392         opt_char = 0;
393         sh.st.loopcnt = 0;
394         sh.trapnote = 0;
395         sh.intrap = 0;
396         error_info.line = 1;
397         sh.inlineno = 1;
398         sh.binscript = 0;
399         if(sfeof(iop))
400                 goto eof_or_error;
401         /* command loop */
402         while(1)
403         {
404                 sh.nextprompt = 1;
405                 sh_freeup();
406                 stakset(NIL(char*),0);
407                 exitset();
408                 sh_offstate(SH_STOPOK|SH_ERREXIT|SH_VERBOSE|SH_TIMING|SH_GRACE|SH_TTYWAIT);
409                 sh_onstate(sh_isoption(SH_VERBOSE)|SH_ERREXIT);
410                 /* -eim  flags don't apply to profiles */
411                 if(sh_isstate(SH_PROFILE))
412                         sh_offstate(SH_INTERACTIVE|SH_ERREXIT|SH_MONITOR);
413                 if(sh_isstate(SH_INTERACTIVE) && !tdone)
414                 {
415                         register char *mail;
416 #ifdef JOBS
417                         sh_offstate(SH_MONITOR);
418                         sh_onstate(sh_isoption(SH_MONITOR));
419                         if(job.pwlist)
420                         {
421                                 job_walk(sfstderr,job_list,JOB_NFLAG,(char**)0);
422                                 job_wait((pid_t)0);
423                         }
424 #endif  /* JOBS */
425                         if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD)))
426                         {
427                                 time(&curtime);
428                                 if ((curtime - mailtime) >= sh_mailchk)
429                                 {
430                                         chkmail(mail);
431                                         mailtime = curtime;
432                                 }
433                         }
434                         if(sh.hist_ptr)
435                                 hist_eof(sh.hist_ptr);
436                         /* sets timeout for command entry */
437                         sh.timeout = sh.tmout;
438 #ifdef SHOPT_TIMEOUT
439                         if(sh.timeout <= 0 || sh.timeout > SHOPT_TIMEOUT)
440                                 sh.timeout = SHOPT_TIMEOUT;
441 #endif /* SHOPT_TIMEOUT */
442                         sh.inlineno = 1;
443                         error_info.line = 1;
444                         if(buff.mode == SH_JMPEXIT)
445                         {
446                                 buff.mode = SH_JMPERREXIT;
447 #ifdef DEBUG
448                                 error(ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid());
449 #endif
450                         }
451                 }
452                 errno = 0;
453                 if(tdone || !sfreserve(iop,0,0))
454                 {
455                 eof_or_error:
456                         if(sh_isstate(SH_INTERACTIVE) && !sferror(iop)) 
457                         {
458                                 if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) &&
459                                          !sferror(sfstderr) && (sh.fdstatus[fno]&IOTTY))
460                                 {
461                                         sfclrerr(iop);
462                                         error(0,e_logout);
463                                         continue;
464                                 }
465                                 else if(job_close()<0)
466                                         continue;
467                         }
468                         if(errno==0 && sferror(iop) && --maxtry>0)
469                         {
470                                 sfclrlock(iop);
471                                 sfclrerr(iop);
472                                 continue;
473                         }
474                         goto done;
475                 }
476                 maxtry = IOMAXTRY;
477                 if(sh_isstate(SH_INTERACTIVE) && sh.hist_ptr)
478                 {
479                         hist_eof(sh.hist_ptr);
480                         sfsync(sfstderr);
481                 }
482                 sh_onstate(sh_isoption(SH_HISTORY));
483                 job.waitall = job.curpgid = 0;
484                 error_info.flags |= ERROR_INTERACTIVE;
485                 t = sh_parse(iop,0);
486                 if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_CFLAG))
487                         error_info.flags &= ~ERROR_INTERACTIVE;
488                 sh.readscript = 0;
489                 if(sh_isstate(SH_INTERACTIVE) && sh.hist_ptr)
490                         hist_flush(sh.hist_ptr);
491                 sh_offstate(SH_HISTORY);
492                 if(t)
493                 {
494                         execflags = (SH_ERREXIT|SH_INTERACTIVE);
495                         /* The last command may not have to fork */
496                         if(!(sh_isstate(SH_PROFILE|SH_INTERACTIVE)) &&
497                                 (fno<0 || !(sh.fdstatus[fno]&(IOTTY|IONOSEEK)))
498                                 && !sfreserve(iop,0,0))
499                         {
500                                         execflags |= SH_NOFORK;
501                         }
502                         sh.st.execbrk = 0;
503                         sh_exec(t,execflags);
504                         if(sh.forked)
505                         {
506                                 sh_offstate(SH_INTERACTIVE);
507                                 goto done;
508                         }
509                         /* This is for sh -t */
510                         if(sh_isoption(SH_TFLAG) && !sh_isstate(SH_PROFILE))
511                                 tdone++;
512                 }
513         }
514 done:
515         sh_popcontext(&buff);
516         if(sh_isstate(SH_INTERACTIVE))
517         {
518                 sfputc(sfstderr,'\n');
519                 job_close();
520         }
521         if(jmpval == SH_JMPSCRIPT)
522                 siglongjmp(*sh.jmplist,jmpval);
523         else if(jmpval == SH_JMPEXIT)
524                 sh_done(0);
525         if(fno>0)
526                 sh_close(fno);
527 }
528
529
530 /* prints out messages if files in list have been modified since last call */
531 static void chkmail __PARAM__((char *files), (files)) __OTORP__(char *files;){
532         register char *cp,*sp,*qp;
533         register char save;
534         struct argnod *arglist=0;
535         int     offset = staktell();
536         char    *savstak=stakptr(0);
537         struct stat     statb;
538         if(*(cp=files) == 0)
539                 return;
540         sp = cp;
541         do
542         {
543                 /* skip to : or end of string saving first '?' */
544                 for(qp=0;*sp && *sp != ':';sp++)
545                         if((*sp == '?' || *sp=='%') && qp == 0)
546                                 qp = sp;
547                 save = *sp;
548                 *sp = 0;
549                 /* change '?' to end-of-string */
550                 if(qp)
551                         *qp = 0;
552                 do
553                 {
554                         /* see if time has been modified since last checked
555                          * and the access time <= the modification time
556                          */
557                         if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime
558                                 && statb.st_atime <= statb.st_mtime)
559                         {
560                                 /* check for directory */
561                                 if(!arglist && S_ISDIR(statb.st_mode)) 
562                                 {
563                                         /* generate list of directory entries */
564                                         path_complete(cp,"/*",&arglist);
565                                 }
566                                 else
567                                 {
568                                         /*
569                                          * If the file has shrunk,
570                                          * or if the size is zero
571                                          * then don't print anything
572                                          */
573                                         if(statb.st_size &&
574                                                 (  statb.st_ino != lastmail.st_ino
575                                                 || statb.st_dev != lastmail.st_dev
576                                                 || statb.st_size > lastmail.st_size))
577                                         {
578                                                 /* save and restore $_ */
579                                                 char *save = sh.lastarg;
580                                                 sh.lastarg = cp;
581                                                 error(0,sh_mactry(qp?qp+1:(char*)e_mailmsg));
582                                                 sh.lastarg = save;
583                                         }
584                                         lastmail = statb;
585                                         break;
586                                 }
587                         }
588                         if(arglist)
589                         {
590                                 cp = arglist->argval;
591                                 arglist = arglist->argchn.ap;
592                         }
593                         else
594                                 cp = 0;
595                 }
596                 while(cp);
597                 if(qp)
598                         *qp = '?';
599                 *sp++ = save;
600                 cp = sp;
601         }
602         while(save);
603         stakset(savstak,offset);
604 }
605
606 #undef EXECARGS
607 #undef PSTAT
608 #if defined(_hdr_execargs) && defined(pdp11)
609 #   include     <execargs.h>
610 #   define EXECARGS     1
611 #endif
612
613 #if defined(_lib_pstat) && defined(_sys_pstat)
614 #   include     <sys/pstat.h>
615 #   define PSTAT        1
616 #endif
617
618 #if defined(_lib_fork) && !defined(_NEXT_SOURCE)
619 /*
620  * fix up command line for ps command
621  * mode is 0 for initialization
622  */
623 static void fixargs __PARAM__((char **argv, int mode), (argv, mode)) __OTORP__(char **argv; int mode;){
624 #if EXECARGS
625         *execargs=(char *)argv;
626 #else
627         static char *buff;
628         static int command_len;
629         register char *cp;
630         int offset=0,size;
631 #   ifdef PSTAT
632         union pstun un;
633         if(mode==0)
634         {
635                 struct pst_static st;
636                 un.pst_static = &st;
637                 if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0)
638                         return;
639                 command_len = st.command_length;
640                 return;
641         }
642         stakseek(command_len+2);
643         buff = stakseek(0);
644 #   else
645         if(mode==0)
646         {
647                 buff = argv[0];
648                 while(cp = *argv++)
649                         command_len += strlen(cp)+1;
650                 if(environ && *environ==buff+command_len)
651                 {
652                         for(argv=environ; cp = *argv; cp++)
653                         {
654                                 if(command_len > CMD_LENGTH)
655                                 {
656                                         command_len = CMD_LENGTH;
657                                         break;
658                                 }
659                                 *argv++ = strdup(cp);
660                                 command_len += strlen(cp)+1;
661                         }
662                 }
663                 command_len -= 1;
664                 return;
665         }
666 #   endif /* PSTAT */
667         if(command_len==0)
668                 return;
669         while((cp = *argv++) && offset < command_len)
670         {
671                 if(offset + (size=strlen(cp)) >= command_len)
672                         size = command_len - offset;
673                 memcpy(buff+offset,cp,size);
674                 offset += size;
675                 buff[offset++] = ' ';
676         }
677         buff[offset-1] = 0;
678         environ=0;
679 #   ifdef PSTAT
680         un.pst_command = stakptr(0);
681         pstat(PSTAT_SETCMD,un,0,0,0);
682 #   endif /* PSTAT */
683 #endif /* EXECARGS */
684 }
685 #endif /* _lib_fork */