17c478bd9Sstevel@tonic-gate /* 2*134a1f4eSCasper H.S. Dik * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 37c478bd9Sstevel@tonic-gate */ 47c478bd9Sstevel@tonic-gate 57c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 67c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 77c478bd9Sstevel@tonic-gate 87c478bd9Sstevel@tonic-gate /* 97c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 107c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley Software License Agreement 117c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 127c478bd9Sstevel@tonic-gate */ 137c478bd9Sstevel@tonic-gate 147c478bd9Sstevel@tonic-gate #include <locale.h> 157c478bd9Sstevel@tonic-gate #include "sh.h" 167c478bd9Sstevel@tonic-gate /* #include <sys/ioctl.h> */ 177c478bd9Sstevel@tonic-gate #include <fcntl.h> 187c478bd9Sstevel@tonic-gate #include <sys/filio.h> 197c478bd9Sstevel@tonic-gate #include "sh.tconst.h" 207c478bd9Sstevel@tonic-gate #include <pwd.h> 217c478bd9Sstevel@tonic-gate #include <stdlib.h> 2284368791Smuffin #ifdef TRACE 2384368791Smuffin #include <stdio.h> 2484368791Smuffin #endif 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * We use these csh(1) private versions of the select macros, (see select(3C)) 287c478bd9Sstevel@tonic-gate * so as not to be limited by the size of struct fd_set (ie 1024). 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate #define CSH_FD_SET(n, p) ((*((p) + ((n)/NFDBITS))) |= (1 << ((n) % NFDBITS))) 317c478bd9Sstevel@tonic-gate #define CSH_FD_CLR(n, p) ((*((p) + ((n)/NFDBITS))) &= ~(1 << ((n) % NFDBITS))) 327c478bd9Sstevel@tonic-gate #define CSH_FD_ISSET(n, p) ((*((p) + ((n)/NFDBITS))) & (1 << ((n) % NFDBITS))) 337c478bd9Sstevel@tonic-gate #define CSH_FD_ZERO(p, n) memset((void *)(p), 0, (n)) 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate tchar *pathlist[] = { S_usrbin /* "/usr/bin" */, S_DOT /* "." */, 0 }; 367c478bd9Sstevel@tonic-gate tchar *dumphist[] = { S_history /* "history" */, S_h /* "-h" */, 0, 0 }; 37*134a1f4eSCasper H.S. Dik tchar *loadhist[] = { S_source /* "source" */, S_h /* "-h" */, 38*134a1f4eSCasper H.S. Dik S_NDOThistory /* "~/.history" */, 0 }; 397c478bd9Sstevel@tonic-gate tchar HIST = '!'; 407c478bd9Sstevel@tonic-gate tchar HISTSUB = '^'; 417c478bd9Sstevel@tonic-gate int nofile; 427c478bd9Sstevel@tonic-gate bool reenter; 437c478bd9Sstevel@tonic-gate bool nverbose; 447c478bd9Sstevel@tonic-gate bool nexececho; 457c478bd9Sstevel@tonic-gate bool quitit; 467c478bd9Sstevel@tonic-gate bool fast; 477c478bd9Sstevel@tonic-gate bool batch; 487c478bd9Sstevel@tonic-gate bool prompt = 1; 497c478bd9Sstevel@tonic-gate bool enterhist = 0; 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate extern gid_t getegid(), getgid(); 527c478bd9Sstevel@tonic-gate extern uid_t geteuid(), getuid(); 537c478bd9Sstevel@tonic-gate extern tchar **strblktotsblk(/* char **, int */); 547c478bd9Sstevel@tonic-gate 552b51d29aSmg147109 extern void hupforegnd(void); 562b51d29aSmg147109 void interactive_hup(void); 572b51d29aSmg147109 void interactive_login_hup(void); 582b51d29aSmg147109 596c02b4a4Smuffin void importpath(tchar *); 606c02b4a4Smuffin void srccat(tchar *, tchar *); 616c02b4a4Smuffin void srccat_inlogin(tchar *, tchar *); 626c02b4a4Smuffin void srcunit(int, bool, bool); 636c02b4a4Smuffin void rechist(void); 646c02b4a4Smuffin void goodbye(void); 656c02b4a4Smuffin void pintr1(bool); 666c02b4a4Smuffin void process(bool); 676c02b4a4Smuffin void dosource(tchar **); 686c02b4a4Smuffin void mailchk(void); 696c02b4a4Smuffin void printprompt(void); 706c02b4a4Smuffin void sigwaiting(void); 716c02b4a4Smuffin void siglwp(void); 726c02b4a4Smuffin void initdesc(int, char *[]); 736c02b4a4Smuffin void initdesc_x(int, char *[], int); 746c02b4a4Smuffin void closem(void); 756c02b4a4Smuffin void unsetfd(int); 766c02b4a4Smuffin void phup(void); 777c478bd9Sstevel@tonic-gate 7884368791Smuffin #ifdef TRACE 7984368791Smuffin FILE *trace; 8084368791Smuffin /* 8184368791Smuffin * Trace routines 8284368791Smuffin */ 8384368791Smuffin #define TRACEFILE "/tmp/trace.XXXXXX" 8484368791Smuffin 8584368791Smuffin /* 8684368791Smuffin * Initialize trace file. 8784368791Smuffin * Called from main. 8884368791Smuffin */ 8984368791Smuffin void 9084368791Smuffin trace_init(void) 9184368791Smuffin { 9284368791Smuffin char name[128]; 9384368791Smuffin char *p; 9484368791Smuffin 9584368791Smuffin strcpy(name, TRACEFILE); 9684368791Smuffin p = mktemp(name); 9784368791Smuffin trace = fopen(p, "w"); 9884368791Smuffin } 9984368791Smuffin 10084368791Smuffin /* 10184368791Smuffin * write message to trace file 10284368791Smuffin */ 10384368791Smuffin /*VARARGS1*/ 10484368791Smuffin void 10584368791Smuffin tprintf(fmt, a, b, c, d, e, f, g, h, i, j) 10684368791Smuffin char *fmt; 10784368791Smuffin { 10884368791Smuffin if (trace) { 10984368791Smuffin fprintf(trace, fmt, a, b, c, d, e, f, g, h, i, j); 11084368791Smuffin fflush(trace); 11184368791Smuffin } 11284368791Smuffin } 11384368791Smuffin #endif 1146c02b4a4Smuffin 1156c02b4a4Smuffin int 1166c02b4a4Smuffin main(int c, char **av) 1177c478bd9Sstevel@tonic-gate { 118*134a1f4eSCasper H.S. Dik tchar **v, *cp, *r; 1196c02b4a4Smuffin int f; 1207c478bd9Sstevel@tonic-gate struct sigvec osv; 1217c478bd9Sstevel@tonic-gate struct sigaction sa; 1227c478bd9Sstevel@tonic-gate tchar s_prompt[MAXHOSTNAMELEN+3]; 1231de7ff79Sjonb char *c_max_var_len; 1241de7ff79Sjonb int c_max_var_len_size; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate /* 1277c478bd9Sstevel@tonic-gate * set up the error exit, if there is an error before 1287c478bd9Sstevel@tonic-gate * this is done, it will core dump, and we don't 1297c478bd9Sstevel@tonic-gate * tolerate core dumps 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate haderr = 0; 1327c478bd9Sstevel@tonic-gate setexit(); 1337c478bd9Sstevel@tonic-gate if (haderr) { 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * if were here, there was an error in the csh 1367c478bd9Sstevel@tonic-gate * startup so just punt 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate printf("csh startup error, csh exiting...\n"); 1397c478bd9Sstevel@tonic-gate flush(); 1407c478bd9Sstevel@tonic-gate exitstat(); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1457c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1467c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1477c478bd9Sstevel@tonic-gate #endif 1487c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* Copy arguments */ 1517c478bd9Sstevel@tonic-gate v = strblktotsblk(av, c); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Initialize paraml list 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate paraml.next = paraml.prev = ¶ml; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate settimes(); /* Immed. estab. timing base */ 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate if (eq(v[0], S_aout /* "a.out" */)) /* A.out's are quittable */ 1617c478bd9Sstevel@tonic-gate quitit = 1; 1627c478bd9Sstevel@tonic-gate uid = getuid(); 1637c478bd9Sstevel@tonic-gate loginsh = **v == '-'; 1647c478bd9Sstevel@tonic-gate if (loginsh) 1657c478bd9Sstevel@tonic-gate (void) time(&chktim); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Move the descriptors to safe places. 1697c478bd9Sstevel@tonic-gate * The variable didfds is 0 while we have only FSH* to work with. 1707c478bd9Sstevel@tonic-gate * When didfds is true, we have 0,1,2 and prefer to use these. 1717c478bd9Sstevel@tonic-gate * 1727c478bd9Sstevel@tonic-gate * Also, setup data for csh internal file descriptor book keeping. 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate initdesc(c, av); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * Initialize the shell variables. 1787c478bd9Sstevel@tonic-gate * ARGV and PROMPT are initialized later. 1797c478bd9Sstevel@tonic-gate * STATUS is also munged in several places. 1807c478bd9Sstevel@tonic-gate * CHILD is munged when forking/waiting 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate 1831de7ff79Sjonb c_max_var_len_size = snprintf(NULL, 0, "%ld", MAX_VAR_LEN); 1841de7ff79Sjonb c_max_var_len = (char *)xalloc(c_max_var_len_size + 1); 1851de7ff79Sjonb (void) snprintf(c_max_var_len, (c_max_var_len_size + 1), 1861de7ff79Sjonb "%ld", MAX_VAR_LEN); 1871de7ff79Sjonb set(S_SUNW_VARLEN, strtots(NOSTR, c_max_var_len)); 1881de7ff79Sjonb xfree(c_max_var_len); 1891de7ff79Sjonb 1907c478bd9Sstevel@tonic-gate /* don't do globbing here, just set exact copies */ 1917c478bd9Sstevel@tonic-gate setNS(S_noglob); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate set(S_status /* "status" */, S_0 /* "0" */); 1947c478bd9Sstevel@tonic-gate dinit(cp = getenvs_("HOME")); /* dinit thinks that HOME==cwd in a */ 1957c478bd9Sstevel@tonic-gate /* login shell */ 1967c478bd9Sstevel@tonic-gate if (cp == NOSTR) 1977c478bd9Sstevel@tonic-gate fast++; /* No home -> can't read scripts */ 1987c478bd9Sstevel@tonic-gate else { 1997c478bd9Sstevel@tonic-gate if (strlen_(cp) >= BUFSIZ - 10) { 2007c478bd9Sstevel@tonic-gate cp = NOSTR; 2017c478bd9Sstevel@tonic-gate fast++; 2027c478bd9Sstevel@tonic-gate printf("%s\n", gettext("Pathname too long")); 2037c478bd9Sstevel@tonic-gate set(S_home /* "home" */, savestr(cp)); 2047c478bd9Sstevel@tonic-gate local_setenv(S_HOME, savestr(cp)); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate set(S_home /* "home" */, savestr(cp)); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate /* 2097c478bd9Sstevel@tonic-gate * Grab other useful things from the environment. 2107c478bd9Sstevel@tonic-gate * Should we grab everything?? 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate if ((cp = getenvs_("USER")) != NOSTR) 2137c478bd9Sstevel@tonic-gate set(S_user /* "user" */, savestr(cp)); 2147c478bd9Sstevel@tonic-gate else { 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * If USER is not defined, set it here. 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate struct passwd *pw; 2197c478bd9Sstevel@tonic-gate pw = getpwuid(getuid()); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate if (pw != NULL) { 2227c478bd9Sstevel@tonic-gate set(S_user, strtots((tchar *)0, pw->pw_name)); 2237c478bd9Sstevel@tonic-gate local_setenv(S_USER, strtots((tchar *)0, pw->pw_name)); 224*134a1f4eSCasper H.S. Dik } else if (loginsh) { /* Give up setting USER variable. */ 2257c478bd9Sstevel@tonic-gate printf("Warning: USER environment variable could not be set.\n"); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate if ((cp = getenvs_("TERM")) != NOSTR) 2297c478bd9Sstevel@tonic-gate set(S_term /* "term" */, savestr(cp)); 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Re-initialize path if set in environment 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate if ((cp = getenvs_("PATH")) == NOSTR) 2347c478bd9Sstevel@tonic-gate set1(S_path /* "path" */, saveblk(pathlist), &shvhed); 2357c478bd9Sstevel@tonic-gate else 2367c478bd9Sstevel@tonic-gate importpath(cp); 2377c478bd9Sstevel@tonic-gate set(S_shell /* "shell" */, S_SHELLPATH); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate doldol = putn(getpid()); /* For $$ */ 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* restore globbing until the user says otherwise */ 2427c478bd9Sstevel@tonic-gate unsetv(S_noglob); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* 2457c478bd9Sstevel@tonic-gate * Record the interrupt states from the parent process. 2467c478bd9Sstevel@tonic-gate * If the parent is non-interruptible our hand must be forced 2477c478bd9Sstevel@tonic-gate * or we (and our children) won't be either. 2487c478bd9Sstevel@tonic-gate * Our children inherit termination from our parent. 2497c478bd9Sstevel@tonic-gate * We catch it only if we are the login shell. 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate /* parents interruptibility */ 2527c478bd9Sstevel@tonic-gate (void) sigvec(SIGINT, (struct sigvec *)0, &osv); 2537c478bd9Sstevel@tonic-gate parintr = osv.sv_handler; 2547c478bd9Sstevel@tonic-gate /* parents terminability */ 2557c478bd9Sstevel@tonic-gate (void) sigvec(SIGTERM, (struct sigvec *)0, &osv); 2567c478bd9Sstevel@tonic-gate parterm = osv.sv_handler; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate _signal(SIGLWP, siglwp); 2597c478bd9Sstevel@tonic-gate _signal(SIGWAITING, sigwaiting); 2607c478bd9Sstevel@tonic-gate if (loginsh) { 2617c478bd9Sstevel@tonic-gate (void) signal(SIGHUP, phup); /* exit processing on HUP */ 2627c478bd9Sstevel@tonic-gate (void) signal(SIGXCPU, phup); /* ...and on XCPU */ 2637c478bd9Sstevel@tonic-gate (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */ 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * Process the arguments. 2687c478bd9Sstevel@tonic-gate * 2697c478bd9Sstevel@tonic-gate * Note that processing of -v/-x is actually delayed till after 2707c478bd9Sstevel@tonic-gate * script processing. 2717c478bd9Sstevel@tonic-gate */ 2727c478bd9Sstevel@tonic-gate c--, v++; 2737c478bd9Sstevel@tonic-gate while (c > 0 && (cp = v[0])[0] == '-' && *++cp != '\0' && !batch) { 2747c478bd9Sstevel@tonic-gate do switch (*cp++) { 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate case 'b': /* -b Next arg is input file */ 2777c478bd9Sstevel@tonic-gate batch++; 2787c478bd9Sstevel@tonic-gate break; 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate case 'c': /* -c Command input from arg */ 2817c478bd9Sstevel@tonic-gate if (c == 1) 2827c478bd9Sstevel@tonic-gate exit(0); 2837c478bd9Sstevel@tonic-gate c--, v++; 2847c478bd9Sstevel@tonic-gate arginp = v[0]; 2857c478bd9Sstevel@tonic-gate prompt = 0; 2867c478bd9Sstevel@tonic-gate nofile++; 2877c478bd9Sstevel@tonic-gate cflg++; 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate case 'e': /* -e Exit on any error */ 2917c478bd9Sstevel@tonic-gate exiterr++; 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate case 'f': /* -f Fast start */ 2957c478bd9Sstevel@tonic-gate fast++; 2967c478bd9Sstevel@tonic-gate break; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate case 'i': /* -i Interactive, even if !intty */ 2997c478bd9Sstevel@tonic-gate intact++; 3007c478bd9Sstevel@tonic-gate nofile++; 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate case 'n': /* -n Don't execute */ 3047c478bd9Sstevel@tonic-gate noexec++; 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate case 'q': /* -q (Undoc'd) ... die on quit */ 3087c478bd9Sstevel@tonic-gate quitit = 1; 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate case 's': /* -s Read from std input */ 3127c478bd9Sstevel@tonic-gate nofile++; 3137c478bd9Sstevel@tonic-gate break; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate case 't': /* -t Read one line from input */ 3167c478bd9Sstevel@tonic-gate onelflg = 2; 3177c478bd9Sstevel@tonic-gate prompt = 0; 3187c478bd9Sstevel@tonic-gate nofile++; 3197c478bd9Sstevel@tonic-gate break; 3207c478bd9Sstevel@tonic-gate #ifdef TRACE 3217c478bd9Sstevel@tonic-gate case 'T': /* -T trace switch on */ 3227c478bd9Sstevel@tonic-gate trace_init(); 3237c478bd9Sstevel@tonic-gate break; 3247c478bd9Sstevel@tonic-gate #endif 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate case 'v': /* -v Echo hist expanded input */ 3277c478bd9Sstevel@tonic-gate nverbose = 1; /* ... later */ 3287c478bd9Sstevel@tonic-gate break; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate case 'x': /* -x Echo just before execution */ 3317c478bd9Sstevel@tonic-gate nexececho = 1; /* ... later */ 3327c478bd9Sstevel@tonic-gate break; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate case 'V': /* -V Echo hist expanded input */ 3357c478bd9Sstevel@tonic-gate setNS(S_verbose /* "verbose" */); /* NOW! */ 3367c478bd9Sstevel@tonic-gate break; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate case 'X': /* -X Echo just before execution */ 3397c478bd9Sstevel@tonic-gate setNS(S_echo /* "echo" */); /* NOW! */ 3407c478bd9Sstevel@tonic-gate break; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate } while (*cp); 3437c478bd9Sstevel@tonic-gate v++, c--; 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (quitit) /* With all due haste, for debugging */ 3477c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * Unless prevented by -c, -i, -s, or -t, if there 3517c478bd9Sstevel@tonic-gate * are remaining arguments the first of them is the name 3527c478bd9Sstevel@tonic-gate * of a shell file from which to read commands. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate if (!batch && (uid != geteuid() || getgid() != getegid())) { 3557c478bd9Sstevel@tonic-gate errno = EACCES; 3567c478bd9Sstevel@tonic-gate child++; /* So this ... */ 3577c478bd9Sstevel@tonic-gate Perror(S_csh /* "csh" */); /* ... doesn't return */ 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate if (nofile == 0 && c > 0) { 3617c478bd9Sstevel@tonic-gate nofile = open_(v[0], 0); 3627c478bd9Sstevel@tonic-gate if (nofile < 0) { 3637c478bd9Sstevel@tonic-gate child++; /* So this ... */ 3647c478bd9Sstevel@tonic-gate Perror(v[0]); /* ... doesn't return */ 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate file = v[0]; 3677c478bd9Sstevel@tonic-gate SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */ 3687c478bd9Sstevel@tonic-gate (void) fcntl(SHIN, F_SETFD, 1); 3697c478bd9Sstevel@tonic-gate prompt = 0; 3707c478bd9Sstevel@tonic-gate c--, v++; 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* 3747c478bd9Sstevel@tonic-gate * Consider input a tty if it really is or we are interactive. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate intty = intact || isatty(SHIN); 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * Decide whether we should play with signals or not. 3807c478bd9Sstevel@tonic-gate * If we are explicitly told (via -i, or -) or we are a login 3817c478bd9Sstevel@tonic-gate * shell (arg0 starts with -) or the input and output are both 3827c478bd9Sstevel@tonic-gate * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 3837c478bd9Sstevel@tonic-gate * Note that in only the login shell is it likely that parent 3847c478bd9Sstevel@tonic-gate * may have set signals to be ignored 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate if (loginsh || intact || intty && isatty(SHOUT)) 3877c478bd9Sstevel@tonic-gate setintr = 1; 3887c478bd9Sstevel@tonic-gate #ifdef TELL 3897c478bd9Sstevel@tonic-gate settell(); 3907c478bd9Sstevel@tonic-gate #endif 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * Save the remaining arguments in argv. 3937c478bd9Sstevel@tonic-gate */ 3943b09452cSnakanon setq(S_argv /* "argv" */, copyblk(v), &shvhed); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Set up the prompt. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate if (prompt) { 4007c478bd9Sstevel@tonic-gate gethostname_(s_prompt, MAXHOSTNAMELEN); 401*134a1f4eSCasper H.S. Dik strcat_(s_prompt, 402*134a1f4eSCasper H.S. Dik uid == 0 ? S_SHARPSP /* "# " */ : S_PERSENTSP /* "% " */); 4037c478bd9Sstevel@tonic-gate set(S_prompt /* "prompt" */, s_prompt); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * If we are an interactive shell, then start fiddling 4087c478bd9Sstevel@tonic-gate * with the signals; this is a tricky game. 4097c478bd9Sstevel@tonic-gate */ 4107c478bd9Sstevel@tonic-gate shpgrp = getpgid(0); 4117c478bd9Sstevel@tonic-gate opgrp = tpgrp = -1; 4127c478bd9Sstevel@tonic-gate if (setintr) { 4137c478bd9Sstevel@tonic-gate **av = '-'; 4147c478bd9Sstevel@tonic-gate if (!quitit) /* Wary! */ 4157c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 4167c478bd9Sstevel@tonic-gate (void) signal(SIGINT, pintr); 4177c478bd9Sstevel@tonic-gate (void) sigblock(sigmask(SIGINT)); 4187c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, SIG_IGN); 4192b51d29aSmg147109 4202b51d29aSmg147109 /* 4212b51d29aSmg147109 * Explicitly terminate foreground jobs and exit if we are 4222b51d29aSmg147109 * interactive shell 4232b51d29aSmg147109 */ 4242b51d29aSmg147109 if (loginsh) { 4252b51d29aSmg147109 (void) signal(SIGHUP, interactive_login_hup); 4262b51d29aSmg147109 } else { 4272b51d29aSmg147109 (void) signal(SIGHUP, interactive_hup); 4282b51d29aSmg147109 } 4292b51d29aSmg147109 4307c478bd9Sstevel@tonic-gate if (quitit == 0 && arginp == 0) { 4317c478bd9Sstevel@tonic-gate (void) signal(SIGTSTP, SIG_IGN); 4327c478bd9Sstevel@tonic-gate (void) signal(SIGTTIN, SIG_IGN); 4337c478bd9Sstevel@tonic-gate (void) signal(SIGTTOU, SIG_IGN); 4347c478bd9Sstevel@tonic-gate /* 4357c478bd9Sstevel@tonic-gate * Wait till in foreground, in case someone 4367c478bd9Sstevel@tonic-gate * stupidly runs 4377c478bd9Sstevel@tonic-gate * csh & 4387c478bd9Sstevel@tonic-gate * dont want to try to grab away the tty. 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate if (isatty(FSHDIAG)) 4417c478bd9Sstevel@tonic-gate f = FSHDIAG; 4427c478bd9Sstevel@tonic-gate else if (isatty(FSHOUT)) 4437c478bd9Sstevel@tonic-gate f = FSHOUT; 4447c478bd9Sstevel@tonic-gate else if (isatty(OLDSTD)) 4457c478bd9Sstevel@tonic-gate f = OLDSTD; 4467c478bd9Sstevel@tonic-gate else 4477c478bd9Sstevel@tonic-gate f = -1; 4487c478bd9Sstevel@tonic-gate retry: 4497c478bd9Sstevel@tonic-gate if (ioctl(f, TIOCGPGRP, (char *)&tpgrp) == 0 && 4507c478bd9Sstevel@tonic-gate tpgrp != -1) { 4517c478bd9Sstevel@tonic-gate if (tpgrp != shpgrp) { 452*134a1f4eSCasper H.S. Dik void (*old)() = (void (*)()) 453*134a1f4eSCasper H.S. Dik signal(SIGTTIN, SIG_DFL); 4547c478bd9Sstevel@tonic-gate (void) kill(0, SIGTTIN); 4557c478bd9Sstevel@tonic-gate (void) signal(SIGTTIN, old); 4567c478bd9Sstevel@tonic-gate goto retry; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate opgrp = shpgrp; 4597c478bd9Sstevel@tonic-gate shpgrp = getpid(); 4607c478bd9Sstevel@tonic-gate tpgrp = shpgrp; 4617c478bd9Sstevel@tonic-gate (void) setpgid(0, shpgrp); 4627c478bd9Sstevel@tonic-gate (void) ioctl(f, TIOCSPGRP, (char *)&shpgrp); 4637c478bd9Sstevel@tonic-gate (void) fcntl(dcopy(f, FSHTTY), F_SETFD, 1); 4647c478bd9Sstevel@tonic-gate } else { 4657c478bd9Sstevel@tonic-gate notty: 4667c478bd9Sstevel@tonic-gate printf("Warning: no access to tty; thus no job control in this shell...\n"); 4677c478bd9Sstevel@tonic-gate tpgrp = -1; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate if (setintr == 0 && parintr == SIG_DFL) 4727c478bd9Sstevel@tonic-gate setintr++; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * Set SIGCHLD handler, making sure that reads restart after it runs. 4767c478bd9Sstevel@tonic-gate */ 4777c478bd9Sstevel@tonic-gate sigemptyset(&sa.sa_mask); 4787c478bd9Sstevel@tonic-gate sa.sa_handler = pchild; 4797c478bd9Sstevel@tonic-gate sa.sa_flags = SA_RESTART; 4807c478bd9Sstevel@tonic-gate (void) sigaction(SIGCHLD, &sa, (struct sigaction *)NULL); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Set an exit here in case of an interrupt or error reading 4847c478bd9Sstevel@tonic-gate * the shell start-up scripts. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate setexit(); 4877c478bd9Sstevel@tonic-gate haderr = 0; /* In case second time through */ 4887c478bd9Sstevel@tonic-gate if (!fast && reenter == 0) { 4897c478bd9Sstevel@tonic-gate reenter++; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate /* 4927c478bd9Sstevel@tonic-gate * If this is a login csh, and /etc/.login exists, 4937c478bd9Sstevel@tonic-gate * source /etc/.login first. 4947c478bd9Sstevel@tonic-gate */ 4957c478bd9Sstevel@tonic-gate if (loginsh) { 4967c478bd9Sstevel@tonic-gate tchar tmp_etc[4+1]; /* strlen("/etc")+1 */ 4977c478bd9Sstevel@tonic-gate tchar tmp_login[7+1]; /* strlen("/.login")+1 */ 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate strtots(tmp_etc, "/etc"); 5007c478bd9Sstevel@tonic-gate strtots(tmp_login, "/.login"); 5017c478bd9Sstevel@tonic-gate srccat_inlogin(tmp_etc, tmp_login); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* Will have value("home") here because set fast if don't */ 505*134a1f4eSCasper H.S. Dik srccat(value(S_home /* "home" */), 506*134a1f4eSCasper H.S. Dik S_SLADOTcshrc /* "/.cshrc" */); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* Hash path */ 5097c478bd9Sstevel@tonic-gate if (!fast && !arginp && !onelflg && !havhash) 5107c478bd9Sstevel@tonic-gate dohash(xhash); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * Reconstruct the history list now, so that it's 5157c478bd9Sstevel@tonic-gate * available from within .login. 5167c478bd9Sstevel@tonic-gate */ 5177c478bd9Sstevel@tonic-gate dosource(loadhist); 5187c478bd9Sstevel@tonic-gate if (loginsh) { 519*134a1f4eSCasper H.S. Dik srccat_inlogin(value(S_home /* "home" */), 520*134a1f4eSCasper H.S. Dik S_SLADOTlogin /* "/.login" */); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* 5247c478bd9Sstevel@tonic-gate * To get cdpath hashing $cdpath must have a 5257c478bd9Sstevel@tonic-gate * value, not $CDPATH. So if after reading 5267c478bd9Sstevel@tonic-gate * the startup files ( .cshrc ), and 5277c478bd9Sstevel@tonic-gate * user has specified a value for cdpath, then 5287c478bd9Sstevel@tonic-gate * cache $cdpath paths. xhash2 is global array 5297c478bd9Sstevel@tonic-gate * for $cdpath caching. 5307c478bd9Sstevel@tonic-gate */ 5317c478bd9Sstevel@tonic-gate if (!fast && !arginp && !onelflg && !havhash2) 5327c478bd9Sstevel@tonic-gate dohash(xhash2); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * Now are ready for the -v and -x flags 5377c478bd9Sstevel@tonic-gate */ 5387c478bd9Sstevel@tonic-gate if (nverbose) 5397c478bd9Sstevel@tonic-gate setNS(S_verbose /* "verbose" */); 5407c478bd9Sstevel@tonic-gate if (nexececho) 5417c478bd9Sstevel@tonic-gate setNS(S_echo /* "echo" */); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate * All the rest of the world is inside this call. 5457c478bd9Sstevel@tonic-gate * The argument to process indicates whether it should 5467c478bd9Sstevel@tonic-gate * catch "error unwinds". Thus if we are a interactive shell 5477c478bd9Sstevel@tonic-gate * our call here will never return by being blown past on an error. 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate process(setintr); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * Mop-up. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate if (loginsh) { 5557c478bd9Sstevel@tonic-gate printf("logout\n"); 5567c478bd9Sstevel@tonic-gate (void) close(SHIN); /* No need for unsetfd(). */ 5577c478bd9Sstevel@tonic-gate child++; 5587c478bd9Sstevel@tonic-gate goodbye(); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate rechist(); 5617c478bd9Sstevel@tonic-gate exitstat(); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5646c02b4a4Smuffin void 5656c02b4a4Smuffin untty(void) 5667c478bd9Sstevel@tonic-gate { 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate if (tpgrp > 0) { 5697c478bd9Sstevel@tonic-gate (void) setpgid(0, opgrp); 5707c478bd9Sstevel@tonic-gate (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&opgrp); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate 5746c02b4a4Smuffin void 5756c02b4a4Smuffin importpath(tchar *cp) 5767c478bd9Sstevel@tonic-gate { 5776c02b4a4Smuffin int i = 0; 5786c02b4a4Smuffin tchar *dp; 5796c02b4a4Smuffin tchar **pv; 5807c478bd9Sstevel@tonic-gate int c; 5817c478bd9Sstevel@tonic-gate static tchar dot[2] = {'.', 0}; 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate for (dp = cp; *dp; dp++) 5847c478bd9Sstevel@tonic-gate if (*dp == ':') 5857c478bd9Sstevel@tonic-gate i++; 5867c478bd9Sstevel@tonic-gate /* 5877c478bd9Sstevel@tonic-gate * i+2 where i is the number of colons in the path. 5887c478bd9Sstevel@tonic-gate * There are i+1 directories in the path plus we need 5897c478bd9Sstevel@tonic-gate * room for a zero terminator. 5907c478bd9Sstevel@tonic-gate */ 59165b0c20eSnakanon pv = (tchar **)xcalloc((unsigned)(i + 2), sizeof (tchar **)); 5927c478bd9Sstevel@tonic-gate dp = cp; 5937c478bd9Sstevel@tonic-gate i = 0; 5947c478bd9Sstevel@tonic-gate if (*dp) 5957c478bd9Sstevel@tonic-gate for (;;) { 5967c478bd9Sstevel@tonic-gate if ((c = *dp) == ':' || c == 0) { 5977c478bd9Sstevel@tonic-gate *dp = 0; 5987c478bd9Sstevel@tonic-gate pv[i++] = savestr(*cp ? cp : dot); 5997c478bd9Sstevel@tonic-gate if (c) { 6007c478bd9Sstevel@tonic-gate cp = dp + 1; 6017c478bd9Sstevel@tonic-gate *dp = ':'; 6027c478bd9Sstevel@tonic-gate } else 6037c478bd9Sstevel@tonic-gate break; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate dp++; 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate pv[i] = 0; 6087c478bd9Sstevel@tonic-gate set1(S_path /* "path" */, pv, &shvhed); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* 6127c478bd9Sstevel@tonic-gate * Source to the file which is the catenation of the argument names. 6137c478bd9Sstevel@tonic-gate */ 6146c02b4a4Smuffin void 6156c02b4a4Smuffin srccat(tchar *cp, tchar *dp) 6167c478bd9Sstevel@tonic-gate { 6176c02b4a4Smuffin tchar *ep = strspl(cp, dp); 6186c02b4a4Smuffin int unit = dmove(open_(ep, 0), -1); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate (void) fcntl(unit, F_SETFD, 1); 6217c478bd9Sstevel@tonic-gate xfree(ep); 6227c478bd9Sstevel@tonic-gate #ifdef INGRES 6237c478bd9Sstevel@tonic-gate srcunit(unit, 0, 0); 6247c478bd9Sstevel@tonic-gate #else 6257c478bd9Sstevel@tonic-gate srcunit(unit, 1, 0); 6267c478bd9Sstevel@tonic-gate #endif 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * Source to the file which is the catenation of the argument names. 6317c478bd9Sstevel@tonic-gate * This one does not check the ownership. 6327c478bd9Sstevel@tonic-gate */ 6336c02b4a4Smuffin void 6346c02b4a4Smuffin srccat_inlogin(tchar *cp, tchar *dp) 6357c478bd9Sstevel@tonic-gate { 6366c02b4a4Smuffin tchar *ep = strspl(cp, dp); 6376c02b4a4Smuffin int unit = dmove(open_(ep, 0), -1); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate (void) fcntl(unit, F_SETFD, 1); 6407c478bd9Sstevel@tonic-gate xfree(ep); 6417c478bd9Sstevel@tonic-gate srcunit(unit, 0, 0); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * Source to a unit. If onlyown it must be our file or our group or 6467c478bd9Sstevel@tonic-gate * we don't chance it. This occurs on ".cshrc"s and the like. 6477c478bd9Sstevel@tonic-gate */ 6486c02b4a4Smuffin void 6496c02b4a4Smuffin srcunit(int unit, bool onlyown, bool hflg) 6507c478bd9Sstevel@tonic-gate { 6517c478bd9Sstevel@tonic-gate /* We have to push down a lot of state here */ 6527c478bd9Sstevel@tonic-gate /* All this could go into a structure */ 6537c478bd9Sstevel@tonic-gate int oSHIN = -1, oldintty = intty; 6547c478bd9Sstevel@tonic-gate struct whyle *oldwhyl = whyles; 6557c478bd9Sstevel@tonic-gate tchar *ogointr = gointr, *oarginp = arginp; 6567c478bd9Sstevel@tonic-gate tchar *oevalp = evalp, **oevalvec = evalvec; 6577c478bd9Sstevel@tonic-gate int oonelflg = onelflg; 6587c478bd9Sstevel@tonic-gate bool oenterhist = enterhist; 6597c478bd9Sstevel@tonic-gate tchar OHIST = HIST; 6607c478bd9Sstevel@tonic-gate #ifdef TELL 6617c478bd9Sstevel@tonic-gate bool otell = cantell; 6627c478bd9Sstevel@tonic-gate #endif 6637c478bd9Sstevel@tonic-gate struct Bin saveB; 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* The (few) real local variables */ 6667c478bd9Sstevel@tonic-gate jmp_buf oldexit; 6677c478bd9Sstevel@tonic-gate int reenter, omask; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate if (unit < 0) 6707c478bd9Sstevel@tonic-gate return; 6717c478bd9Sstevel@tonic-gate if (didfds) 6727c478bd9Sstevel@tonic-gate donefds(); 6737c478bd9Sstevel@tonic-gate if (onlyown) { 6747c478bd9Sstevel@tonic-gate struct stat stb; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate if (fstat(unit, &stb) < 0 || 6777c478bd9Sstevel@tonic-gate (stb.st_uid != uid && stb.st_gid != getgid())) { 6787c478bd9Sstevel@tonic-gate (void) close(unit); 6797c478bd9Sstevel@tonic-gate unsetfd(unit); 6807c478bd9Sstevel@tonic-gate return; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6857c478bd9Sstevel@tonic-gate * There is a critical section here while we are pushing down the 6867c478bd9Sstevel@tonic-gate * input stream since we have stuff in different structures. 6877c478bd9Sstevel@tonic-gate * If we weren't careful an interrupt could corrupt SHIN's Bin 6887c478bd9Sstevel@tonic-gate * structure and kill the shell. 6897c478bd9Sstevel@tonic-gate * 6907c478bd9Sstevel@tonic-gate * We could avoid the critical region by grouping all the stuff 6917c478bd9Sstevel@tonic-gate * in a single structure and pointing at it to move it all at 6927c478bd9Sstevel@tonic-gate * once. This is less efficient globally on many variable references 6937c478bd9Sstevel@tonic-gate * however. 6947c478bd9Sstevel@tonic-gate */ 6957c478bd9Sstevel@tonic-gate getexit(oldexit); 6967c478bd9Sstevel@tonic-gate reenter = 0; 6977c478bd9Sstevel@tonic-gate if (setintr) 6987c478bd9Sstevel@tonic-gate omask = sigblock(sigmask(SIGINT)); 6997c478bd9Sstevel@tonic-gate setexit(); 7007c478bd9Sstevel@tonic-gate reenter++; 7017c478bd9Sstevel@tonic-gate if (reenter == 1) { 7027c478bd9Sstevel@tonic-gate /* Setup the new values of the state stuff saved above */ 703*134a1f4eSCasper H.S. Dik copy((char *)&saveB, (char *)&B, sizeof (saveB)); 7047c478bd9Sstevel@tonic-gate fbuf = (tchar **) 0; 7057c478bd9Sstevel@tonic-gate fseekp = feobp = fblocks = 0; 7067c478bd9Sstevel@tonic-gate oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; 7077c478bd9Sstevel@tonic-gate intty = isatty(SHIN), whyles = 0, gointr = 0; 7087c478bd9Sstevel@tonic-gate evalvec = 0; evalp = 0; 7097c478bd9Sstevel@tonic-gate enterhist = hflg; 7107c478bd9Sstevel@tonic-gate if (enterhist) 7117c478bd9Sstevel@tonic-gate HIST = '\0'; 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * Now if we are allowing commands to be interrupted, 7147c478bd9Sstevel@tonic-gate * we let ourselves be interrupted. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate if (setintr) 7177c478bd9Sstevel@tonic-gate (void) sigsetmask(omask); 7187c478bd9Sstevel@tonic-gate #ifdef TELL 7197c478bd9Sstevel@tonic-gate settell(); 7207c478bd9Sstevel@tonic-gate #endif 7217c478bd9Sstevel@tonic-gate process(0); /* 0 -> blow away on errors */ 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate if (setintr) 7247c478bd9Sstevel@tonic-gate (void) sigsetmask(omask); 7257c478bd9Sstevel@tonic-gate if (oSHIN >= 0) { 7266c02b4a4Smuffin int i; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* We made it to the new state... free up its storage */ 7297c478bd9Sstevel@tonic-gate /* This code could get run twice but xfree doesn't care */ 7307c478bd9Sstevel@tonic-gate for (i = 0; i < fblocks; i++) 7317c478bd9Sstevel@tonic-gate xfree(fbuf[i]); 7327c478bd9Sstevel@tonic-gate xfree((char *)fbuf); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* Reset input arena */ 735*134a1f4eSCasper H.S. Dik copy((char *)&B, (char *)&saveB, sizeof (B)); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate (void) close(SHIN), SHIN = oSHIN; 7387c478bd9Sstevel@tonic-gate unsetfd(SHIN); 7397c478bd9Sstevel@tonic-gate arginp = oarginp, onelflg = oonelflg; 7407c478bd9Sstevel@tonic-gate evalp = oevalp, evalvec = oevalvec; 7417c478bd9Sstevel@tonic-gate intty = oldintty, whyles = oldwhyl, gointr = ogointr; 7427c478bd9Sstevel@tonic-gate if (enterhist) 7437c478bd9Sstevel@tonic-gate HIST = OHIST; 7447c478bd9Sstevel@tonic-gate enterhist = oenterhist; 7457c478bd9Sstevel@tonic-gate #ifdef TELL 7467c478bd9Sstevel@tonic-gate cantell = otell; 7477c478bd9Sstevel@tonic-gate #endif 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate resexit(oldexit); 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * If process reset() (effectively an unwind) then 7537c478bd9Sstevel@tonic-gate * we must also unwind. 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate if (reenter >= 2) 7567c478bd9Sstevel@tonic-gate error(NULL); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7596c02b4a4Smuffin void 7606c02b4a4Smuffin rechist(void) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate tchar buf[BUFSIZ]; 7637c478bd9Sstevel@tonic-gate int fp, ftmp, oldidfds; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate if (!fast) { 7667c478bd9Sstevel@tonic-gate if (value(S_savehist /* "savehist" */)[0] == '\0') 7677c478bd9Sstevel@tonic-gate return; 7687c478bd9Sstevel@tonic-gate (void) strcpy_(buf, value(S_home /* "home" */)); 7697c478bd9Sstevel@tonic-gate (void) strcat_(buf, S_SLADOThistory /* "/.history" */); 7707c478bd9Sstevel@tonic-gate fp = creat_(buf, 0666); 7717c478bd9Sstevel@tonic-gate if (fp == -1) 7727c478bd9Sstevel@tonic-gate return; 7737c478bd9Sstevel@tonic-gate oldidfds = didfds; 7747c478bd9Sstevel@tonic-gate didfds = 0; 7757c478bd9Sstevel@tonic-gate ftmp = SHOUT; 7767c478bd9Sstevel@tonic-gate SHOUT = fp; 7777c478bd9Sstevel@tonic-gate (void) strcpy_(buf, value(S_savehist /* "savehist" */)); 7787c478bd9Sstevel@tonic-gate dumphist[2] = buf; 7797c478bd9Sstevel@tonic-gate dohist(dumphist); 7807c478bd9Sstevel@tonic-gate (void) close(fp); 7817c478bd9Sstevel@tonic-gate unsetfd(fp); 7827c478bd9Sstevel@tonic-gate SHOUT = ftmp; 7837c478bd9Sstevel@tonic-gate didfds = oldidfds; 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7876c02b4a4Smuffin void 7886c02b4a4Smuffin goodbye(void) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate if (loginsh) { 7917c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 7927c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); 7937c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, SIG_IGN); 7947c478bd9Sstevel@tonic-gate setintr = 0; /* No interrupts after "logout" */ 7957c478bd9Sstevel@tonic-gate if (adrof(S_home /* "home" */)) 796*134a1f4eSCasper H.S. Dik srccat(value(S_home /* "home" */), 797*134a1f4eSCasper H.S. Dik S_SLADOTlogout /* "/.logout" */); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate rechist(); 8007c478bd9Sstevel@tonic-gate exitstat(); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8036c02b4a4Smuffin void 8046c02b4a4Smuffin exitstat(void) 8057c478bd9Sstevel@tonic-gate { 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate #ifdef PROF 8087c478bd9Sstevel@tonic-gate monitor(0); 8097c478bd9Sstevel@tonic-gate #endif 8107c478bd9Sstevel@tonic-gate /* 8117c478bd9Sstevel@tonic-gate * Note that if STATUS is corrupted (i.e. getn bombs) 8127c478bd9Sstevel@tonic-gate * then error will exit directly because we poke child here. 8137c478bd9Sstevel@tonic-gate * Otherwise we might continue unwarrantedly (sic). 8147c478bd9Sstevel@tonic-gate */ 8157c478bd9Sstevel@tonic-gate child++; 8167c478bd9Sstevel@tonic-gate untty(); 8177c478bd9Sstevel@tonic-gate exit(getn(value(S_status /* "status" */))); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * in the event of a HUP we want to save the history 8227c478bd9Sstevel@tonic-gate */ 8237c478bd9Sstevel@tonic-gate void 8246c02b4a4Smuffin phup(void) 8257c478bd9Sstevel@tonic-gate { 8267c478bd9Sstevel@tonic-gate rechist(); 8277c478bd9Sstevel@tonic-gate exit(1); 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8302b51d29aSmg147109 void 8312b51d29aSmg147109 interactive_hup(void) 8322b51d29aSmg147109 { 8332b51d29aSmg147109 hupforegnd(); 8342b51d29aSmg147109 exit(1); 8352b51d29aSmg147109 } 8362b51d29aSmg147109 8372b51d29aSmg147109 void 8382b51d29aSmg147109 interactive_login_hup(void) 8392b51d29aSmg147109 { 8402b51d29aSmg147109 rechist(); 8412b51d29aSmg147109 hupforegnd(); 8422b51d29aSmg147109 exit(1); 8432b51d29aSmg147109 } 8442b51d29aSmg147109 8457c478bd9Sstevel@tonic-gate tchar *jobargv[2] = { S_jobs /* "jobs" */, 0 }; 8467c478bd9Sstevel@tonic-gate /* 8477c478bd9Sstevel@tonic-gate * Catch an interrupt, e.g. during lexical input. 8487c478bd9Sstevel@tonic-gate * If we are an interactive shell, we reset the interrupt catch 8497c478bd9Sstevel@tonic-gate * immediately. In any case we drain the shell output, 8507c478bd9Sstevel@tonic-gate * and finally go through the normal error mechanism, which 8517c478bd9Sstevel@tonic-gate * gets a chance to make the shell go away. 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate void 8546c02b4a4Smuffin pintr(void) 8557c478bd9Sstevel@tonic-gate { 8567c478bd9Sstevel@tonic-gate pintr1(1); 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8596c02b4a4Smuffin void 8606c02b4a4Smuffin pintr1(bool wantnl) 8617c478bd9Sstevel@tonic-gate { 8626c02b4a4Smuffin tchar **v; 8637c478bd9Sstevel@tonic-gate int omask; 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate omask = sigblock(0); 8667c478bd9Sstevel@tonic-gate if (setintr) { 8677c478bd9Sstevel@tonic-gate (void) sigsetmask(omask & ~sigmask(SIGINT)); 8687c478bd9Sstevel@tonic-gate if (pjobs) { 8697c478bd9Sstevel@tonic-gate pjobs = 0; 8707c478bd9Sstevel@tonic-gate printf("\n"); 8717c478bd9Sstevel@tonic-gate dojobs(jobargv); 8727c478bd9Sstevel@tonic-gate bferr("Interrupted"); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate (void) sigsetmask(omask & ~sigmask(SIGCHLD)); 8767c478bd9Sstevel@tonic-gate draino(); 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * If we have an active "onintr" then we search for the label. 8807c478bd9Sstevel@tonic-gate * Note that if one does "onintr -" then we shan't be interruptible 8817c478bd9Sstevel@tonic-gate * so we needn't worry about that here. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate if (gointr) { 8847c478bd9Sstevel@tonic-gate search(ZGOTO, 0, gointr); 8857c478bd9Sstevel@tonic-gate timflg = 0; 8867c478bd9Sstevel@tonic-gate if (v = pargv) 8877c478bd9Sstevel@tonic-gate pargv = 0, blkfree(v); 8887c478bd9Sstevel@tonic-gate if (v = gargv) 8897c478bd9Sstevel@tonic-gate gargv = 0, blkfree(v); 8907c478bd9Sstevel@tonic-gate reset(); 8917c478bd9Sstevel@tonic-gate } else if (intty && wantnl) 8927c478bd9Sstevel@tonic-gate printf("\n"); /* Some like this, others don't */ 8937c478bd9Sstevel@tonic-gate error(NULL); 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate /* 8977c478bd9Sstevel@tonic-gate * Process is the main driving routine for the shell. 8987c478bd9Sstevel@tonic-gate * It runs all command processing, except for those within { ... } 8997c478bd9Sstevel@tonic-gate * in expressions (which is run by a routine evalav in sh.exp.c which 9007c478bd9Sstevel@tonic-gate * is a stripped down process), and `...` evaluation which is run 9017c478bd9Sstevel@tonic-gate * also by a subset of this code in sh.glob.c in the routine backeval. 9027c478bd9Sstevel@tonic-gate * 9037c478bd9Sstevel@tonic-gate * The code here is a little strange because part of it is interruptible 9047c478bd9Sstevel@tonic-gate * and hence freeing of structures appears to occur when none is necessary 9057c478bd9Sstevel@tonic-gate * if this is ignored. 9067c478bd9Sstevel@tonic-gate * 9077c478bd9Sstevel@tonic-gate * Note that if catch is not set then we will unwind on any error. 9087c478bd9Sstevel@tonic-gate * If an end-of-file occurs, we return. 9097c478bd9Sstevel@tonic-gate */ 9106c02b4a4Smuffin void 9116c02b4a4Smuffin process(bool catch) 9127c478bd9Sstevel@tonic-gate { 9137c478bd9Sstevel@tonic-gate jmp_buf osetexit; 9146c02b4a4Smuffin struct command *t; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate getexit(osetexit); 9177c478bd9Sstevel@tonic-gate for (;;) { 9187c478bd9Sstevel@tonic-gate pendjob(); 91965b0c20eSnakanon freelex(¶ml); 9207c478bd9Sstevel@tonic-gate paraml.next = paraml.prev = ¶ml; 9217c478bd9Sstevel@tonic-gate paraml.word = S_ /* "" */; 9227c478bd9Sstevel@tonic-gate t = 0; 9237c478bd9Sstevel@tonic-gate setexit(); 9247c478bd9Sstevel@tonic-gate justpr = enterhist; /* execute if not entering history */ 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * Interruptible during interactive reads 9287c478bd9Sstevel@tonic-gate */ 9297c478bd9Sstevel@tonic-gate if (setintr) 9307c478bd9Sstevel@tonic-gate (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT)); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate /* 9337c478bd9Sstevel@tonic-gate * For the sake of reset() 9347c478bd9Sstevel@tonic-gate */ 9357c478bd9Sstevel@tonic-gate freelex(¶ml), freesyn(t), t = 0; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate if (haderr) { 9387c478bd9Sstevel@tonic-gate if (!catch) { 9397c478bd9Sstevel@tonic-gate /* unwind */ 9407c478bd9Sstevel@tonic-gate doneinp = 0; 9417c478bd9Sstevel@tonic-gate resexit(osetexit); 9427c478bd9Sstevel@tonic-gate reset(); 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate haderr = 0; 9457c478bd9Sstevel@tonic-gate /* 9467c478bd9Sstevel@tonic-gate * Every error is eventually caught here or 9477c478bd9Sstevel@tonic-gate * the shell dies. It is at this 9487c478bd9Sstevel@tonic-gate * point that we clean up any left-over open 9497c478bd9Sstevel@tonic-gate * files, by closing all but a fixed number 9507c478bd9Sstevel@tonic-gate * of pre-defined files. Thus routines don't 9517c478bd9Sstevel@tonic-gate * have to worry about leaving files open due 9527c478bd9Sstevel@tonic-gate * to deeper errors... they will get closed here. 9537c478bd9Sstevel@tonic-gate */ 9547c478bd9Sstevel@tonic-gate closem(); 9557c478bd9Sstevel@tonic-gate continue; 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate if (doneinp) { 9587c478bd9Sstevel@tonic-gate doneinp = 0; 9597c478bd9Sstevel@tonic-gate break; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate if (chkstop) 9627c478bd9Sstevel@tonic-gate chkstop--; 9637c478bd9Sstevel@tonic-gate if (neednote) 9647c478bd9Sstevel@tonic-gate pnote(); 9657c478bd9Sstevel@tonic-gate if (intty && prompt && evalvec == 0) { 9667c478bd9Sstevel@tonic-gate mailchk(); 9677c478bd9Sstevel@tonic-gate /* 9687c478bd9Sstevel@tonic-gate * If we are at the end of the input buffer 9697c478bd9Sstevel@tonic-gate * then we are going to read fresh stuff. 9707c478bd9Sstevel@tonic-gate * Otherwise, we are rereading input and don't 9717c478bd9Sstevel@tonic-gate * need or want to prompt. 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate if (fseekp == feobp) 9747c478bd9Sstevel@tonic-gate printprompt(); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate err = 0; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * Echo not only on VERBOSE, but also with history expansion. 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate if (lex(¶ml) && intty || 9827c478bd9Sstevel@tonic-gate adrof(S_verbose /* "verbose" */)) { 9837c478bd9Sstevel@tonic-gate haderr = 1; 9847c478bd9Sstevel@tonic-gate prlex(¶ml); 9857c478bd9Sstevel@tonic-gate haderr = 0; 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate /* 9897c478bd9Sstevel@tonic-gate * The parser may lose space if interrupted. 9907c478bd9Sstevel@tonic-gate */ 9917c478bd9Sstevel@tonic-gate if (setintr) 9927c478bd9Sstevel@tonic-gate (void) sigblock(sigmask(SIGINT)); 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate /* 9957c478bd9Sstevel@tonic-gate * Save input text on the history list if 9967c478bd9Sstevel@tonic-gate * reading in old history, or it 9977c478bd9Sstevel@tonic-gate * is from the terminal at the top level and not 9987c478bd9Sstevel@tonic-gate * in a loop. 9997c478bd9Sstevel@tonic-gate */ 10007c478bd9Sstevel@tonic-gate if (enterhist || catch && intty && !whyles) 10017c478bd9Sstevel@tonic-gate savehist(¶ml); 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate /* 10047c478bd9Sstevel@tonic-gate * Print lexical error messages, except when sourcing 10057c478bd9Sstevel@tonic-gate * history lists. 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate if (!enterhist && err) 10087c478bd9Sstevel@tonic-gate error("%s", gettext(err)); 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate /* 10117c478bd9Sstevel@tonic-gate * If had a history command :p modifier then 10127c478bd9Sstevel@tonic-gate * this is as far as we should go 10137c478bd9Sstevel@tonic-gate */ 10147c478bd9Sstevel@tonic-gate if (justpr) 10157c478bd9Sstevel@tonic-gate reset(); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate alias(¶ml); 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * Parse the words of the input into a parse tree. 10217c478bd9Sstevel@tonic-gate */ 10227c478bd9Sstevel@tonic-gate t = syntax(paraml.next, ¶ml, 0); 10237c478bd9Sstevel@tonic-gate if (err) 10247c478bd9Sstevel@tonic-gate error("%s", gettext(err)); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate /* 10277c478bd9Sstevel@tonic-gate * Execute the parse tree 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate { 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate * POSIX requires SIGCHLD to be held 10327c478bd9Sstevel@tonic-gate * until all processes have joined the 10337c478bd9Sstevel@tonic-gate * process group in order to avoid race 10347c478bd9Sstevel@tonic-gate * condition. 10357c478bd9Sstevel@tonic-gate */ 10367c478bd9Sstevel@tonic-gate int omask; 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate omask = sigblock(sigmask(SIGCHLD)); 10397c478bd9Sstevel@tonic-gate execute(t, tpgrp); 10407c478bd9Sstevel@tonic-gate (void) sigsetmask(omask &~ sigmask(SIGCHLD)); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if (err) 10447c478bd9Sstevel@tonic-gate error("%s", gettext(err)); 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * Made it! 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate freelex(¶ml), freesyn(t); 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate resexit(osetexit); 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate 10536c02b4a4Smuffin void 10546c02b4a4Smuffin dosource(tchar **t) 10557c478bd9Sstevel@tonic-gate { 10566c02b4a4Smuffin tchar *f; 10576c02b4a4Smuffin int u; 10587c478bd9Sstevel@tonic-gate bool hflg = 0; 10597c478bd9Sstevel@tonic-gate tchar buf[BUFSIZ]; 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate t++; 10627c478bd9Sstevel@tonic-gate if (*t && eq(*t, S_h /* "-h" */)) { 10637c478bd9Sstevel@tonic-gate if (*++t == NOSTR) 10647c478bd9Sstevel@tonic-gate bferr("Too few arguments."); 10657c478bd9Sstevel@tonic-gate hflg++; 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate (void) strcpy_(buf, *t); 10687c478bd9Sstevel@tonic-gate f = globone(buf); 10697c478bd9Sstevel@tonic-gate u = dmove(open_(f, 0), -1); 10707c478bd9Sstevel@tonic-gate xfree(f); 10717c478bd9Sstevel@tonic-gate freelex(¶ml); 10727c478bd9Sstevel@tonic-gate if (u < 0 && !hflg) 10737c478bd9Sstevel@tonic-gate Perror(f); 10747c478bd9Sstevel@tonic-gate (void) fcntl(u, F_SETFD, 1); 10757c478bd9Sstevel@tonic-gate srcunit(u, 0, hflg); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate /* 10797c478bd9Sstevel@tonic-gate * Check for mail. 10807c478bd9Sstevel@tonic-gate * If we are a login shell, then we don't want to tell 10817c478bd9Sstevel@tonic-gate * about any mail file unless its been modified 10827c478bd9Sstevel@tonic-gate * after the time we started. 10837c478bd9Sstevel@tonic-gate * This prevents us from telling the user things he already 10847c478bd9Sstevel@tonic-gate * knows, since the login program insists on saying 10857c478bd9Sstevel@tonic-gate * "You have mail." 10867c478bd9Sstevel@tonic-gate */ 10876c02b4a4Smuffin void 10886c02b4a4Smuffin mailchk(void) 10897c478bd9Sstevel@tonic-gate { 10906c02b4a4Smuffin struct varent *v; 10916c02b4a4Smuffin tchar **vp; 10927c478bd9Sstevel@tonic-gate time_t t; 10937c478bd9Sstevel@tonic-gate int intvl, cnt; 10947c478bd9Sstevel@tonic-gate struct stat stb; 10957c478bd9Sstevel@tonic-gate bool new; 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate v = adrof(S_mail /* "mail" */); 10987c478bd9Sstevel@tonic-gate if (v == 0) 10997c478bd9Sstevel@tonic-gate return; 11007c478bd9Sstevel@tonic-gate (void) time(&t); 11017c478bd9Sstevel@tonic-gate vp = v->vec; 11027c478bd9Sstevel@tonic-gate cnt = blklen(vp); 11037c478bd9Sstevel@tonic-gate intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 11047c478bd9Sstevel@tonic-gate if (intvl < 1) 11057c478bd9Sstevel@tonic-gate intvl = 1; 11067c478bd9Sstevel@tonic-gate if (chktim + intvl > t) 11077c478bd9Sstevel@tonic-gate return; 11087c478bd9Sstevel@tonic-gate for (; *vp; vp++) { 11097c478bd9Sstevel@tonic-gate if (stat_(*vp, &stb) < 0) 11107c478bd9Sstevel@tonic-gate continue; 11117c478bd9Sstevel@tonic-gate new = stb.st_mtime > time0.tv_sec; 11127c478bd9Sstevel@tonic-gate if (stb.st_size == 0 || stb.st_atime >= stb.st_mtime || 11137c478bd9Sstevel@tonic-gate (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 11147c478bd9Sstevel@tonic-gate loginsh && !new) 11157c478bd9Sstevel@tonic-gate continue; 11167c478bd9Sstevel@tonic-gate if (cnt == 1) 11177c478bd9Sstevel@tonic-gate printf("You have %smail.\n", new ? "new " : ""); 11187c478bd9Sstevel@tonic-gate else 11197c478bd9Sstevel@tonic-gate printf("%s in %t.\n", new ? "New mail" : "Mail", *vp); 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate chktim = t; 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* 11257c478bd9Sstevel@tonic-gate * Extract a home directory from the password file 11267c478bd9Sstevel@tonic-gate * The argument points to a buffer where the name of the 11277c478bd9Sstevel@tonic-gate * user whose home directory is sought is currently. 11287c478bd9Sstevel@tonic-gate * We write the home directory of the user back there. 11297c478bd9Sstevel@tonic-gate */ 11306c02b4a4Smuffin int 11316c02b4a4Smuffin gethdir(tchar *home) 11327c478bd9Sstevel@tonic-gate { 11337c478bd9Sstevel@tonic-gate /* getpwname will not be modified, so we need temp. buffer */ 11347c478bd9Sstevel@tonic-gate char home_str[BUFSIZ]; 11357c478bd9Sstevel@tonic-gate tchar home_ts[BUFSIZ]; 11366c02b4a4Smuffin struct passwd *pp /* = getpwnam(home) */; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate pp = getpwnam(tstostr(home_str, home)); 11397c478bd9Sstevel@tonic-gate if (pp == 0) 11407c478bd9Sstevel@tonic-gate return (1); 11417c478bd9Sstevel@tonic-gate (void) strcpy_(home, strtots(home_ts, pp->pw_dir)); 11427c478bd9Sstevel@tonic-gate return (0); 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate 114665b0c20eSnakanon #if 0 11476c02b4a4Smuffin void 11487c478bd9Sstevel@tonic-gate #ifdef PROF 11496c02b4a4Smuffin done(int i) 11507c478bd9Sstevel@tonic-gate #else 11516c02b4a4Smuffin exit(int i) 11527c478bd9Sstevel@tonic-gate #endif 11537c478bd9Sstevel@tonic-gate { 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate untty(); 11567c478bd9Sstevel@tonic-gate _exit(i); 11577c478bd9Sstevel@tonic-gate } 115865b0c20eSnakanon #endif 11597c478bd9Sstevel@tonic-gate 11606c02b4a4Smuffin void 11616c02b4a4Smuffin printprompt(void) 11627c478bd9Sstevel@tonic-gate { 11636c02b4a4Smuffin tchar *cp; 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate if (!whyles) { 11667c478bd9Sstevel@tonic-gate /* 11677c478bd9Sstevel@tonic-gate * Print the prompt string 11687c478bd9Sstevel@tonic-gate */ 11697c478bd9Sstevel@tonic-gate for (cp = value(S_prompt /* "prompt" */); *cp; cp++) 11707c478bd9Sstevel@tonic-gate if (*cp == HIST) 11717c478bd9Sstevel@tonic-gate printf("%d", eventno + 1); 11727c478bd9Sstevel@tonic-gate else { 11737c478bd9Sstevel@tonic-gate if (*cp == '\\' && cp[1] == HIST) 11747c478bd9Sstevel@tonic-gate cp++; 11757c478bd9Sstevel@tonic-gate Putchar(*cp | QUOTE); 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate } else 11787c478bd9Sstevel@tonic-gate /* 11797c478bd9Sstevel@tonic-gate * Prompt for forward reading loop 11807c478bd9Sstevel@tonic-gate * body content. 11817c478bd9Sstevel@tonic-gate */ 11827c478bd9Sstevel@tonic-gate printf("? "); 11837c478bd9Sstevel@tonic-gate flush(); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /* 11877c478bd9Sstevel@tonic-gate * Save char * block. 11887c478bd9Sstevel@tonic-gate */ 11897c478bd9Sstevel@tonic-gate tchar ** 11906c02b4a4Smuffin strblktotsblk(char **v, int num) 11917c478bd9Sstevel@tonic-gate { 11926c02b4a4Smuffin tchar **newv = 119365b0c20eSnakanon (tchar **)xcalloc((unsigned)(num+ 1), sizeof (tchar **)); 11947c478bd9Sstevel@tonic-gate tchar **onewv = newv; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate while (*v && num--) 11977c478bd9Sstevel@tonic-gate *newv++ = strtots(NOSTR, *v++); 11987c478bd9Sstevel@tonic-gate *newv = 0; 11997c478bd9Sstevel@tonic-gate return (onewv); 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12026c02b4a4Smuffin void 12036c02b4a4Smuffin sigwaiting(void) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate _signal(SIGWAITING, sigwaiting); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12086c02b4a4Smuffin void 12096c02b4a4Smuffin siglwp(void) 12107c478bd9Sstevel@tonic-gate { 12117c478bd9Sstevel@tonic-gate _signal(SIGLWP, siglwp); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate /* 12167c478bd9Sstevel@tonic-gate * Following functions and data are used for csh to do its 12177c478bd9Sstevel@tonic-gate * file descriptors book keeping. 12187c478bd9Sstevel@tonic-gate */ 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate static int *fdinuse = NULL; /* The list of files opened by csh */ 12217c478bd9Sstevel@tonic-gate static int nbytesused = 0; /* no of bytes allocated to fdinuse */ 12227c478bd9Sstevel@tonic-gate static int max_fd = 0; /* The maximum descriptor in fdinuse */ 12237c478bd9Sstevel@tonic-gate static int my_pid; /* The process id set in initdesc() */ 12247c478bd9Sstevel@tonic-gate static int NoFile = NOFILE; /* The number of files I can use. */ 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate /* 12277c478bd9Sstevel@tonic-gate * Get the number of files this csh can use. 12287c478bd9Sstevel@tonic-gate * 12297c478bd9Sstevel@tonic-gate * Move the initial descriptors to their eventual 12307c478bd9Sstevel@tonic-gate * resting places, closing all other units. 12317c478bd9Sstevel@tonic-gate * 12327c478bd9Sstevel@tonic-gate * Also, reserve 0/1/2, so NIS+ routines do not get 12337c478bd9Sstevel@tonic-gate * hold of them. And initialize fdinuse list and set 12347c478bd9Sstevel@tonic-gate * the current process id. 12357c478bd9Sstevel@tonic-gate * 12367c478bd9Sstevel@tonic-gate * If this csh was invoked from setuid'ed script file, 12377c478bd9Sstevel@tonic-gate * do not close the third argument passed. The file 12387c478bd9Sstevel@tonic-gate * must be one of /dev/fd/0,1,2,,, 12397c478bd9Sstevel@tonic-gate * (execv() always passes three arguments when it execs a script 12407c478bd9Sstevel@tonic-gate * file in a form of #! /bin/csh -b.) 12417c478bd9Sstevel@tonic-gate * 12427c478bd9Sstevel@tonic-gate * If is_reinit is set in initdesc_x(), then we only close the file 12437c478bd9Sstevel@tonic-gate * descriptors that we actually opened (as recorded in fdinuse). 12447c478bd9Sstevel@tonic-gate */ 12456c02b4a4Smuffin void 12466c02b4a4Smuffin initdesc(int argc, char *argv[]) 12477c478bd9Sstevel@tonic-gate { 12487c478bd9Sstevel@tonic-gate initdesc_x(argc, argv, 0); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12516c02b4a4Smuffin void 12526c02b4a4Smuffin reinitdesc(int argc, char *argv[]) 12537c478bd9Sstevel@tonic-gate { 12547c478bd9Sstevel@tonic-gate initdesc_x(argc, argv, 1); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * Callback functions for closing all file descriptors. 12597c478bd9Sstevel@tonic-gate */ 12607c478bd9Sstevel@tonic-gate static int 12617c478bd9Sstevel@tonic-gate close_except(void *cd, int fd) 12627c478bd9Sstevel@tonic-gate { 12637c478bd9Sstevel@tonic-gate int script_fd = *(int *)cd; 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate if (fd >= 3 && fd < NoFile && fd != script_fd) 12667c478bd9Sstevel@tonic-gate (void) close(fd); 12677c478bd9Sstevel@tonic-gate return (0); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate static int 12717c478bd9Sstevel@tonic-gate close_inuse(void *cd, int fd) 12727c478bd9Sstevel@tonic-gate { 12737c478bd9Sstevel@tonic-gate int script_fd = *(int *)cd; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate if (fd >= 3 && fd < NoFile && fd != script_fd && 12767c478bd9Sstevel@tonic-gate CSH_FD_ISSET(fd, fdinuse)) { 12777c478bd9Sstevel@tonic-gate (void) close(fd); 12787c478bd9Sstevel@tonic-gate unsetfd(fd); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate return (0); 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate 12836c02b4a4Smuffin void 12846c02b4a4Smuffin initdesc_x(int argc, char *argv[], int is_reinit) 12857c478bd9Sstevel@tonic-gate { 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate int script_fd = -1; 12887c478bd9Sstevel@tonic-gate struct stat buf; 12897c478bd9Sstevel@tonic-gate struct rlimit rlp; 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * Get pid of this shell 12937c478bd9Sstevel@tonic-gate */ 12947c478bd9Sstevel@tonic-gate my_pid = getpid(); 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate /* 12977c478bd9Sstevel@tonic-gate * Get the hard limit numbers of descriptors 12987c478bd9Sstevel@tonic-gate * this csh can use. 12997c478bd9Sstevel@tonic-gate */ 13007c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlp) == 0) 13017c478bd9Sstevel@tonic-gate NoFile = rlp.rlim_cur; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate /* 13047c478bd9Sstevel@tonic-gate * If this csh was invoked for executing setuid script file, 13057c478bd9Sstevel@tonic-gate * the third argument passed is the special file name 13067c478bd9Sstevel@tonic-gate * which should not be closed. This special file name is 13077c478bd9Sstevel@tonic-gate * in the form /dev/fd/X. 13087c478bd9Sstevel@tonic-gate */ 13097c478bd9Sstevel@tonic-gate if (argc >= 3) 13107c478bd9Sstevel@tonic-gate if (sscanf(argv[2], "/dev/fd/%d", &script_fd) != 1) 13117c478bd9Sstevel@tonic-gate script_fd = -1; 13127c478bd9Sstevel@tonic-gate else 1313*134a1f4eSCasper H.S. Dik /* Make sure to close this file on exec. */ 1314*134a1f4eSCasper H.S. Dik fcntl(script_fd, F_SETFD, 1); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate if (fdinuse == NULL) { 1317*134a1f4eSCasper H.S. Dik nbytesused = sizeof (int) * 1318*134a1f4eSCasper H.S. Dik howmany(NoFile, sizeof (int) * NBBY); 13197c478bd9Sstevel@tonic-gate fdinuse = (int *)xalloc(nbytesused); 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * Close all files except 0/1/2 to get a clean 13247c478bd9Sstevel@tonic-gate * file descritor space. 13257c478bd9Sstevel@tonic-gate */ 13267c478bd9Sstevel@tonic-gate if (!is_reinit) 13277c478bd9Sstevel@tonic-gate (void) fdwalk(close_except, &script_fd); 13287c478bd9Sstevel@tonic-gate else 13297c478bd9Sstevel@tonic-gate (void) fdwalk(close_inuse, &script_fd); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate didfds = 0; /* 0, 1, 2 aren't set up */ 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate if (fstat(0, &buf) < 0) 13347c478bd9Sstevel@tonic-gate open("/dev/null", 0); 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate (void) fcntl(SHIN = dcopy(0, FSHIN), F_SETFD, 1); 13377c478bd9Sstevel@tonic-gate (void) fcntl(SHOUT = dcopy(1, FSHOUT), F_SETFD, 1); 13387c478bd9Sstevel@tonic-gate (void) fcntl(SHDIAG = dcopy(2, FSHDIAG), F_SETFD, 1); 13397c478bd9Sstevel@tonic-gate (void) fcntl(OLDSTD = dcopy(SHIN, FOLDSTD), F_SETFD, 1); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * Open 0/1/2 to avoid Nis+ functions to pick them up. 13437c478bd9Sstevel@tonic-gate * Now, 0/1/2 are saved, close them and open them. 13447c478bd9Sstevel@tonic-gate */ 13457c478bd9Sstevel@tonic-gate close(0); close(1); close(2); 13467c478bd9Sstevel@tonic-gate open("/dev/null", 0); 13477c478bd9Sstevel@tonic-gate dup(0); 13487c478bd9Sstevel@tonic-gate dup(0); 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * Clear fd_set mask 13527c478bd9Sstevel@tonic-gate */ 13537c478bd9Sstevel@tonic-gate if (!is_reinit) 13547c478bd9Sstevel@tonic-gate CSH_FD_ZERO(fdinuse, nbytesused); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate /* 13587c478bd9Sstevel@tonic-gate * This routine is called after an error to close up 13597c478bd9Sstevel@tonic-gate * any units which may have been left open accidentally. 13607c478bd9Sstevel@tonic-gate * 13617c478bd9Sstevel@tonic-gate * You only need to remove files in fdinuse list. 13627c478bd9Sstevel@tonic-gate * After you have removed the files, you can clear the 13637c478bd9Sstevel@tonic-gate * list and max_fd. 13647c478bd9Sstevel@tonic-gate */ 13656c02b4a4Smuffin void 13666c02b4a4Smuffin closem(void) 13677c478bd9Sstevel@tonic-gate { 13686c02b4a4Smuffin int f; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate for (f = 3; f <= max_fd; f++) { 13717c478bd9Sstevel@tonic-gate if (CSH_FD_ISSET(f, fdinuse) && 13727c478bd9Sstevel@tonic-gate f != SHIN && f != SHOUT && f != SHDIAG && 13737c478bd9Sstevel@tonic-gate f != OLDSTD && f != FSHTTY) 13747c478bd9Sstevel@tonic-gate close(f); 13757c478bd9Sstevel@tonic-gate } 13767c478bd9Sstevel@tonic-gate CSH_FD_ZERO(fdinuse, nbytesused); 13777c478bd9Sstevel@tonic-gate max_fd = 0; 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate /* 13817c478bd9Sstevel@tonic-gate * Reset my_pid when a new process is created. Only call this 13827c478bd9Sstevel@tonic-gate * if you want the process to affect fdinuse (e.g., fork, but 13837c478bd9Sstevel@tonic-gate * not vfork). 13847c478bd9Sstevel@tonic-gate */ 13856c02b4a4Smuffin void 13866c02b4a4Smuffin new_process(void) 13877c478bd9Sstevel@tonic-gate { 13887c478bd9Sstevel@tonic-gate my_pid = getpid(); 13897c478bd9Sstevel@tonic-gate } 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate /* 13937c478bd9Sstevel@tonic-gate * Whenever Csh open/create/dup/pipe a file or files, 13947c478bd9Sstevel@tonic-gate * Csh keeps track of its open files. The open files 13957c478bd9Sstevel@tonic-gate * are kept in "fdinuse, Fd In Use" list. 13967c478bd9Sstevel@tonic-gate * 13977c478bd9Sstevel@tonic-gate * When a file descriptor is newly allocated, setfd() is 13987c478bd9Sstevel@tonic-gate * used to mark the fact in "fdinuse" list. 13997c478bd9Sstevel@tonic-gate * For example, 14007c478bd9Sstevel@tonic-gate * fd = open("newfile", 0); 14017c478bd9Sstevel@tonic-gate * setfd(fd); 14027c478bd9Sstevel@tonic-gate * 14037c478bd9Sstevel@tonic-gate * When a file is freed by close() function, unsetfd() is 14047c478bd9Sstevel@tonic-gate * used to remove the fd from "fdinuse" list. 14057c478bd9Sstevel@tonic-gate * For example, 14067c478bd9Sstevel@tonic-gate * close(fd); 14077c478bd9Sstevel@tonic-gate * unsetfd(fd); 14087c478bd9Sstevel@tonic-gate */ 14096c02b4a4Smuffin void 14106c02b4a4Smuffin setfd(int fd) 14117c478bd9Sstevel@tonic-gate { 14127c478bd9Sstevel@tonic-gate /* 14137c478bd9Sstevel@tonic-gate * Because you want to avoid 14147c478bd9Sstevel@tonic-gate * conflict due to vfork(). 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate if (my_pid != getpid()) 14177c478bd9Sstevel@tonic-gate return; 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate if (fd >= NoFile || fd < 0) 14207c478bd9Sstevel@tonic-gate return; 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate if (fd > max_fd) 14237c478bd9Sstevel@tonic-gate max_fd = fd; 14247c478bd9Sstevel@tonic-gate CSH_FD_SET(fd, fdinuse); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14276c02b4a4Smuffin void 14286c02b4a4Smuffin unsetfd(int fd) 14297c478bd9Sstevel@tonic-gate { 14306c02b4a4Smuffin int i; 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate /* 14337c478bd9Sstevel@tonic-gate * Because you want to avoid 14347c478bd9Sstevel@tonic-gate * conflict due to vfork(). 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate if (my_pid != getpid()) 14377c478bd9Sstevel@tonic-gate return; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate if (fd >= NoFile || fd < 0) 14407c478bd9Sstevel@tonic-gate return; 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate CSH_FD_CLR(fd, fdinuse); 14437c478bd9Sstevel@tonic-gate if (fd == max_fd) { 14447c478bd9Sstevel@tonic-gate for (i = max_fd-1; i >= 3; i--) 14457c478bd9Sstevel@tonic-gate if (CSH_FD_ISSET(i, fdinuse)) { 14467c478bd9Sstevel@tonic-gate max_fd = i; 14477c478bd9Sstevel@tonic-gate return; 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate max_fd = 0; 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate } 1452