2 * tc.func.c: New tcsh builtins.
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "ed.defns.h" /* for the function names */
39 #else /* WINNT_NATIVE */
41 #endif /* WINNT_NATIVE */
45 #include <afs/kautils.h>
46 long ka_UserAuthenticateGeneral();
52 extern time_t t_period
;
53 extern int just_signaled
;
54 static int precmd_active
= 0;
55 static int jobcmd_active
= 0; /* GrP */
56 int postcmd_active
= 0;
57 static int periodic_active
= 0;
58 static int cwdcmd_active
= 0; /* PWP: for cwd_cmd */
59 static int beepcmd_active
= 0;
60 static void (*alm_fun
)(void) = NULL
;
62 static void auto_logout (void);
63 static char *xgetpass (const char *);
64 static void auto_lock (void);
66 static void insert (struct wordent
*, int);
67 static void insert_we (struct wordent
*, struct wordent
*);
68 static int inlist (Char
*, Char
*);
70 static int tildecompare (const void *, const void *);
71 static Char
*gethomedir (const Char
*);
73 static void palarm (int);
74 static void getremotehost (int);
75 #endif /* REMOTEHOST */
82 * expand_lex: Take the given lex and return an expanded version of it.
83 * First guy in lex list is ignored; last guy is ^J which we ignore.
84 * Only take lex'es from position 'from' to position 'to' inclusive
86 * Note: csh sometimes sets bit 8 in characters which causes all kinds
87 * of problems if we don't mask it here. Note: excl's in lexes have been
88 * un-back-slashed and must be re-back-slashed
91 /* PWP: this is a combination of the old sprlex() and the expand_lex from
92 the magic-space stuff */
95 expand_lex(const struct wordent
*sp0
, int from
, int to
)
97 struct Strbuf buf
= Strbuf_INIT
;
98 const struct wordent
*sp
;
105 if (!sp0
|| (sp
= sp0
->next
) == sp0
|| sp
== (sp0
= sp0
->prev
))
106 return Strbuf_finish(&buf
); /* null lex */
109 if ((i
>= from
) && (i
<= to
)) { /* if in range */
110 for (s
= sp
->word
; *s
; s
++) {
112 * bugfix by Michael Bloom: anything but the current history
113 * character {(PWP) and backslash} seem to be dealt with
117 if ((*s
& TRIM
) == HIST
&& HIST
!= '\0')
118 Strbuf_append1(&buf
, '\\');
122 if (prev_c
== '\\') break;
131 Strbuf_append1(&buf
, '\\');
134 if (prev_c
== '\\') break;
136 Strbuf_append1(&buf
, '\\');
140 #if INVALID_BYTE != 0
141 if ((*s
& INVALID_BYTE
) != INVALID_BYTE
) /* *s < INVALID_BYTE */
142 Strbuf_append1(&buf
, *s
& TRIM
);
144 Strbuf_append1(&buf
, *s
);
146 Strbuf_append1(&buf
, *s
& TRIM
);
150 Strbuf_append1(&buf
, ' ');
157 buf
.len
--; /* get rid of trailing space */
159 return Strbuf_finish(&buf
);
163 sprlex(const struct wordent
*sp0
)
165 return expand_lex(sp0
, 0, INT_MAX
);
170 Itoa(int n
, size_t min_digits
, Char attributes
)
173 * The array size here is derived from
175 * which is guaranteed to be enough for a decimal
176 * representation. We add 1 because integer divide
182 Char buf
[CHAR_BIT
* sizeof(int) / 3 + 1], *res
, *p
, *s
;
183 unsigned int un
; /* handle most negative # too */
184 int pad
= (min_digits
!= 0);
186 if (sizeof(buf
) - 1 < min_digits
)
187 min_digits
= sizeof(buf
) - 1;
195 *p
++ = un
% 10 + '0';
197 } while ((pad
&& (ssize_t
)--min_digits
> 0) || un
!= 0);
199 res
= xmalloc((p
- buf
+ 2) * sizeof(*res
));
204 *s
++ = *--p
| attributes
;
213 dolist(Char
**v
, struct command
*c
)
221 struct Strbuf word
= Strbuf_INIT
;
223 Strbuf_terminate(&word
);
224 cleanup_push(&word
, Strbuf_cleanup
);
225 (void) t_search(&word
, LIST
, TW_ZERO
, 0, STRNULL
, 0);
226 cleanup_until(&word
);
229 v
= glob_all_or_error(v
);
231 cleanup_push(globbed
, blk_cleanup
);
232 for (k
= 0; v
[k
] != NULL
&& v
[k
][0] != '-'; k
++)
236 * We cannot process a flag therefore we let ls do it right.
240 struct wordent cmd
, *nextword
, *lastword
;
246 cleanup_push(&pintr_disabled
, disabled_cleanup
);
256 /* Look at listflags, to add -A to the flags, to get a path
257 of ls if necessary */
258 if ((vp
= adrof(STRlistflags
)) != NULL
&& vp
->vec
!= NULL
&&
259 vp
->vec
[0] != STRNULL
) {
260 if (vp
->vec
[1] != NULL
&& vp
->vec
[1][0] != '\0')
262 for (cp
= vp
->vec
[0]; *cp
; cp
++)
280 nextword
= xcalloc(1, sizeof cmd
);
281 nextword
->word
= Strsave(lspath
);
282 lastword
->next
= nextword
;
283 nextword
->prev
= lastword
;
285 nextword
= xcalloc(1, sizeof cmd
);
286 nextword
->word
= Strsave(STRmCF
);
287 lastword
->next
= nextword
;
288 nextword
->prev
= lastword
;
289 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
292 nextword
= xcalloc(1, sizeof cmd
);
293 nextword
->word
= Strsave(STRmmliteral
);
294 lastword
->next
= nextword
;
295 nextword
->prev
= lastword
;
299 if (color_context_ls
) {
301 nextword
= xcalloc(1, sizeof cmd
);
302 nextword
->word
= Strsave(STRmmcolormauto
);
303 lastword
->next
= nextword
;
304 nextword
->prev
= lastword
;
306 #endif /* COLOR_LS_F */
308 for (cp
= *v
; cp
; cp
= *++v
) {
309 nextword
= xcalloc(1, sizeof cmd
);
310 nextword
->word
= quote(Strsave(cp
));
311 lastword
->next
= nextword
;
312 nextword
->prev
= lastword
;
315 lastword
->next
= &cmd
;
317 cleanup_push(&cmd
, lex_cleanup
);
319 /* build a syntax tree for the command. */
320 t
= syntax(cmd
.next
, &cmd
, 0);
321 cleanup_push(t
, syntax_cleanup
);
324 /* expand aliases like process() does */
326 /* execute the parse tree. */
327 execute(t
, tpgrp
> 0 ? tpgrp
: -1, NULL
, NULL
, FALSE
);
328 /* done. free the lex list and parse tree. */
331 cleanup_until(&pintr_disabled
);
335 struct Strbuf buf
= Strbuf_INIT
;
337 cleanup_push(&buf
, Strbuf_cleanup
);
338 for (k
= 0, i
= 0; v
[k
] != NULL
; k
++) {
339 tmp
= dnormalize(v
[k
], symlinks
== SYM_IGNORE
);
340 cleanup_push(tmp
, xfree
);
341 dp
= Strend(tmp
) - 1;
342 if (*dp
== '/' && dp
!= tmp
)
347 if (stat(short2str(tmp
), &st
) == -1) {
354 print_by_column(STRNULL
, &v
[i
], k
- i
, FALSE
);
357 xprintf("%" TCSH_S
": %s.\n", tmp
, strerror(err
));
362 else if (S_ISDIR(st
.st_mode
)) {
368 print_by_column(STRNULL
, &v
[i
], k
- i
, FALSE
);
370 if (k
!= 0 && v
[1] != NULL
)
372 xprintf("%" TCSH_S
":\n", tmp
);
374 for (cp
= tmp
; *cp
; cp
++)
375 Strbuf_append1(&buf
, (*cp
| QUOTE
));
376 Strbuf_terminate(&buf
);
377 dp
= &buf
.s
[buf
.len
- 1];
380 (*dp
!= (Char
) (':' | QUOTE
)) &&
381 #endif /* WINNT_NATIVE */
382 (*dp
!= (Char
) ('/' | QUOTE
))) {
383 Strbuf_append1(&buf
, '/');
384 Strbuf_terminate(&buf
);
387 (void) t_search(&buf
, LIST
, TW_ZERO
, 0, STRNULL
, 0);
396 print_by_column(STRNULL
, &v
[i
], k
- i
, FALSE
);
399 stderror(ERR_SILENT
);
402 cleanup_until(globbed
);
405 extern int GotTermCaps
;
409 dotelltc(Char
**v
, struct command
*c
)
420 doechotc(Char
**v
, struct command
*c
)
430 dosettc(Char
**v
, struct command
*c
)
438 tv
[0] = strsave(short2str(v
[1]));
439 cleanup_push(tv
[0], xfree
);
440 tv
[1] = strsave(short2str(v
[2]));
441 cleanup_push(tv
[1], xfree
);
443 cleanup_until(tv
[0]);
446 /* The dowhich() is by:
447 * Andreas Luik <luik@isaak.isa.de>
448 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
455 cmd_expand(Char
*cmd
, Char
**str
)
457 struct wordent lexp
[3];
461 lexp
[0].next
= &lexp
[1];
462 lexp
[1].next
= &lexp
[2];
463 lexp
[2].next
= &lexp
[0];
465 lexp
[0].prev
= &lexp
[2];
466 lexp
[1].prev
= &lexp
[0];
467 lexp
[2].prev
= &lexp
[1];
469 lexp
[0].word
= STRNULL
;
470 lexp
[2].word
= STRret
;
472 if ((vp
= adrof1(cmd
, &aliases
)) != NULL
&& vp
->vec
!= NULL
) {
474 xprintf(CGETS(22, 1, "%" TCSH_S
": \t aliased to "), cmd
);
479 *str
= blkexpand(vp
->vec
);
483 rv
= tellmewhat(lexp
, str
);
491 dowhich(Char
**v
, struct command
*c
)
497 * We don't want to glob dowhich args because we lose quoteing
498 * E.g. which \ls if ls is aliased will not work correctly if
503 rv
&= cmd_expand(*v
, NULL
);
510 findvv(Char
**vv
, const char *cp
)
512 for (; vv
&& *vv
; vv
++) {
514 for (i
= 0; (*vv
)[i
] && (*vv
)[i
] == cp
[i
]; i
++)
516 if ((*vv
)[i
] == '\0' && cp
[i
] == '\0')
522 /* PWP: a hack to start up your stopped editor on a single keystroke */
523 /* jbs - fixed hack so it worked :-) 3/28/89 */
528 struct process
*pp
, *retp
;
529 const char *ep
= NULL
, *vp
= NULL
;
531 size_t epl
= 0, vpl
= 0;
536 if (pcurrent
== NULL
) /* see if we have any jobs */
537 return NULL
; /* nope */
539 if ((varp
= adrof(STReditors
)) != NULL
)
545 if ((ep
= getenv("EDITOR")) != NULL
) { /* if we have a value */
546 if ((p
= strrchr(ep
, '/')) != NULL
) /* if it has a path */
547 ep
= p
+ 1; /* then we want only the last part */
552 if ((vp
= getenv("VISUAL")) != NULL
) { /* if we have a value */
553 if ((p
= strrchr(vp
, '/')) != NULL
) /* and it has a path */
554 vp
= p
+ 1; /* then we want only the last part */
559 for (vpl
= 0; vp
[vpl
] && !isspace((unsigned char)vp
[vpl
]); vpl
++)
561 for (epl
= 0; ep
[epl
] && !isspace((unsigned char)ep
[epl
]); epl
++)
566 for (pp
= proclist
.p_next
; pp
; pp
= pp
->p_next
)
567 if (pp
->p_procid
== pp
->p_jobid
) {
570 * Only foreground an edit session if it is suspended. Some GUI
571 * editors have may be happily running in a separate window, no
572 * point in foregrounding these if they're already running - webb
574 pstatus
= (int) (pp
->p_flags
& PALLSTATES
);
575 if (pstatus
!= PINTERRUPTED
&& pstatus
!= PSTOPPED
&&
576 pstatus
!= PSIGNALED
)
579 p
= short2str(pp
->p_command
);
580 /* get the first word */
581 for (cp
= p
; *cp
&& !isspace((unsigned char) *cp
); cp
++)
585 if ((cp
= strrchr(p
, '/')) != NULL
) /* and it has a path */
586 cp
= cp
+ 1; /* then we want only the last part */
588 cp
= p
; /* else we get all of it */
591 * If we find the current name in the $editors array (if set)
592 * or as $EDITOR or $VISUAL (if $editors not set), fg it.
594 if ((vv
&& findvv(vv
, cp
)) ||
595 (epl
&& strncmp(ep
, cp
, epl
) == 0 && cp
[epl
] == '\0') ||
596 (vpl
&& strncmp(vp
, cp
, vpl
) == 0 && cp
[vpl
] == '\0')) {
598 * If there is a choice, then choose the current process if
599 * available, or the previous process otherwise, or else
600 * anything will do - Robert Webb (robertw@mulga.cs.mu.oz.au).
604 else if (retp
== NULL
|| pp
== pprevious
)
609 return retp
; /* Will be NULL if we didn't find a job */
613 fg_proc_entry(struct process
*pp
)
623 oGettingInput
= GettingInput
;
626 ohaderr
= haderr
; /* we need to ignore setting of haderr due to
627 * process getting stopped by a signal */
628 omark
= cleanup_push_mark();
629 if (setexit() == 0) { /* come back here after pjwait */
631 (void) alarm(0); /* No autologout */
632 alrmcatch_disabled
= 1;
633 if (!pstart(pp
, 1)) {
635 stderror(ERR_BADJOB
, pp
->p_command
, strerror(errno
));
639 setalarm(1); /* Autologout back on */
640 cleanup_pop_mark(omark
);
643 GettingInput
= oGettingInput
;
645 disabled_cleanup(&pintr_disabled
);
649 xgetpass(const char *prm
)
651 static struct strbuf pass
; /* = strbuf_INIT; */
654 struct sigaction sa
, osa
;
656 sa
.sa_handler
= SIG_IGN
;
657 sigemptyset(&sa
.sa_mask
);
659 (void)sigaction(SIGINT
, &sa
, &osa
);
662 sigaddset(&set
, SIGINT
);
663 (void)sigprocmask(SIG_UNBLOCK
, &set
, &oset
);
665 cleanup_push(&osa
, sigint_cleanup
);
666 cleanup_push(&oset
, sigprocmask_cleanup
);
667 (void) Rawmode(); /* Make sure, cause we want echo off */
668 fd
= xopen("/dev/tty", O_RDWR
|O_LARGEFILE
);
672 cleanup_push(&fd
, open_cleanup
);
674 xprintf("%s", prm
); flush();
679 if (xread(fd
, &c
, 1) < 1 || c
== '\n')
681 strbuf_append1(&pass
, c
);
683 strbuf_terminate(&pass
);
692 extern char *crypt ();
700 * Ask the user for his login password to continue working
701 * On systems that have a shadow password, this will only
702 * work for root, but what can we do?
704 * If we fail to get the password, then we log the user out
719 #if defined(HAVE_AUTH_H) && defined(HAVE_GETAUTHUID)
721 struct authorization
*apw
;
722 extern char *crypt16 (const char *, const char *);
724 # define XCRYPT(pw, a, b) crypt16(a, b)
726 if ((pw
= xgetpwuid(euid
)) != NULL
&& /* effective user passwd */
727 (apw
= getauthuid(euid
)) != NULL
) /* enhanced ultrix passwd */
728 srpp
= apw
->a_password
;
730 #elif defined(HAVE_SHADOW_H)
734 # define XCRYPT(pw, a, b) crypt(a, b)
736 if ((pw
= xgetpwuid(euid
)) != NULL
) { /* effective user passwd */
738 while ((spw
= getspnam(pw
->pw_name
)) == NULL
&& errno
== EINTR
) {
739 handle_pending_signals();
742 if (spw
!= NULL
) /* shadowed passwd */
750 # define XCRYPT(pw, a, b) cygwin_xcrypt(pw, a, b)
752 # define XCRYPT(pw, a, b) crypt(a, b)
755 #if !defined(__MVS__)
756 if ((pw
= xgetpwuid(euid
)) != NULL
) /* effective user passwd */
757 srpp
= pw
->pw_passwd
;
768 setalarm(0); /* Not for locking any more */
770 for (i
= 0; i
< 5; i
++) {
777 if ((safs
= varval(STRafsuser
)) != STRNULL
)
778 afsname
= short2str(safs
);
780 if ((afsname
= getenv("AFSUSER")) == NULL
)
781 afsname
= pw
->pw_name
;
783 pp
= xgetpass("Password:");
785 crpp
= XCRYPT(pw
, pp
, srpp
);
786 if ((crpp
&& strcmp(crpp
, srpp
) == 0)
788 || (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
,
799 (void) memset(pp
, 0, strlen(pp
));
800 if (GettingInput
&& !just_signaled
) {
809 xprintf(CGETS(22, 2, "\nIncorrect passwd for %s\n"), pw
->pw_name
);
811 #endif /* NO_CRYPT */
819 xprintf("auto-logout\n");
820 /* Don't leave the tty in raw mode */
824 setcopy(STRlogout
, STRautomatic
, VAR_READWRITE
);
829 GettingInput
= FALSE
; /* make flush() work to write hist files. Huber*/
841 * Karl Kleinpaste, 21oct1983.
842 * Added precmd(), which checks for the alias
843 * precmd in aliases. If it's there, the alias
844 * is executed as a command. This is done
845 * after mailchk() and just before print-
846 * ing the prompt. Useful for things like printing
847 * one's current directory just before each command.
853 cleanup_push(&pintr_disabled
, disabled_cleanup
);
854 if (precmd_active
) { /* an error must have been caught */
855 aliasrun(2, STRunalias
, STRprecmd
);
856 xprintf("%s", CGETS(22, 3, "Faulty alias 'precmd' removed.\n"));
860 if (!whyles
&& adrof1(STRprecmd
, &aliases
))
861 aliasrun(1, STRprecmd
, NULL
);
864 cleanup_until(&pintr_disabled
);
871 cleanup_push(&pintr_disabled
, disabled_cleanup
);
872 if (postcmd_active
) { /* an error must have been caught */
873 aliasrun(2, STRunalias
, STRpostcmd
);
874 xprintf("%s", CGETS(22, 3, "Faulty alias 'postcmd' removed.\n"));
878 if (!whyles
&& adrof1(STRpostcmd
, &aliases
))
879 aliasrun(1, STRpostcmd
, NULL
);
882 cleanup_until(&pintr_disabled
);
886 * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into
887 * submission... Run every time $cwd is set (after it is set). Useful
888 * for putting your machine and cwd (or anything else) in an xterm title
895 cleanup_push(&pintr_disabled
, disabled_cleanup
);
896 if (cwdcmd_active
) { /* an error must have been caught */
897 aliasrun(2, STRunalias
, STRcwdcmd
);
898 xprintf("%s", CGETS(22, 4, "Faulty alias 'cwdcmd' removed.\n"));
902 if (!whyles
&& adrof1(STRcwdcmd
, &aliases
))
903 aliasrun(1, STRcwdcmd
, NULL
);
906 cleanup_until(&pintr_disabled
);
910 * Joachim Hoenig 07/16/91 Added beep_cmd, run every time tcsh wishes
911 * to beep the terminal bell. Useful for playing nice sounds instead.
917 cleanup_push(&pintr_disabled
, disabled_cleanup
);
918 if (beepcmd_active
) { /* an error must have been caught */
919 aliasrun(2, STRunalias
, STRbeepcmd
);
920 xprintf("%s", CGETS(22, 5, "Faulty alias 'beepcmd' removed.\n"));
924 if (!whyles
&& adrof1(STRbeepcmd
, &aliases
))
925 aliasrun(1, STRbeepcmd
, NULL
);
928 cleanup_until(&pintr_disabled
);
933 * Karl Kleinpaste, 18 Jan 1984.
934 * Added period_cmd(), which executes the alias "periodic" every
935 * $tperiod minutes. Useful for occasional checking of msgs and such.
946 cleanup_push(&pintr_disabled
, disabled_cleanup
);
947 if (periodic_active
) { /* an error must have been caught */
948 aliasrun(2, STRunalias
, STRperiodic
);
949 xprintf("%s", CGETS(22, 6, "Faulty alias 'periodic' removed.\n"));
953 if (!whyles
&& adrof1(STRperiodic
, &aliases
)) {
954 vp
= varval(STRtperiod
);
956 aliasrun(1, STRperiodic
, NULL
);
961 if (t
- t_period
>= interval
* 60) {
963 aliasrun(1, STRperiodic
, NULL
);
968 cleanup_until(&pintr_disabled
);
973 * GrP Greg Parker May 2001
974 * Added job_cmd(), which is run every time a job is started or
975 * foregrounded. The command is passed a single argument, the string
976 * used to start the job originally. With precmd, useful for setting
978 * Cloned from cwd_cmd().
986 cleanup_push(&pintr_disabled
, disabled_cleanup
);
987 if (jobcmd_active
) { /* an error must have been caught */
988 aliasrun(2, STRunalias
, STRjobcmd
);
989 xprintf("%s", CGETS(22, 14, "Faulty alias 'jobcmd' removed.\n"));
993 if (!whyles
&& adrof1(STRjobcmd
, &aliases
)) {
994 struct process
*pp
= pcurrjob
; /* put things back after the hook */
995 aliasrun(2, STRjobcmd
, args
);
1000 cleanup_until(&pintr_disabled
);
1005 * Karl Kleinpaste, 21oct1983.
1006 * Set up a one-word alias command, for use for special things.
1007 * This code is based on the mainline of process().
1010 aliasrun(int cnt
, Char
*s1
, Char
*s2
)
1012 struct wordent w
, *new1
, *new2
; /* for holding alias name */
1013 struct command
*t
= NULL
;
1022 seterr
= NULL
; /* don't repeatedly print err msg. */
1025 new1
= xcalloc(1, sizeof w
);
1026 new1
->word
= Strsave(s1
);
1028 /* build a lex list with one word. */
1029 w
.next
= w
.prev
= new1
;
1030 new1
->next
= new1
->prev
= &w
;
1033 /* build a lex list with two words. */
1034 new2
= xcalloc(1, sizeof w
);
1035 new2
->word
= Strsave(s2
);
1036 w
.next
= new2
->prev
= new1
;
1037 new1
->next
= w
.prev
= new2
;
1038 new1
->prev
= new2
->next
= &w
;
1040 cleanup_push(&w
, lex_cleanup
);
1042 /* Save the old status */
1043 status
= getstatus();
1045 /* expand aliases like process() does. */
1047 /* build a syntax tree for the command. */
1048 t
= syntax(w
.next
, &w
, 0);
1049 cleanup_push(t
, syntax_cleanup
);
1054 cleanup_push(&cnt
, psavejob_cleanup
); /* cnt is used only as a marker */
1056 /* catch any errors here */
1057 omark
= cleanup_push_mark();
1059 /* execute the parse tree. */
1061 * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
1062 * was execute(t, tpgrp);
1064 execute(t
, tpgrp
> 0 ? tpgrp
: -1, NULL
, NULL
, TRUE
);
1065 /* reset the error catcher to the old place */
1066 cleanup_pop_mark(omark
);
1071 * Either precmd, or cwdcmd, or periodic had an error. Call it again so
1072 * that it is removed
1080 * XXX: On the other hand, just interrupting them causes an error too.
1081 * So if we hit ^C in the middle of cwdcmd or periodic the alias gets
1082 * removed. We don't want that. Note that we want to remove precmd
1083 * though, cause that could lead into an infinite loop. This should be
1084 * fixed correctly, but then haderr should give us the whole exit
1085 * status not just true or false.
1087 else if (cwdcmd_active
)
1089 else if (beepcmd_active
)
1091 else if (periodic_active
)
1098 /* Restore status */
1099 setstrstatus(putn((tcsh_number_t
)status
));
1107 unsigned alrm_time
= 0, logout_time
, lock_time
;
1108 time_t cl
, nl
, sched_dif
;
1110 if ((vp
= adrof(STRautologout
)) != NULL
&& vp
->vec
!= NULL
) {
1111 if ((cp
= vp
->vec
[0]) != 0) {
1112 if ((logout_time
= (unsigned) atoi(short2str(cp
)) * 60) > 0) {
1115 * Solaris alarm(2) uses a timer based in clock ticks
1116 * internally so it multiplies our value with CLK_TCK...
1117 * Of course that can overflow leading to unexpected
1118 * results, so we clip it here. Grr. Where is that
1121 if (logout_time
>= 0x7fffffff / CLK_TCK
)
1122 logout_time
= 0x7fffffff / CLK_TCK
;
1123 #endif /* SOLARIS2 */
1124 alrm_time
= logout_time
;
1125 alm_fun
= auto_logout
;
1128 if ((cp
= vp
->vec
[1]) != 0) {
1129 if ((lock_time
= (unsigned) atoi(short2str(cp
)) * 60) > 0) {
1131 if (alrm_time
== 0 || lock_time
< alrm_time
) {
1132 alrm_time
= lock_time
;
1133 alm_fun
= auto_lock
;
1136 else /* lock_time always < alrm_time */
1138 alrm_time
-= lock_time
;
1142 if ((nl
= sched_next()) != -1) {
1144 sched_dif
= nl
> cl
? nl
- cl
: 0;
1145 if ((alrm_time
== 0) || ((unsigned) sched_dif
< alrm_time
)) {
1146 alrm_time
= ((unsigned) sched_dif
) + 1;
1147 alm_fun
= sched_run
;
1150 alrmcatch_disabled
= 0;
1151 (void) alarm(alrm_time
); /* Autologout ON */
1154 #undef RMDEBUG /* For now... */
1157 rmstar(struct wordent
*cp
)
1159 struct wordent
*we
, *args
;
1160 struct wordent
*tmp
, *del
;
1163 static Char STRrmdebug
[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'};
1165 #endif /* RMDEBUG */
1167 int ask
, doit
, star
= 0, silent
= 0, opintr_disabled
;
1169 if (!adrof(STRrmstar
))
1172 tag
= varval(STRrmdebug
);
1173 #endif /* RMDEBUG */
1175 while (*we
->word
== ';' && we
!= cp
)
1177 opintr_disabled
= pintr_disabled
;
1180 Char
*cmd
= we
->word
;
1181 if (cmd
[0] == STRQNULL
[0])
1185 xprintf(CGETS(22, 7, "parsing command line [%" TCSH_S
"]\n"), cmd
);
1186 #endif /* RMDEBUG */
1187 if (!StrQcmp(cmd
, STRrm
)) {
1189 ask
= (*args
->word
!= '-');
1190 while (*args
->word
== '-' && !silent
) { /* check options */
1191 for (charac
= (args
->word
+ 1); *charac
&& !silent
; charac
++)
1192 silent
= (*charac
== 'i' || *charac
== 'f');
1195 ask
= (ask
|| (!ask
&& !silent
));
1197 for (; !star
&& *args
->word
!= ';'
1198 && args
!= cp
; args
= args
->next
)
1199 if (!Strcmp(args
->word
, STRstar
))
1202 doit
= getYN(CGETS(22, 8,
1203 "Do you really want to delete all files? [N/y] "));
1205 /* remove the command instead */
1208 xprintf(CGETS(22, 9,
1209 "skipping deletion of files!\n"));
1210 #endif /* RMDEBUG */
1212 *tmp
->word
!= '\n' &&
1213 *tmp
->word
!= ';' && tmp
!= cp
;) {
1214 tmp
->prev
->next
= tmp
->next
;
1215 tmp
->next
->prev
= tmp
->prev
;
1221 if (*tmp
->word
== ';') {
1222 tmp
->prev
->next
= tmp
->next
;
1223 tmp
->next
->prev
= tmp
->prev
;
1236 *we
->word
!= ';' && we
!= cp
;
1239 if (*we
->word
== ';')
1244 xprintf(CGETS(22, 10, "command line now is:\n"));
1245 for (we
= cp
->next
; we
!= cp
; we
= we
->next
)
1246 xprintf("[%" TCSH_S
"] ", we
->word
);
1248 #endif /* RMDEBUG */
1249 pintr_disabled
= opintr_disabled
;
1254 /* Check if command is in continue list
1255 and do a "aliasing" if it exists as a job in background */
1257 #undef CNDEBUG /* For now */
1259 continue_jobs(struct wordent
*cp
)
1262 struct process
*pp
, *np
;
1263 Char
*cmd
, *continue_list
, *continue_args_list
;
1267 static Char STRcndebug
[] =
1268 {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'};
1269 #endif /* CNDEBUG */
1270 int in_cont_list
, in_cont_arg_list
;
1274 tag
= varval(STRcndebug
);
1275 #endif /* CNDEBUG */
1276 continue_list
= varval(STRcontinue
);
1277 continue_args_list
= varval(STRcontinue_args
);
1278 if (*continue_list
== '\0' && *continue_args_list
== '\0')
1282 while (*we
->word
== ';' && we
!= cp
)
1287 xprintf(CGETS(22, 11, "parsing command line\n"));
1288 #endif /* CNDEBUG */
1290 in_cont_list
= inlist(continue_list
, cmd
);
1291 in_cont_arg_list
= inlist(continue_args_list
, cmd
);
1292 if (in_cont_list
|| in_cont_arg_list
) {
1295 xprintf(CGETS(22, 12, "in one of the lists\n"));
1296 #endif /* CNDEBUG */
1298 for (pp
= proclist
.p_next
; pp
; pp
= pp
->p_next
) {
1299 if (prefix(cmd
, pp
->p_command
)) {
1307 insert(we
, in_cont_arg_list
);
1311 *we
->word
!= ';' && we
!= cp
;
1314 if (*we
->word
== ';')
1319 xprintf(CGETS(22, 13, "command line now is:\n"));
1320 for (we
= cp
->next
; we
!= cp
; we
= we
->next
)
1321 xprintf("%" TCSH_S
" ", we
->word
);
1323 #endif /* CNDEBUG */
1327 /* The actual "aliasing" of for backgrounds() is done here
1328 with the aid of insert_we(). */
1330 insert(struct wordent
*pl
, int file_args
)
1332 struct wordent
*now
, *last
;
1333 Char
*cmd
, *bcmd
, *cp1
, *cp2
;
1335 Char
*upause
= STRunderpause
;
1336 size_t p_len
= Strlen(upause
);
1338 cmd_len
= Strlen(pl
->word
);
1339 cmd
= xcalloc(1, (cmd_len
+ 1) * sizeof(Char
));
1340 (void) Strcpy(cmd
, pl
->word
);
1341 /* Do insertions at beginning, first replace command word */
1346 now
->word
= xcalloc(1, 5 * sizeof(Char
));
1347 (void) Strcpy(now
->word
, STRecho
);
1349 now
= xcalloc(1, sizeof(struct wordent
));
1350 now
->word
= xcalloc(1, 6 * sizeof(Char
));
1351 (void) Strcpy(now
->word
, STRbackqpwd
);
1354 for (last
= now
; *last
->word
!= '\n' && *last
->word
!= ';';
1358 now
= xcalloc(1, sizeof(struct wordent
));
1359 now
->word
= xcalloc(1, 2 * sizeof(Char
));
1360 (void) Strcpy(now
->word
, STRgt
);
1361 insert_we(now
, last
->prev
);
1363 now
= xcalloc(1, sizeof(struct wordent
));
1364 now
->word
= xcalloc(1, 2 * sizeof(Char
));
1365 (void) Strcpy(now
->word
, STRbang
);
1366 insert_we(now
, last
->prev
);
1368 now
= xcalloc(1, sizeof(struct wordent
));
1369 now
->word
= xcalloc(1, (cmd_len
+ p_len
+ 4) * sizeof(Char
));
1375 while ((*cp1
++ = *cp2
++) != '\0')
1379 while ((*cp1
++ = *cp2
++) != '\0')
1381 insert_we(now
, last
->prev
);
1383 now
= xcalloc(1, sizeof(struct wordent
));
1384 now
->word
= xcalloc(1, 2 * sizeof(Char
));
1385 (void) Strcpy(now
->word
, STRsemi
);
1386 insert_we(now
, last
->prev
);
1387 bcmd
= xcalloc(1, (cmd_len
+ 2) * sizeof(Char
));
1389 Strcpy(bcmd
+ 1, cmd
);
1390 now
= xcalloc(1, sizeof(struct wordent
));
1392 insert_we(now
, last
->prev
);
1395 struct wordent
*del
;
1399 now
->word
= xcalloc(1, (cmd_len
+ 2) * sizeof(Char
));
1401 Strcpy(now
->word
+ 1, cmd
);
1402 for (now
= now
->next
;
1403 *now
->word
!= '\n' && *now
->word
!= ';' && now
!= pl
;) {
1404 now
->prev
->next
= now
->next
;
1405 now
->next
->prev
= now
->prev
;
1415 insert_we(struct wordent
*new, struct wordent
*where
)
1419 new->next
= where
->next
;
1421 new->next
->prev
= new;
1425 inlist(Char
*list
, Char
*name
)
1436 if (*n
== '\0' && (*l
== ' ' || *l
== '\0'))
1442 while (*l
&& *l
!= ' ')
1443 l
++; /* skip to blank */
1444 while (*l
&& *l
== ' ')
1445 l
++; /* and find first nonblank character */
1452 #endif /* BSDJOBS */
1456 * Implement a small cache for tilde names. This is used primarily
1457 * to expand tilde names to directories, but also
1458 * we can find users from their home directories for the tilde
1459 * prompt, on machines where yp lookup is slow this can be a big win...
1460 * As with any cache this can run out of sync, rehash can sync it again.
1462 static struct tildecache
{
1470 static size_t tsize
= TILINCR
;
1473 tildecompare(const void *xp1
, const void *xp2
)
1475 const struct tildecache
*p1
, *p2
;
1479 return Strcmp(p1
->user
, p2
->user
);
1483 gethomedir(const Char
*us
)
1487 char **res
, **res1
, *cp
;
1491 pp
= xgetpwnam(short2str(us
));
1497 /* Don't return if root */
1498 if (pp
->pw_dir
[0] == '/' && pp
->pw_dir
[1] == '\0')
1502 return Strsave(str2short(pp
->pw_dir
));
1505 res
= hes_resolve(short2str(us
), "filsys");
1508 if ((*res
) != NULL
) {
1510 * Look at the first token to determine how to interpret
1512 * Yes, strtok is evil (it's not thread-safe), but it's also
1515 cp
= strtok(*res
, " ");
1516 if (strcmp(cp
, "AFS") == 0) {
1517 /* next token is AFS pathname.. */
1518 cp
= strtok(NULL
, " ");
1520 rp
= Strsave(str2short(cp
));
1521 } else if (strcmp(cp
, "NFS") == 0) {
1523 if ((strtok(NULL
, " ")) && /* skip remote pathname */
1524 (strtok(NULL
, " ")) && /* skip host */
1525 (strtok(NULL
, " ")) && /* skip mode */
1526 (cp
= strtok(NULL
, " "))) {
1527 rp
= Strsave(str2short(cp
));
1531 for (res1
= res
; *res1
; res1
++)
1534 /* Don't return if root */
1535 if (rp
!= NULL
&& rp
[0] == '/' && rp
[1] == '\0') {
1547 gettilde(const Char
*us
)
1549 struct tildecache
*bp1
, *bp2
, *bp
;
1552 /* Ignore NIS special names */
1553 if (*us
== '+' || *us
== '-')
1557 tcache
= xmalloc(TILINCR
* sizeof(struct tildecache
));
1561 for (bp1
= tcache
, bp2
= tcache
+ tlength
; bp1
< bp2
;) {
1564 bp
= bp1
+ ((bp2
- bp1
) >> 1);
1565 if ((i
= *us
- *bp
->user
) == 0 && (i
= Strcmp(us
, bp
->user
)) == 0)
1573 * Not in the cache, try to get it from the passwd file
1575 hd
= gethomedir(us
);
1582 tcache
[tlength
].user
= Strsave(us
);
1583 tcache
[tlength
].home
= hd
;
1584 tcache
[tlength
++].hlen
= Strlen(hd
);
1586 qsort(tcache
, tlength
, sizeof(struct tildecache
), tildecompare
);
1588 if (tlength
== tsize
) {
1590 tcache
= xrealloc(tcache
, tsize
* sizeof(struct tildecache
));
1596 * Return the username if the directory path passed contains a
1597 * user's home directory in the tilde cache, otherwise return NULL
1598 * hm points to the place where the path became different.
1599 * Special case: Our own home directory.
1600 * If we are passed a null pointer, then we flush the cache.
1603 getusername(Char
**hm
)
1609 for (i
= 0; i
< tlength
; i
++) {
1610 xfree(tcache
[i
].home
);
1611 xfree(tcache
[i
].user
);
1620 if (((h
= varval(STRhome
)) != STRNULL
) &&
1621 (Strncmp(p
, h
, j
= Strlen(h
)) == 0) &&
1622 (p
[j
] == '/' || p
[j
] == '\0')) {
1626 for (i
= 0; i
< tlength
; i
++)
1627 if ((Strncmp(p
, tcache
[i
].home
, (j
= tcache
[i
].hlen
)) == 0) &&
1628 (p
[j
] == '/' || p
[j
] == '\0')) {
1630 return tcache
[i
].user
;
1637 * set the shell-level var to 1 or apply change to it.
1644 if ((cp
= getenv("SHLVL")) != NULL
) {
1652 if (adrof(STRshlvl
) != NULL
)
1654 Unsetenv(STRKSHLVL
);
1659 p
= Itoa(val
, 0, 0);
1660 cleanup_push(p
, xfree
);
1661 setv(STRshlvl
, p
, VAR_READWRITE
);
1664 tsetenv(STRKSHLVL
, p
);
1668 setcopy(STRshlvl
, STR1
, VAR_READWRITE
);
1669 tsetenv(STRKSHLVL
, STR1
);
1675 * Try to recover from a read error
1678 fixio(int fd
, int e
)
1681 case -1: /* Make sure that the code is reachable */
1686 #endif /* EWOULDBLOCK */
1688 #if defined(POSIX) && defined(EAGAIN)
1689 # if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN
1692 # endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */
1693 #endif /* POSIX && EAGAIN */
1699 * Great! we have on suns 3 flavors and 5 names...
1700 * I hope that will cover everything.
1701 * I added some more defines... many systems have different defines.
1702 * Rather than dealing with getting the right includes, we'll just
1703 * cover all the known possibilities here. -- sterling@netcom.com
1706 # define O_NONBLOCK 0
1707 # endif /* O_NONBLOCK */
1710 # endif /* O_NDELAY */
1716 # endif /* _FNBIO */
1719 # endif /* FNONBIO */
1721 # define FNONBLOCK 0
1722 # endif /* FNONBLOCK */
1724 # define _FNONBLOCK 0
1725 # endif /* _FNONBLOCK */
1728 # endif /* FNDELAY */
1731 # endif /* _FNDELAY */
1732 # ifndef FNDLEAY /* Some linux versions have this typo */
1734 # endif /* FNDLEAY */
1735 if ((e
= fcntl(fd
, F_GETFL
, 0)) == -1)
1738 e
&= ~(O_NDELAY
|O_NONBLOCK
|FNBIO
|_FNBIO
|FNONBIO
|FNONBLOCK
|_FNONBLOCK
|
1739 FNDELAY
|_FNDELAY
|FNDLEAY
); /* whew! */
1740 if (fcntl(fd
, F_SETFL
, e
) == -1)
1744 # endif /* F_SETFL */
1748 if (ioctl(fd
, FIONBIO
, (ioctl_t
) &e
) == -1)
1750 # endif /* FIONBIO */
1752 #endif /* FDRETRY */
1767 collate(const Char
*a
, const Char
*b
)
1770 #ifdef SHORT_STRINGS
1771 /* This strips the quote bit as a side effect */
1772 char *sa
= strsave(short2str(a
));
1773 char *sb
= strsave(short2str(b
));
1775 char *sa
= strip(strsave(a
));
1776 char *sb
= strip(strsave(b
));
1777 #endif /* SHORT_STRINGS */
1779 #if defined(NLS) && defined(HAVE_STRCOLL)
1780 errno
= 0; /* strcoll sets errno, another brain-damage */
1782 rv
= strcoll(sa
, sb
);
1785 * We should be checking for errno != 0, but some systems
1786 * forget to reset errno to 0. So we only check for the
1787 * only documented valid errno value for strcoll [EINVAL]
1789 if (errno
== EINVAL
) {
1792 stderror(ERR_SYSTEM
, "strcoll", strerror(errno
));
1795 rv
= strcmp(sa
, sb
);
1796 #endif /* NLS && HAVE_STRCOLL */
1806 * From: peter@zeus.dialix.oz.au (Peter Wemm)
1807 * If exec() fails look first for a #! [word] [word] ....
1808 * If it is, splice the header into the argument list and retry.
1810 #define HACKBUFSZ 1024 /* Max chars in #! vector */
1812 hashbang(int fd
, Char
***vp
)
1814 struct blk_buf sarg
= BLK_BUF_INIT
;
1815 char lbuf
[HACKBUFSZ
], *p
, *ws
;
1817 int fw
= 0; /* found at least one word */
1820 #endif /* WINNT_NATIVE */
1822 if (xread(fd
, lbuf
, HACKBUFSZ
) <= 0)
1825 ws
= 0; /* word started = 0 */
1827 for (p
= lbuf
; p
< &lbuf
[HACKBUFSZ
]; ) {
1831 #if defined(WINNT_NATIVE) || defined (__CYGWIN__)
1833 #endif /* WINNT_NATIVE || __CYGWIN__ */
1834 if (ws
) { /* a blank after a word.. save it */
1838 real
= hb_subst(ws
);
1844 #endif /* WINNT_NATIVE */
1845 bb_append(&sarg
, SAVE(ws
));
1851 case '\0': /* Whoa!! what the hell happened */
1854 case '\n': /* The end of the line. */
1858 #endif /* WINNT_NATIVE */
1859 ws
) { /* terminate the last word */
1862 /* deal with the 1-word case */
1864 real
= hb_subst(ws
);
1868 #endif /* !WINNT_NATIVE */
1870 bb_append(&sarg
, SAVE(ws
));
1873 *vp
= bb_finish(&sarg
);
1880 if (!ws
) /* Start a new word? */
1890 #endif /* HASHBANG */
1902 getremotehost(int dest_fd
)
1904 const char *host
= NULL
;
1906 struct sockaddr_storage saddr
;
1907 static char hbuf
[NI_MAXHOST
];
1910 struct sockaddr_in saddr
;
1912 socklen_t len
= sizeof(saddr
);
1915 if (getpeername(SHIN
, (struct sockaddr
*) &saddr
, &len
) != -1 &&
1916 (saddr
.ss_family
== AF_INET6
|| saddr
.ss_family
== AF_INET
)) {
1917 int flag
= NI_NUMERICHOST
;
1919 #ifdef NI_WITHSCOPEID
1920 flag
|= NI_WITHSCOPEID
;
1922 getnameinfo((struct sockaddr
*)&saddr
, len
, hbuf
, sizeof(hbuf
),
1926 if (getpeername(SHIN
, (struct sockaddr
*) &saddr
, &len
) != -1 &&
1927 saddr
.sin_family
== AF_INET
) {
1929 if ((hp
= gethostbyaddr((char *)&saddr
.sin_addr
, sizeof(struct in_addr
),
1934 host
= inet_ntoa(saddr
.sin_addr
);
1937 #ifdef HAVE_STRUCT_UTMP_UT_HOST
1940 char *name
= utmphost();
1941 /* Avoid empty names and local X displays */
1942 if (name
!= NULL
&& *name
!= '\0' && *name
!= ':') {
1943 struct in_addr addr
;
1946 /* Look for host:display.screen */
1948 * There is conflict with IPv6 address and X DISPLAY. So,
1949 * we assume there is no IPv6 address in utmp and don't
1952 if ((sptr
= strchr(name
, ':')) != NULL
)
1954 /* Leave IPv4 address as is */
1956 * we use inet_addr here, not inet_aton because many systems
1957 * have not caught up yet.
1959 addr
.s_addr
= inet_addr(name
);
1960 if (addr
.s_addr
!= (unsigned int)~0)
1966 char dbuf
[MAXHOSTNAMELEN
];
1967 struct addrinfo hints
, *res
= NULL
;
1969 memset(&hints
, 0, sizeof(hints
));
1970 hints
.ai_family
= PF_UNSPEC
;
1971 hints
.ai_socktype
= SOCK_STREAM
;
1972 hints
.ai_flags
= AI_PASSIVE
| AI_CANONNAME
;
1973 if (strlen(name
) < utmphostsize())
1975 if (getaddrinfo(name
, NULL
, &hints
, &res
) != 0)
1977 } else if (gethostname(dbuf
, sizeof(dbuf
)) == 0 &&
1978 (dbuf
[sizeof(dbuf
)-1] = '\0', /*FIXME: ugly*/
1979 (domain
= strchr(dbuf
, '.')) != NULL
)) {
1980 for (s
= strchr(name
, '.');
1981 s
!= NULL
; s
= strchr(s
+ 1, '.')) {
1982 if (*(s
+ 1) != '\0' &&
1983 (ptr
= strstr(domain
, s
)) != NULL
) {
1986 cbuf
= strspl(name
, ptr
+ strlen(s
));
1987 if (getaddrinfo(cbuf
, NULL
, &hints
, &res
) != 0)
1995 if (res
->ai_canonname
!= NULL
) {
1996 strncpy(hbuf
, res
->ai_canonname
, sizeof(hbuf
));
1997 hbuf
[sizeof(hbuf
) - 1] = '\0';
2003 if ((hp
= gethostbyname(name
)) == NULL
) {
2004 /* Try again eliminating the trailing domain */
2005 if ((ptr
= strchr(name
, '.')) != NULL
) {
2007 if ((hp
= gethostbyname(name
)) != NULL
)
2024 left
= strlen(host
);
2028 res
= xwrite(dest_fd
, host
, left
);
2039 * From: <lesv@ppvku.ericsson.se> (Lennart Svensson)
2044 struct sigaction sa
;
2045 struct strbuf hostname
= strbuf_INIT
;
2046 int fds
[2], wait_options
, status
;
2047 pid_t pid
, wait_res
;
2049 sa
.sa_handler
= SIG_DFL
; /* Make sure a zombie is created */
2050 sigemptyset(&sa
.sa_mask
);
2052 sigaction(SIGCHLD
, &sa
, NULL
);
2058 /* Don't get stuck if the resolver does not work! */
2059 signal(SIGALRM
, palarm
);
2061 sigaddset(&set
, SIGALRM
);
2062 (void)sigprocmask(SIG_UNBLOCK
, &set
, NULL
);
2064 getremotehost(fds
[1]);
2072 res
= xread(fds
[0], buf
, sizeof(buf
));
2075 wait_options
= WNOHANG
;
2080 strbuf_appendn(&hostname
, buf
, res
);
2084 cleanup_push(&hostname
, strbuf_cleanup
);
2086 while ((wait_res
= waitpid(pid
, &status
, wait_options
)) == -1
2088 handle_pending_signals();
2089 if (hostname
.len
> 0 && wait_res
== pid
&& WIFEXITED(status
)
2090 && WEXITSTATUS(status
) == 0) {
2091 strbuf_terminate(&hostname
);
2092 tsetenv(STRREMOTEHOST
, str2short(hostname
.s
));
2094 cleanup_until(&hostname
);
2097 /* From: casper@fwi.uva.nl (Casper H.S. Dik), for Solaris 2.3 */
2102 #endif /* REMOTEHOST */
2104 #ifndef WINNT_NATIVE
2106 * indicate if a terminal type is defined in terminfo/termcap
2107 * (by default the current term type). This allows ppl to look
2108 * for a working term type automatically in their login scripts
2109 * when using a terminal known as different things on different
2113 dotermname(Char
**v
, struct command
*c
)
2117 * Maximum size of a termcap record. We make it twice as large.
2119 char termcap_buffer
[2048];
2122 /* try to find which entry we should be looking for */
2123 termtype
= (v
[1] == NULL
? getenv("TERM") : short2str(v
[1]));
2124 if (termtype
== NULL
) {
2125 /* no luck - the user didn't provide one and none is
2126 * specified in the environment
2133 * we use the termcap function - if we are using terminfo we
2134 * will end up with it's compatibility function
2135 * terminfo/termcap will be initialized with the new
2136 * type but we don't care because tcsh has cached all the things
2139 if (tgetent(termcap_buffer
, termtype
) == 1) {
2140 xprintf("%s\n", termtype
);
2145 #endif /* WINNT_NATIVE */