1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 /* 22 * UNIX shell 23 * 24 * S. R. Bourne 25 * Rewritten By David Korn 26 * AT&T Labs 27 * 28 */ 29 30 #include <ast.h> 31 #include <sfio.h> 32 #include <stak.h> 33 #include <ls.h> 34 #include <fcin.h> 35 #include "defs.h" 36 #include "variables.h" 37 #include "path.h" 38 #include "io.h" 39 #include "jobs.h" 40 #include "shnodes.h" 41 #include "history.h" 42 #include "timeout.h" 43 #include "FEATURE/time" 44 #include "FEATURE/pstat" 45 #include "FEATURE/execargs" 46 #include "FEATURE/externs" 47 #ifdef _hdr_nc 48 # include <nc.h> 49 #endif /* _hdr_nc */ 50 51 #define CMD_LENGTH 64 52 53 /* These routines are referenced by this module */ 54 static void exfile(Shell_t*, Sfio_t*,int); 55 static void chkmail(Shell_t *shp, char*); 56 #if defined(_lib_fork) && !defined(_NEXT_SOURCE) 57 static void fixargs(char**,int); 58 #else 59 # define fixargs(a,b) 60 #endif 61 62 #ifndef environ 63 extern char **environ; 64 #endif 65 66 static struct stat lastmail; 67 static time_t mailtime; 68 static char beenhere = 0; 69 70 #ifdef _lib_sigvec 71 void clearsigmask(register int sig) 72 { 73 struct sigvec vec; 74 if(sigvec(sig,NIL(struct sigvec*),&vec)>=0 && vec.sv_mask) 75 { 76 vec.sv_mask = 0; 77 sigvec(sig,&vec,NIL(struct sigvec*)); 78 } 79 } 80 #endif /* _lib_sigvec */ 81 82 #ifdef _lib_fts_notify 83 # include <fts.h> 84 /* check for interrupts during tree walks */ 85 static int fts_sigcheck(FTS* fp, FTSENT* ep, void* context) 86 { 87 Shell_t *shp = (Shell_t*)context; 88 NOT_USED(fp); 89 NOT_USED(ep); 90 if(shp->trapnote&SH_SIGSET) 91 { 92 errno = EINTR; 93 return(-1); 94 } 95 return(0); 96 } 97 #endif /* _lib_fts_notify */ 98 99 #ifdef PATH_BFPATH 100 #define PATHCOMP NIL(Pathcomp_t*) 101 #else 102 #define PATHCOMP "" 103 #endif 104 105 /* 106 * search for file and exfile() it if it exists 107 * 1 returned if file found, 0 otherwise 108 */ 109 110 int sh_source(Shell_t *shp, Sfio_t *iop, const char *file) 111 { 112 char* oid; 113 char* nid; 114 int fd; 115 116 if (!file || !*file || (fd = path_open(file, PATHCOMP)) < 0) 117 return 0; 118 oid = error_info.id; 119 nid = error_info.id = strdup(file); 120 shp->st.filename = path_fullname(stakptr(PATH_OFFSET)); 121 exfile(shp, iop, fd); 122 error_info.id = oid; 123 free(nid); 124 return 1; 125 } 126 127 #ifdef S_ISSOCK 128 #define REMOTE(m) (S_ISSOCK(m)||!(m)) 129 #else 130 #define REMOTE(m) !(m) 131 #endif 132 133 int sh_main(int ac, char *av[], void (*userinit)(int)) 134 { 135 register char *name; 136 register int fdin; 137 register Sfio_t *iop; 138 register Shell_t *shp; 139 struct stat statb; 140 int i, rshflag; /* set for restricted shell */ 141 char *command; 142 #ifdef _lib_sigvec 143 /* This is to clear mask that my be left on by rlogin */ 144 clearsigmask(SIGALRM); 145 clearsigmask(SIGHUP); 146 clearsigmask(SIGCHLD); 147 #endif /* _lib_sigvec */ 148 #ifdef _hdr_nc 149 _NutConf(_NC_SET_SUFFIXED_SEARCHING, 1); 150 #endif /* _hdr_nc */ 151 fixargs(av,0); 152 shp = sh_init(ac,av,userinit); 153 time(&mailtime); 154 if(rshflag=sh_isoption(SH_RESTRICTED)) 155 sh_offoption(SH_RESTRICTED); 156 #ifdef _lib_fts_notify 157 fts_notify(fts_sigcheck,(void*)shp); 158 #endif /* _lib_fts_notify */ 159 if(sigsetjmp(*((sigjmp_buf*)shp->jmpbuffer),0)) 160 { 161 /* begin script execution here */ 162 sh_reinit((char**)0); 163 if(rshflag) 164 sh_onoption(SH_RESTRICTED); 165 } 166 shp->fn_depth = shp->dot_depth = 0; 167 command = error_info.id; 168 /* set pidname '$$' */ 169 shp->pid = getpid(); 170 srand(shp->pid&0x7fff); 171 shp->ppid = getppid(); 172 if(nv_isnull(PS4NOD)) 173 nv_putval(PS4NOD,e_traceprompt,NV_RDONLY); 174 path_pwd(1); 175 iop = (Sfio_t*)0; 176 #if SHOPT_BRACEPAT 177 sh_onoption(SH_BRACEEXPAND); 178 #endif 179 if((beenhere++)==0) 180 { 181 sh_onstate(SH_PROFILE); 182 if(shp->ppid==1) 183 shp->login_sh++; 184 if(shp->login_sh >= 2) 185 sh_onoption(SH_LOGIN_SHELL); 186 /* decide whether shell is interactive */ 187 if(!sh_isoption(SH_TFLAG) && !sh_isoption(SH_CFLAG) && sh_isoption(SH_SFLAG) && 188 tty_check(0) && tty_check(ERRIO)) 189 { 190 sh_onoption(SH_INTERACTIVE); 191 sh_onoption(SH_BGNICE); 192 sh_onoption(SH_RC); 193 } 194 if(!sh_isoption(SH_RC) && (sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX) 195 #if SHOPT_REMOTE 196 || !fstat(0, &statb) && REMOTE(statb.st_mode) 197 #endif 198 )) 199 sh_onoption(SH_RC); 200 for(i=0; i<elementsof(sh.offoptions.v); i++) 201 sh.options.v[i] &= ~sh.offoptions.v[i]; 202 if(sh_isoption(SH_INTERACTIVE)) 203 { 204 #ifdef SIGXCPU 205 signal(SIGXCPU,SIG_DFL); 206 #endif /* SIGXCPU */ 207 #ifdef SIGXFSZ 208 signal(SIGXFSZ,SIG_DFL); 209 #endif /* SIGXFSZ */ 210 sh_onoption(SH_MONITOR); 211 } 212 job_init(sh_isoption(SH_LOGIN_SHELL)); 213 if(sh_isoption(SH_LOGIN_SHELL) && !sh_isoption(SH_NOPROFILE)) 214 { 215 /* system profile */ 216 sh_source(shp, iop, e_sysprofile); 217 if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED)) 218 { 219 char **files = shp->login_files; 220 while ((name = *files++) && !sh_source(shp, iop, sh_mactry(name))); 221 } 222 } 223 /* make sure PWD is set up correctly */ 224 path_pwd(1); 225 if(!sh_isoption(SH_NOEXEC)) 226 { 227 if(!sh_isoption(SH_NOUSRPROFILE) && !sh_isoption(SH_PRIVILEGED) && sh_isoption(SH_RC)) 228 { 229 #if SHOPT_BASH 230 if(sh_isoption(SH_BASH) && !sh_isoption(SH_POSIX)) 231 { 232 #if SHOPT_SYSRC 233 sh_source(shp, iop, e_bash_sysrc); 234 #endif 235 sh_source(shp, iop, shp->rcfile ? shp->rcfile : sh_mactry((char*)e_bash_rc)); 236 } 237 else 238 #endif 239 { 240 #if SHOPT_SYSRC 241 sh_source(shp, iop, e_sysrc); 242 #endif 243 sh_source(shp, iop, sh_mactry(nv_getval(ENVNOD))); 244 } 245 } 246 else if(sh_isoption(SH_INTERACTIVE) && sh_isoption(SH_PRIVILEGED)) 247 sh_source(shp, iop, e_suidprofile); 248 } 249 shp->st.cmdname = error_info.id = command; 250 sh_offstate(SH_PROFILE); 251 if(rshflag) 252 sh_onoption(SH_RESTRICTED); 253 /* open input file if specified */ 254 if(shp->comdiv) 255 { 256 shell_c: 257 iop = sfnew(NIL(Sfio_t*),shp->comdiv,strlen(shp->comdiv),0,SF_STRING|SF_READ); 258 } 259 else 260 { 261 name = error_info.id; 262 error_info.id = shp->shname; 263 if(sh_isoption(SH_SFLAG)) 264 fdin = 0; 265 else 266 { 267 char *sp; 268 /* open stream should have been passed into shell */ 269 if(strmatch(name,e_devfdNN)) 270 { 271 char *cp; 272 int type; 273 fdin = (int)strtol(name+8, (char**)0, 10); 274 if(fstat(fdin,&statb)<0) 275 errormsg(SH_DICT,ERROR_system(1),e_open,error_info.id); 276 #if !_WINIX 277 /* 278 * try to undo effect of solaris 2.5+ 279 * change for argv for setuid scripts 280 */ 281 if(((type = sh_type(cp = av[0])) & SH_TYPE_SH) && (!(name = nv_getval(L_ARGNOD)) || !((type = sh_type(cp = name)) & SH_TYPE_SH))) 282 { 283 av[0] = (type & SH_TYPE_LOGIN) ? cp : path_basename(cp); 284 /* exec to change $0 for ps */ 285 execv(pathshell(),av); 286 /* exec fails */ 287 shp->st.dolv[0] = av[0]; 288 fixargs(shp->st.dolv,1); 289 } 290 #endif 291 name = av[0]; 292 sh_offoption(SH_VERBOSE); 293 sh_offoption(SH_XTRACE); 294 } 295 else 296 { 297 int isdir = 0; 298 if((fdin=sh_open(name,O_RDONLY,0))>=0 &&(fstat(fdin,&statb)<0 || S_ISDIR(statb.st_mode))) 299 { 300 close(fdin); 301 isdir = 1; 302 fdin = -1; 303 } 304 else 305 shp->st.filename = path_fullname(name); 306 sp = 0; 307 if(fdin < 0 && !strchr(name,'/')) 308 { 309 #ifdef PATH_BFPATH 310 if(path_absolute(name,NIL(Pathcomp_t*))) 311 sp = stakptr(PATH_OFFSET); 312 #else 313 sp = path_absolute(name,NIL(char*)); 314 #endif 315 if(sp) 316 { 317 if((fdin=sh_open(sp,O_RDONLY,0))>=0) 318 shp->st.filename = path_fullname(sp); 319 } 320 } 321 if(fdin<0) 322 { 323 if(isdir) 324 errno = EISDIR; 325 error_info.id = av[0]; 326 if(sp || errno!=ENOENT) 327 errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_open,name); 328 /* try sh -c 'name "$@"' */ 329 sh_onoption(SH_CFLAG); 330 shp->comdiv = (char*)malloc(strlen(name)+7); 331 name = strcopy(shp->comdiv,name); 332 if(shp->st.dolc) 333 strcopy(name," \"$@\""); 334 goto shell_c; 335 } 336 if(fdin==0) 337 fdin = sh_iomovefd(fdin); 338 } 339 shp->readscript = shp->shname; 340 } 341 error_info.id = name; 342 shp->comdiv--; 343 #if SHOPT_ACCT 344 sh_accinit(); 345 if(fdin != 0) 346 sh_accbegin(error_info.id); 347 #endif /* SHOPT_ACCT */ 348 } 349 } 350 else 351 { 352 fdin = shp->infd; 353 fixargs(shp->st.dolv,1); 354 } 355 if(sh_isoption(SH_INTERACTIVE)) 356 sh_onstate(SH_INTERACTIVE); 357 nv_putval(IFSNOD,(char*)e_sptbnl,NV_RDONLY); 358 exfile(shp,iop,fdin); 359 sh_done(0); 360 /* NOTREACHED */ 361 return(0); 362 } 363 364 /* 365 * iop is not null when the input is a string 366 * fdin is the input file descriptor 367 */ 368 369 static void exfile(register Shell_t *shp, register Sfio_t *iop,register int fno) 370 { 371 time_t curtime; 372 Shnode_t *t; 373 int maxtry=IOMAXTRY, tdone=0, execflags; 374 int states,jmpval; 375 struct checkpt buff; 376 sh_pushcontext(&buff,SH_JMPERREXIT); 377 /* open input stream */ 378 nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE); 379 if(!iop) 380 { 381 if(fno > 0) 382 { 383 int r; 384 if(fno < 10 && ((r=sh_fcntl(fno,F_DUPFD,10))>=10)) 385 { 386 shp->fdstatus[r] = shp->fdstatus[fno]; 387 sh_close(fno); 388 fno = r; 389 } 390 fcntl(fno,F_SETFD,FD_CLOEXEC); 391 shp->fdstatus[fno] |= IOCLEX; 392 iop = sh_iostream(fno); 393 } 394 else 395 iop = sfstdin; 396 } 397 else 398 fno = -1; 399 shp->infd = fno; 400 if(sh_isstate(SH_INTERACTIVE)) 401 { 402 if(nv_isnull(PS1NOD)) 403 nv_putval(PS1NOD,(shp->euserid?e_stdprompt:e_supprompt),NV_RDONLY); 404 sh_sigdone(); 405 if(sh_histinit()) 406 sh_onoption(SH_HISTORY); 407 } 408 else 409 { 410 if(!sh_isstate(SH_PROFILE)) 411 { 412 buff.mode = SH_JMPEXIT; 413 sh_onoption(SH_TRACKALL); 414 sh_offoption(SH_MONITOR); 415 } 416 sh_offstate(SH_INTERACTIVE); 417 sh_offstate(SH_MONITOR); 418 sh_offstate(SH_HISTORY); 419 sh_offoption(SH_HISTORY); 420 } 421 states = sh_getstate(); 422 jmpval = sigsetjmp(buff.buff,0); 423 if(jmpval) 424 { 425 Sfio_t *top; 426 sh_iorestore(0,jmpval); 427 hist_flush(shp->hist_ptr); 428 sfsync(shp->outpool); 429 shp->st.execbrk = shp->st.breakcnt = 0; 430 /* check for return from profile or env file */ 431 if(sh_isstate(SH_PROFILE) && (jmpval==SH_JMPFUN || jmpval==SH_JMPEXIT)) 432 goto done; 433 if(!sh_isoption(SH_INTERACTIVE) || sh_isstate(SH_FORKED) || (jmpval > SH_JMPERREXIT && job_close() >=0)) 434 { 435 sh_offstate(SH_INTERACTIVE); 436 sh_offstate(SH_MONITOR); 437 goto done; 438 } 439 /* skip over remaining input */ 440 if(top = fcfile()) 441 { 442 while(fcget()>0); 443 fcclose(); 444 while(top=sfstack(iop,SF_POPSTACK)) 445 sfclose(top); 446 } 447 /* make sure that we own the terminal */ 448 #ifdef SIGTSTP 449 tcsetpgrp(job.fd,shp->pid); 450 #endif /* SIGTSTP */ 451 } 452 /* error return here */ 453 sfclrerr(iop); 454 sh_setstate(states); 455 shp->st.optindex = 1; 456 opt_info.offset = 0; 457 shp->st.loopcnt = 0; 458 shp->trapnote = 0; 459 shp->intrap = 0; 460 error_info.line = 1; 461 shp->inlineno = 1; 462 shp->binscript = 0; 463 if(sfeof(iop)) 464 goto eof_or_error; 465 /* command loop */ 466 while(1) 467 { 468 shp->nextprompt = 1; 469 sh_freeup(); 470 stakset(NIL(char*),0); 471 exitset(); 472 sh_offstate(SH_STOPOK); 473 sh_offstate(SH_ERREXIT); 474 sh_offstate(SH_VERBOSE); 475 sh_offstate(SH_TIMING); 476 sh_offstate(SH_GRACE); 477 sh_offstate(SH_TTYWAIT); 478 if(sh_isoption(SH_VERBOSE)) 479 sh_onstate(SH_VERBOSE); 480 sh_onstate(SH_ERREXIT); 481 /* -eim flags don't apply to profiles */ 482 if(sh_isstate(SH_PROFILE)) 483 { 484 sh_offstate(SH_INTERACTIVE); 485 sh_offstate(SH_ERREXIT); 486 sh_offstate(SH_MONITOR); 487 } 488 if(sh_isstate(SH_INTERACTIVE) && !tdone) 489 { 490 register char *mail; 491 #ifdef JOBS 492 sh_offstate(SH_MONITOR); 493 if(sh_isoption(SH_MONITOR)) 494 sh_onstate(SH_MONITOR); 495 if(job.pwlist) 496 { 497 job_walk(sfstderr,job_list,JOB_NFLAG,(char**)0); 498 job_wait((pid_t)0); 499 } 500 #endif /* JOBS */ 501 if((mail=nv_getval(MAILPNOD)) || (mail=nv_getval(MAILNOD))) 502 { 503 time(&curtime); 504 if ((curtime - mailtime) >= sh_mailchk) 505 { 506 chkmail(shp,mail); 507 mailtime = curtime; 508 } 509 } 510 if(shp->hist_ptr) 511 hist_eof(shp->hist_ptr); 512 /* sets timeout for command entry */ 513 shp->timeout = shp->st.tmout; 514 #if SHOPT_TIMEOUT 515 if(shp->timeout <= 0 || shp->timeout > SHOPT_TIMEOUT) 516 shp->timeout = SHOPT_TIMEOUT; 517 #endif /* SHOPT_TIMEOUT */ 518 shp->inlineno = 1; 519 error_info.line = 1; 520 shp->exitval = 0; 521 shp->trapnote = 0; 522 if(buff.mode == SH_JMPEXIT) 523 { 524 buff.mode = SH_JMPERREXIT; 525 #ifdef DEBUG 526 errormsg(SH_DICT,ERROR_warn(0),"%d: mode changed to JMP_EXIT",getpid()); 527 #endif 528 } 529 } 530 errno = 0; 531 if(tdone || !sfreserve(iop,0,0)) 532 { 533 eof_or_error: 534 if(sh_isstate(SH_INTERACTIVE) && !sferror(iop)) 535 { 536 if(--maxtry>0 && sh_isoption(SH_IGNOREEOF) && 537 !sferror(sfstderr) && (shp->fdstatus[fno]&IOTTY)) 538 { 539 sfclrerr(iop); 540 errormsg(SH_DICT,0,e_logout); 541 continue; 542 } 543 else if(job_close()<0) 544 continue; 545 } 546 if(errno==0 && sferror(iop) && --maxtry>0) 547 { 548 sfclrlock(iop); 549 sfclrerr(iop); 550 continue; 551 } 552 goto done; 553 } 554 maxtry = IOMAXTRY; 555 if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr) 556 { 557 job_wait((pid_t)0); 558 hist_eof(shp->hist_ptr); 559 sfsync(sfstderr); 560 } 561 if(sh_isoption(SH_HISTORY)) 562 sh_onstate(SH_HISTORY); 563 job.waitall = job.curpgid = 0; 564 error_info.flags |= ERROR_INTERACTIVE; 565 t = (Shnode_t*)sh_parse(shp,iop,0); 566 if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_CFLAG)) 567 error_info.flags &= ~ERROR_INTERACTIVE; 568 shp->readscript = 0; 569 if(sh_isstate(SH_INTERACTIVE) && shp->hist_ptr) 570 hist_flush(shp->hist_ptr); 571 sh_offstate(SH_HISTORY); 572 if(t) 573 { 574 execflags = sh_state(SH_ERREXIT)|sh_state(SH_INTERACTIVE); 575 /* The last command may not have to fork */ 576 if(!sh_isstate(SH_PROFILE) && !sh_isstate(SH_INTERACTIVE) && 577 (fno<0 || !(shp->fdstatus[fno]&(IOTTY|IONOSEEK))) 578 && !sfreserve(iop,0,0)) 579 { 580 execflags |= sh_state(SH_NOFORK); 581 } 582 shp->st.execbrk = 0; 583 sh_exec(t,execflags); 584 if(shp->forked) 585 { 586 sh_offstate(SH_INTERACTIVE); 587 goto done; 588 } 589 /* This is for sh -t */ 590 if(sh_isoption(SH_TFLAG) && !sh_isstate(SH_PROFILE)) 591 tdone++; 592 } 593 } 594 done: 595 sh_popcontext(&buff); 596 if(sh_isstate(SH_INTERACTIVE)) 597 { 598 sfputc(sfstderr,'\n'); 599 job_close(); 600 } 601 if(jmpval == SH_JMPSCRIPT) 602 siglongjmp(*shp->jmplist,jmpval); 603 else if(jmpval == SH_JMPEXIT) 604 sh_done(0); 605 if(fno>0) 606 sh_close(fno); 607 if(shp->st.filename) 608 free((void*)shp->st.filename); 609 shp->st.filename = 0; 610 } 611 612 613 /* prints out messages if files in list have been modified since last call */ 614 static void chkmail(Shell_t *shp, char *files) 615 { 616 register char *cp,*sp,*qp; 617 register char save; 618 struct argnod *arglist=0; 619 int offset = staktell(); 620 char *savstak=stakptr(0); 621 struct stat statb; 622 if(*(cp=files) == 0) 623 return; 624 sp = cp; 625 do 626 { 627 /* skip to : or end of string saving first '?' */ 628 for(qp=0;*sp && *sp != ':';sp++) 629 if((*sp == '?' || *sp=='%') && qp == 0) 630 qp = sp; 631 save = *sp; 632 *sp = 0; 633 /* change '?' to end-of-string */ 634 if(qp) 635 *qp = 0; 636 do 637 { 638 /* see if time has been modified since last checked 639 * and the access time <= the modification time 640 */ 641 if(stat(cp,&statb) >= 0 && statb.st_mtime >= mailtime 642 && statb.st_atime <= statb.st_mtime) 643 { 644 /* check for directory */ 645 if(!arglist && S_ISDIR(statb.st_mode)) 646 { 647 /* generate list of directory entries */ 648 path_complete(cp,"/*",&arglist); 649 } 650 else 651 { 652 /* 653 * If the file has shrunk, 654 * or if the size is zero 655 * then don't print anything 656 */ 657 if(statb.st_size && 658 ( statb.st_ino != lastmail.st_ino 659 || statb.st_dev != lastmail.st_dev 660 || statb.st_size > lastmail.st_size)) 661 { 662 /* save and restore $_ */ 663 char *save = shp->lastarg; 664 shp->lastarg = cp; 665 errormsg(SH_DICT,0,sh_mactry(qp?qp+1:(char*)e_mailmsg)); 666 shp->lastarg = save; 667 } 668 lastmail = statb; 669 break; 670 } 671 } 672 if(arglist) 673 { 674 cp = arglist->argval; 675 arglist = arglist->argchn.ap; 676 } 677 else 678 cp = 0; 679 } 680 while(cp); 681 if(qp) 682 *qp = '?'; 683 *sp++ = save; 684 cp = sp; 685 } 686 while(save); 687 stakset(savstak,offset); 688 } 689 690 #undef EXECARGS 691 #undef PSTAT 692 #if defined(_hdr_execargs) && defined(pdp11) 693 # include <execargs.h> 694 # define EXECARGS 1 695 #endif 696 697 #if defined(_lib_pstat) && defined(_sys_pstat) 698 # include <sys/pstat.h> 699 # define PSTAT 1 700 #endif 701 702 #if defined(_lib_fork) && !defined(_NEXT_SOURCE) 703 /* 704 * fix up command line for ps command 705 * mode is 0 for initialization 706 */ 707 static void fixargs(char **argv, int mode) 708 { 709 #if EXECARGS 710 *execargs=(char *)argv; 711 #else 712 static char *buff; 713 static int command_len; 714 register char *cp; 715 int offset=0,size; 716 # ifdef PSTAT 717 union pstun un; 718 if(mode==0) 719 { 720 struct pst_static st; 721 un.pst_static = &st; 722 if(pstat(PSTAT_STATIC, un, sizeof(struct pst_static), 1, 0)<0) 723 return; 724 command_len = st.command_length; 725 return; 726 } 727 stakseek(command_len+2); 728 buff = stakseek(0); 729 # else 730 if(mode==0) 731 { 732 buff = argv[0]; 733 while(cp = *argv++) 734 command_len += strlen(cp)+1; 735 if(environ && *environ==buff+command_len) 736 { 737 for(argv=environ; cp = *argv; cp++) 738 { 739 if(command_len > CMD_LENGTH) 740 { 741 command_len = CMD_LENGTH; 742 break; 743 } 744 *argv++ = strdup(cp); 745 command_len += strlen(cp)+1; 746 } 747 } 748 command_len -= 1; 749 return; 750 } 751 # endif /* PSTAT */ 752 if(command_len==0) 753 return; 754 while((cp = *argv++) && offset < command_len) 755 { 756 if(offset + (size=strlen(cp)) >= command_len) 757 size = command_len - offset; 758 memcpy(buff+offset,cp,size); 759 offset += size; 760 buff[offset++] = ' '; 761 } 762 buff[offset-1] = 0; 763 # ifdef PSTAT 764 un.pst_command = stakptr(0); 765 pstat(PSTAT_SETCMD,un,0,0,0); 766 # endif /* PSTAT */ 767 #endif /* EXECARGS */ 768 } 769 #endif /* _lib_fork */ 770