1 /* $NetBSD: csh.c,v 1.40 2007/07/16 18:26:09 christos Exp $ */
4 * Copyright (c) 1980, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)csh.c 8.2 (Berkeley) 10/12/93";
42 __RCSID("$NetBSD: csh.c,v 1.40 2007/07/16 18:26:09 christos Exp $");
46 #include <sys/types.h>
47 #include <sys/ioctl.h>
53 #include <paths.h> /* should this be included in pathnames.h instead? */
64 #include "pathnames.h"
70 * Bill Joy, UC Berkeley, California, USA
71 * October 1978, May 1980
73 * Jim Kulp, IIASA, Laxenburg, Austria
76 * Christos Zoulas, Cornell University
80 Char
*dumphist
[] = {STRhistory
, STRmh
, 0, 0};
81 Char
*loadhist
[] = {STRsource
, STRmh
, STRtildothist
, 0};
94 extern char **environ
;
96 static int readf(void *, char *, int);
97 static fpos_t seekf(void *, fpos_t, int);
98 static int writef(void *, const char *, int);
99 static int closef(void *);
100 static int srccat(Char
*, Char
*);
101 static int srcfile(const char *, int, int);
102 static void phup(int);
103 static void srcunit(int, int, int);
104 static void mailchk(void);
105 #ifndef _PATH_DEFPATH
106 static Char
**defaultpath(void);
109 int main(int, char *[]);
112 main(int argc
, char *argv
[])
114 struct sigaction oact
;
125 setprogname(argv
[0]);
126 settimes(); /* Immed. estab. timing base */
129 * Initialize non constant strings
132 STR_BSHELL
= SAVE(_PATH_BSHELL
);
135 STR_SHELLPATH
= SAVE(_PATH_CSHELL
);
137 STR_environ
= blk2short(environ
);
138 environ
= short2blk(STR_environ
); /* So that we can free it */
139 STR_WORD_CHARS
= SAVE(WORD_CHARS
);
143 word_chars
= STR_WORD_CHARS
;
146 if (eq(str2short(tempv
[0]), STRaout
)) /* A.out's are quittable */
153 * We are a login shell if: 1. we were invoked as -<something> and we had
154 * no arguments 2. or we were invoked only with the -l flag
156 loginsh
= (**tempv
== '-' && argc
== 1) ||
157 (argc
== 2 && tempv
[1][0] == '-' && tempv
[1][1] == 'l' &&
158 tempv
[1][2] == '\0');
160 if (loginsh
&& **tempv
!= '-') {
162 * Mangle the argv space
167 for (tcp
= *tempv
; *tcp
++;)
169 for (tcp
--; tcp
>= *tempv
; tcp
--)
179 (void)setlocale(LC_ALL
, "");
183 for (k
= 0200; k
<= 0377 && !Isprint(k
); k
++)
185 AsciiOnly
= k
> 0377;
188 AsciiOnly
= getenv("LANG") == NULL
&& getenv("LC_CTYPE") == NULL
;
192 * Move the descriptors to safe places. The variable didfds is 0 while we
193 * have only FSH* to work with. When didfds is true, we have 0,1,2 and
194 * prefer to use these.
198 * XXX: This is to keep programs that use stdio happy.
199 * what we really want is freunopen() ....
200 * Closing cshin cshout and csherr (which are really stdin stdout
201 * and stderr at this point and then reopening them in the same order
202 * gives us again stdin == cshin stdout == cshout and stderr == csherr.
203 * If that was not the case builtins like printf that use stdio
204 * would break. But in any case we could fix that with memcpy and
205 * a bit of pointer manipulation...
206 * Fortunately this is not needed under the current implementation
210 (void)fclose(cshout
);
211 (void)fclose(csherr
);
212 if (!(cshin
= funopen((void *) &SHIN
, readf
, writef
, seekf
, closef
)))
214 if (!(cshout
= funopen((void *) &SHOUT
, readf
, writef
, seekf
, closef
)))
216 if (!(csherr
= funopen((void *) &SHERR
, readf
, writef
, seekf
, closef
)))
218 (void)setvbuf(cshin
, NULL
, _IOLBF
, 0);
219 (void)setvbuf(cshout
, NULL
, _IOLBF
, 0);
220 (void)setvbuf(csherr
, NULL
, _IOLBF
, 0);
223 * Initialize the shell variables. ARGV and PROMPT are initialized later.
224 * STATUS is also munged in several places. CHILD is munged when
227 set(STRstatus
, Strsave(STR0
));
229 if ((ecp
= getenv("HOME")) != NULL
)
230 cp
= quote(SAVE(ecp
));
235 fast
= 1; /* No home -> can't read scripts */
238 dinit(cp
); /* dinit thinks that HOME == cwd in a login
241 * Grab other useful things from the environment. Should we grab
244 if ((ecp
= getenv("LOGNAME")) != NULL
||
245 (ecp
= getenv("USER")) != NULL
)
246 set(STRuser
, quote(SAVE(ecp
)));
247 if ((ecp
= getenv("TERM")) != NULL
)
248 set(STRterm
, quote(SAVE(ecp
)));
251 * Re-initialize path if set in environment
253 if ((ecp
= getenv("PATH")) == NULL
) {
255 importpath(str2short(_PATH_DEFPATH
));
257 setq(STRpath
, defaultpath(), &shvhed
);
260 importpath(str2short(ecp
));
263 set(STRshell
, Strsave(STR_SHELLPATH
));
265 doldol
= putn((int) getpid()); /* For $$ */
266 shtemp
= Strspl(STRtmpsh
, doldol
); /* For << */
269 * Record the interrupt states from the parent process. If the parent is
270 * non-interruptible our hand must be forced or we (and our children) won't
271 * be either. Our children inherit termination from our parent. We catch it
272 * only if we are the login shell.
274 /* parents interruptibility */
275 (void)sigaction(SIGINT
, NULL
, &oact
);
276 parintr
= oact
.sa_handler
;
277 (void)sigaction(SIGTERM
, NULL
, &oact
);
278 parterm
= oact
.sa_handler
;
280 /* catch these all, login shell or not */
281 (void)signal(SIGHUP
, phup
); /* exit processing on HUP */
282 (void)signal(SIGXCPU
, phup
); /* ...and on XCPU */
283 (void)signal(SIGXFSZ
, phup
); /* ...and on XFSZ */
286 * Process the arguments.
288 * Note that processing of -v/-x is actually delayed till after script
291 * We set the first character of our name to be '-' if we are a shell
292 * running interruptible commands. Many programs which examine ps'es
293 * use this to filter such shells out.
296 while (argc
> 0 && (tcp
= tempv
[0])[0] == '-' && *++tcp
!= '\0' && !batch
) {
299 case 0: /* - Interruptible, no prompt */
304 case 'b': /* -b Next arg is input file */
307 case 'c': /* -c Command input from arg */
311 arginp
= SAVE(tempv
[0]);
315 case 'e': /* -e Exit on any error */
318 case 'f': /* -f Fast start */
321 case 'i': /* -i Interactive, even if !intty */
325 case 'm': /* -m read .cshrc (from su) */
328 case 'n': /* -n Don't execute */
331 case 'q': /* -q (Undoc'd) ... die on quit */
334 case 's': /* -s Read from std input */
337 case 't': /* -t Read one line from input */
342 case 'v': /* -v Echo hist expanded input */
343 nverbose
= 1; /* ... later */
345 case 'x': /* -x Echo just before execution */
346 nexececho
= 1; /* ... later */
348 case 'V': /* -V Echo hist expanded input */
349 setNS(STRverbose
); /* NOW! */
351 case 'X': /* -X Echo just before execution */
352 setNS(STRecho
); /* NOW! */
359 if (quitit
) /* With all due haste, for debugging */
360 (void)signal(SIGQUIT
, SIG_DFL
);
363 * Unless prevented by -, -c, -i, -s, or -t, if there are remaining
364 * arguments the first of them is the name of a shell file from which to
367 if (nofile
== 0 && argc
> 0) {
368 nofile
= open(tempv
[0], O_RDONLY
);
370 child
= 1; /* So this doesn't return */
371 stderror(ERR_SYSTEM
, tempv
[0], strerror(errno
));
373 ffile
= SAVE(tempv
[0]);
375 * Replace FSHIN. Handle /dev/std{in,out,err} specially
376 * since once they are closed we cannot open them again.
377 * In that case we use our own saved descriptors
379 if ((SHIN
= dmove(nofile
, FSHIN
)) < 0)
391 stderror(ERR_SYSTEM
, tempv
[0], strerror(errno
));
394 (void)ioctl(SHIN
, FIOCLEX
, NULL
);
396 /* argc not used any more */ tempv
++;
399 intty
= isatty(SHIN
);
401 if (intty
|| (intact
&& isatty(SHOUT
))) {
402 if (!batch
&& (uid
!= euid
|| gid
!= egid
)) {
404 child
= 1; /* So this doesn't return */
405 stderror(ERR_SYSTEM
, "csh", strerror(errno
));
409 * Decide whether we should play with signals or not. If we are explicitly
410 * told (via -i, or -) or we are a login shell (arg0 starts with -) or the
411 * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
412 * Note that in only the login shell is it likely that parent may have set
413 * signals to be ignored
415 if (loginsh
|| intact
|| (intty
&& isatty(SHOUT
)))
419 * Save the remaining arguments in argv.
421 setq(STRargv
, blk2short(tempv
), &shvhed
);
427 set(STRprompt
, Strsave(uid
== 0 ? STRsymhash
: STRsymcent
));
428 /* that's a meta-questionmark */
429 set(STRprompt2
, Strsave(STRmquestion
));
433 * If we are an interactive shell, then start fiddling with the signals;
434 * this is a tricky game.
440 if (!quitit
) /* Wary! */
441 (void)signal(SIGQUIT
, SIG_IGN
);
442 (void)signal(SIGINT
, pintr
);
443 sigemptyset(&nsigset
);
444 (void)sigaddset(&nsigset
, SIGINT
);
445 (void)sigprocmask(SIG_BLOCK
, &nsigset
, NULL
);
446 (void)signal(SIGTERM
, SIG_IGN
);
447 if (quitit
== 0 && arginp
== 0) {
448 (void)signal(SIGTSTP
, SIG_IGN
);
449 (void)signal(SIGTTIN
, SIG_IGN
);
450 (void)signal(SIGTTOU
, SIG_IGN
);
452 * Wait till in foreground, in case someone stupidly runs csh &
453 * dont want to try to grab away the tty.
457 else if (isatty(FSHOUT
))
459 else if (isatty(OLDSTD
))
464 if ((tpgrp
= tcgetpgrp(f
)) != -1) {
465 if (tpgrp
!= shpgrp
) {
466 sig_t old
= signal(SIGTTIN
, SIG_DFL
);
467 (void)kill(0, SIGTTIN
);
468 (void)signal(SIGTTIN
, old
);
475 * Setpgid will fail if we are a session leader and
476 * mypid == mypgrp (POSIX 4.3.3)
479 if (setpgid(0, shpgrp
) == -1)
482 * We do that after we set our process group, to make sure
483 * that the process group belongs to a process in the same
484 * session as the tty (our process and our group) (POSIX 7.2.4)
486 if (tcsetpgrp(f
, shpgrp
) == -1)
488 (void)ioctl(dcopy(f
, FSHTTY
), FIOCLEX
, NULL
);
492 (void)fprintf(csherr
, "Warning: no access to tty (%s).\n",
494 (void)fprintf(csherr
, "Thus no job control in this shell.\n");
498 if ((setintr
== 0) && (parintr
== SIG_DFL
))
500 (void)signal(SIGCHLD
, pchild
); /* while signals not ready */
503 * Set an exit here in case of an interrupt or error reading the shell
506 reenter
= setexit(); /* PWP */
507 haderr
= 0; /* In case second time through */
508 if (!fast
&& reenter
== 0) {
509 /* Will have value(STRhome) here because set fast if don't */
517 sigemptyset(&nsigset
);
518 (void)sigaddset(&nsigset
, SIGINT
);
519 (void)sigprocmask(SIG_BLOCK
, &nsigset
, &osigset
);
522 parintr
= SIG_IGN
; /* Disable onintr */
523 #ifdef _PATH_DOTCSHRC
524 (void)srcfile(_PATH_DOTCSHRC
, 0, 0);
526 if (!fast
&& !arginp
&& !onelflg
)
528 #ifdef _PATH_DOTLOGIN
530 (void)srcfile(_PATH_DOTLOGIN
, 0, 0);
532 (void)sigprocmask(SIG_SETMASK
, &osigset
, NULL
);
536 (void)srccat(value(STRhome
), STRsldotcshrc
);
538 if (!fast
&& !arginp
&& !onelflg
&& !havhash
)
541 * Source history before .login so that it is available in .login
543 if ((cp
= value(STRhistfile
)) != STRNULL
)
545 dosource(loadhist
, NULL
);
547 (void)srccat(value(STRhome
), STRsldotlogin
);
551 * Now are ready for the -v and -x flags
559 * All the rest of the world is inside this call. The argument to process
560 * indicates whether it should catch "error unwinds". Thus if we are a
561 * interactive shell our call here will never return by being blown past on
571 (void)fprintf(cshout
, "logout\n");
577 (void)fprintf(cshout
, "exit\n");
589 (void)setpgid(0, opgrp
);
590 (void)tcsetpgrp(FSHTTY
, opgrp
);
601 for (dp
= cp
; *dp
; dp
++)
605 * i+2 where i is the number of colons in the path. There are i+1
606 * directories in the path plus we need room for a zero terminator.
608 pv
= (Char
**)xcalloc((size_t) (i
+ 2), sizeof(Char
**));
613 if ((c
= *dp
) == ':' || c
== 0) {
615 pv
[i
++] = Strsave(*cp
? cp
: STRdot
);
626 setq(STRpath
, pv
, &shvhed
);
630 * Source to the file which is the catenation of the argument names.
633 srccat(Char
*cp
, Char
*dp
)
641 return srcfile(ptr
, mflag
? 0 : 1, 0);
645 * Source to a file putting the file descriptor in a safe place (> 2).
648 srcfile(const char *f
, int onlyown
, int flag
)
652 if ((unit
= open(f
, O_RDONLY
)) == -1)
654 unit
= dmove(unit
, -1);
656 (void) ioctl(unit
, FIOCLEX
, NULL
);
657 srcunit(unit
, onlyown
, flag
);
662 * Source to a unit. If onlyown it must be our file or our group or
663 * we don't chance it. This occurs on ".cshrc"s and the like.
668 srcunit(int unit
, int onlyown
, int hflg
)
670 /* We have to push down a lot of state here */
671 /* All this could go into a structure */
672 struct whyle
*oldwhyl
;
674 sigset_t nsigset
, osigset
;
676 Char
*oarginp
, *oevalp
, **oevalvec
, *ogointr
;
678 int oSHIN
, oinsource
, oldintty
, oonelflg
;
679 int oenterhist
, otell
;
680 /* The (few) real local variables */
685 oinsource
= insource
;
692 oenterhist
= enterhist
;
703 if (fstat(unit
, &stb
) < 0) {
710 * There is a critical section here while we are pushing down the input
711 * stream since we have stuff in different structures. If we weren't
712 * careful an interrupt could corrupt SHIN's Bin structure and kill the
715 * We could avoid the critical region by grouping all the stuff in a single
716 * structure and pointing at it to move it all at once. This is less
717 * efficient globally on many variable references however.
723 sigemptyset(&nsigset
);
724 (void)sigaddset(&nsigset
, SIGINT
);
725 (void)sigprocmask(SIG_BLOCK
, &nsigset
, &osigset
);
727 /* Setup the new values of the state stuff saved above */
728 (void)memcpy(&saveB
, &B
, sizeof(B
));
730 fseekp
= feobp
= fblocks
= 0;
731 oSHIN
= SHIN
, SHIN
= unit
, arginp
= 0, onelflg
= 0;
732 intty
= isatty(SHIN
), whyles
= 0, gointr
= 0;
740 * Now if we are allowing commands to be interrupted, we let ourselves be
744 (void)sigprocmask(SIG_SETMASK
, &osigset
, NULL
);
747 if ((my_reenter
= setexit()) == 0)
748 process(0); /* 0 -> blow away on errors */
751 (void)sigprocmask(SIG_SETMASK
, &osigset
, NULL
);
755 /* We made it to the new state... free up its storage */
756 /* This code could get run twice but xfree doesn't care */
757 for (i
= 0; i
< fblocks
; i
++)
758 xfree((ptr_t
) fbuf
[i
]);
761 /* Reset input arena */
762 (void)memcpy(&B
, &saveB
, sizeof(B
));
764 (void)close(SHIN
), SHIN
= oSHIN
;
765 arginp
= oarginp
, onelflg
= oonelflg
;
766 evalp
= oevalp
, evalvec
= oevalvec
;
767 intty
= oldintty
, whyles
= oldwhyl
, gointr
= ogointr
;
770 enterhist
= oenterhist
;
776 * If process reset() (effectively an unwind) then we must also unwind.
779 stderror(ERR_SILENT
);
780 insource
= oinsource
;
786 Char buf
[BUFSIZE
], hbuf
[BUFSIZE
], *hfile
;
787 int fp
, ftmp
, oldidfds
;
788 struct varent
*shist
;
792 * If $savehist is just set, we use the value of $history
793 * else we use the value in $savehist
795 if ((shist
= adrof(STRsavehist
)) != NULL
) {
796 if (shist
->vec
[0][0] != '\0')
797 (void)Strcpy(hbuf
, shist
->vec
[0]);
798 else if ((shist
= adrof(STRhistory
)) && shist
->vec
[0][0] != '\0')
799 (void)Strcpy(hbuf
, shist
->vec
[0]);
806 if ((hfile
= value(STRhistfile
)) == STRNULL
) {
807 hfile
= Strcpy(buf
, value(STRhome
));
808 (void) Strcat(buf
, STRsldthist
);
811 if ((fp
= open(short2str(hfile
), O_WRONLY
| O_CREAT
| O_TRUNC
,
820 dohist(dumphist
, NULL
);
833 (void)signal(SIGQUIT
, SIG_IGN
);
834 (void)signal(SIGINT
, SIG_IGN
);
835 (void)signal(SIGTERM
, SIG_IGN
);
836 setintr
= 0; /* No interrupts after "logout" */
837 if (!(adrof(STRlogout
)))
838 set(STRlogout
, STRnormal
);
839 #ifdef _PATH_DOTLOGOUT
840 (void)srcfile(_PATH_DOTLOGOUT
, 0, 0);
843 (void)srccat(value(STRhome
), STRsldtlogout
);
857 * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit
858 * directly because we poke child here. Otherwise we might continue
859 * unwarrantedly (sic).
862 s
= value(STRstatus
);
863 xexit(s
? getn(s
) : 0);
868 * in the event of a HUP we want to save the history
876 * We kill the last foreground process group. It then becomes
877 * responsible to propagate the SIGHUP to its progeny.
880 struct process
*pp
, *np
;
882 for (pp
= proclist
.p_next
; pp
; pp
= pp
->p_next
) {
885 * Find if this job is in the foreground. It could be that
886 * the process leader has exited and the foreground flag
891 * If a process is in the foreground; we try to kill
892 * its process group. If we succeed, then the
893 * whole job is gone. Otherwise we keep going...
894 * But avoid sending HUP to the shell again.
896 if ((np
->p_flags
& PFOREGND
) != 0 && np
->p_jobid
!= shpgrp
&&
897 kill(-np
->p_jobid
, SIGHUP
) != -1) {
898 /* In case the job was suspended... */
899 (void)kill(-np
->p_jobid
, SIGCONT
);
902 while ((np
= np
->p_friends
) != pp
);
909 Char
*jobargv
[2] = {STRjobs
, 0};
912 * Catch an interrupt, e.g. during lexical input.
913 * If we are an interactive shell, we reset the interrupt catch
914 * immediately. In any case we drain the shell output,
915 * and finally go through the normal error mechanism, which
916 * gets a chance to make the shell go away.
930 sigset_t nsigset
, osigset
;
932 sigemptyset(&nsigset
);
933 (void)sigprocmask(SIG_BLOCK
, &nsigset
, &osigset
);
936 (void)sigdelset(&nsigset
, SIGINT
);
937 (void)sigprocmask(SIG_SETMASK
, &nsigset
, NULL
);
940 (void)fprintf(cshout
, "\n");
941 dojobs(jobargv
, NULL
);
942 stderror(ERR_NAME
| ERR_INTR
);
945 (void)sigdelset(&osigset
, SIGCHLD
);
946 (void)sigprocmask(SIG_SETMASK
, &osigset
, NULL
);
947 (void)fpurge(cshout
);
951 * If we have an active "onintr" then we search for the label. Note that if
952 * one does "onintr -" then we shan't be interruptible so we needn't worry
958 if ((v
= pargv
) != NULL
)
959 pargv
= 0, blkfree(v
);
960 if ((v
= gargv
) != NULL
)
961 gargv
= 0, blkfree(v
);
964 else if (intty
&& wantnl
) {
965 (void)fputc('\r', cshout
);
966 (void)fputc('\n', cshout
);
968 stderror(ERR_SILENT
);
973 * Process is the main driving routine for the shell.
974 * It runs all command processing, except for those within { ... }
975 * in expressions (which is run by a routine evalav in sh.exp.c which
976 * is a stripped down process), and `...` evaluation which is run
977 * also by a subset of this code in sh.glob.c in the routine backeval.
979 * The code here is a little strange because part of it is interruptible
980 * and hence freeing of structures appears to occur when none is necessary
981 * if this is ignored.
983 * Note that if catch is not set then we will unwind on any error.
984 * If an end-of-file occurs, we return.
986 static struct command
*savet
= NULL
;
1000 paraml
.next
= paraml
.prev
= ¶ml
;
1001 paraml
.word
= STRNULL
;
1003 justpr
= enterhist
; /* execute if not entering history */
1006 * Interruptible during interactive reads
1009 sigemptyset(&nsigset
);
1010 (void)sigaddset(&nsigset
, SIGINT
);
1011 (void)sigprocmask(SIG_UNBLOCK
, &nsigset
, NULL
);
1015 * For the sake of reset()
1019 freesyn(savet
), savet
= NULL
;
1031 * Every error is eventually caught here or the shell dies. It is
1032 * at this point that we clean up any left-over open files, by
1033 * closing all but a fixed number of pre-defined files. Thus
1034 * routines don't have to worry about leaving files open due to
1035 * deeper errors... they will get closed here.
1048 if (intty
&& prompt
&& evalvec
== 0) {
1051 * If we are at the end of the input buffer then we are going to
1052 * read fresh stuff. Otherwise, we are rereading input and don't
1053 * need or want to prompt.
1055 if (aret
== F_SEEK
&& fseekp
== feobp
)
1057 (void)fflush(cshout
);
1060 xfree((ptr_t
) seterr
);
1065 * Echo not only on VERBOSE, but also with history expansion. If there
1066 * is a lexical error then we forego history echo.
1068 if ((lex(¶ml
) && !seterr
&& intty
) || adrof(STRverbose
)) {
1069 int odidfds
= didfds
;
1072 prlex(csherr
, ¶ml
);
1078 * The parser may lose space if interrupted.
1081 (void)sigprocmask(SIG_BLOCK
, &nsigset
, NULL
);
1084 * Save input text on the history list if reading in old history, or it
1085 * is from the terminal at the top level and not in a loop.
1087 * PWP: entry of items in the history list while in a while loop is done
1090 if (enterhist
|| (catch && intty
&& !whyles
))
1094 * Print lexical error messages, except when sourcing history lists.
1096 if (!enterhist
&& seterr
)
1100 * If had a history command :p modifier then this is as far as we
1109 * Parse the words of the input into a parse tree.
1111 savet
= syntax(paraml
.next
, ¶ml
, 0);
1115 execute(savet
, (tpgrp
> 0 ? tpgrp
: -1), NULL
, NULL
);
1121 freesyn((struct command
*) savet
), savet
= NULL
;
1129 dosource(Char
**v
, struct command
*t
)
1131 Char buf
[BUFSIZE
], *f
;
1136 if (*v
&& eq(*v
, STRmh
)) {
1138 stderror(ERR_NAME
| ERR_HFLAG
);
1141 (void)Strcpy(buf
, *v
);
1142 f
= globone(buf
, G_ERROR
);
1143 (void)strcpy((char *)buf
, short2str(f
));
1145 if (!srcfile((char *)buf
, 0, hflg
) && !hflg
)
1146 stderror(ERR_SYSTEM
, (char *)buf
, strerror(errno
));
1151 * If we are a login shell, then we don't want to tell
1152 * about any mail file unless its been modified
1153 * after the time we started.
1154 * This prevents us from telling the user things he already
1155 * knows, since the login program insists on saying
1174 intvl
= (cnt
&& number(*vp
)) ? (--cnt
, getn(*vp
++)) : MAILINTVL
;
1177 if (chktim
+ intvl
> t
)
1180 if (stat(short2str(*vp
), &stb
) < 0)
1182 new = stb
.st_mtime
> time0
.tv_sec
;
1183 if (stb
.st_size
== 0 || stb
.st_atime
> stb
.st_mtime
||
1184 (stb
.st_atime
< chktim
&& stb
.st_mtime
< chktim
) ||
1188 (void)fprintf(cshout
, "You have %smail.\n", new ? "new " : "");
1190 (void)fprintf(cshout
, "%s in %s.\n", new ? "New mail" : "Mail",
1197 * Extract a home directory from the password file
1198 * The argument points to a buffer where the name of the
1199 * user whose home directory is sought is currently.
1200 * We write the home directory of the user back there.
1211 if (*home
== '\0') {
1212 if ((h
= value(STRhome
)) != NULL
) {
1213 (void)Strcpy(home
, h
);
1220 if ((pw
= getpwnam(short2str(home
))) != NULL
) {
1221 (void)Strcpy(home
, str2short(pw
->pw_dir
));
1229 * When didfds is set, we do I/O from 0, 1, 2 otherwise from 15, 16, 17
1230 * We also check if the shell has already changed the descriptor to point to
1231 * 0, 1, 2 when didfds is set.
1233 #define DESC(a) (*((int *) (a)) - (didfds && *((int *) a) >= FSHIN ? FSHIN : 0))
1236 readf(void *oreo
, char *buf
, int siz
)
1238 return read(DESC(oreo
), buf
, siz
);
1243 writef(void *oreo
, const char *buf
, int siz
)
1245 return write(DESC(oreo
), buf
, siz
);
1249 seekf(void *oreo
, fpos_t off
, int whence
)
1251 return lseek(DESC(oreo
), off
, whence
);
1258 return close(DESC(oreo
));
1263 * Print the visible version of a string.
1266 vis_fputc(int ch
, FILE *fp
)
1268 char uenc
[5]; /* 4 + NULL */
1271 return fputc(ch
& TRIM
, fp
);
1273 * XXX: When we are in AsciiOnly we want all characters >= 0200 to
1274 * be encoded, but currently there is no way in vis to do that.
1276 (void)vis(uenc
, ch
& TRIM
, VIS_NOSLASH
, 0);
1277 return (fputs(uenc
, fp
));
1281 * Move the initial descriptors to their eventual
1282 * resting places, closing all other units.
1287 didfds
= 0; /* 0, 1, 2 aren't set up */
1288 (void)ioctl(SHIN
= dcopy(0, FSHIN
), FIOCLEX
, NULL
);
1289 (void)ioctl(SHOUT
= dcopy(1, FSHOUT
), FIOCLEX
, NULL
);
1290 (void)ioctl(SHERR
= dcopy(2, FSHERR
), FIOCLEX
, NULL
);
1291 (void)ioctl(OLDSTD
= dcopy(SHIN
, FOLDSTD
), FIOCLEX
, NULL
);
1308 #ifndef _PATH_DEFPATH
1316 blkp
= blk
= (Char
**)xmalloc((size_t) sizeof(Char
*) * 10);
1318 #define DIRAPPEND(a) \
1319 if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \
1322 DIRAPPEND(RESCUEDIR
);
1324 DIRAPPEND(_PATH_BIN
);
1325 DIRAPPEND(_PATH_USRBIN
);
1330 if (euid
!= 0 && uid
!= 0)
1331 *blkp
++ = Strsave(STRdot
);
1337 #endif /* _PATH_DEFPATH */
1345 for (cp
= value(STRprompt
); *cp
; cp
++)
1347 (void)fprintf(cshout
, "%d", eventno
+ 1);
1349 if (*cp
== '\\' && cp
[1] == HIST
)
1351 (void)vis_fputc(*cp
| QUOTE
, cshout
);
1356 * Prompt for forward reading loop body content.
1358 (void)fprintf(cshout
, "? ");
1359 (void)fflush(cshout
);