Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

47358: Add a ZSH_XTRACEFD environment variable to redirect debug traces #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Src/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -5543,7 +5543,7 @@ execshfunc(Shfunc shf, LinkList args)
cmdsp = 0;
if ((osfc = sfcontext) == SFC_NONE)
sfcontext = SFC_DIRECT;
xtrerr = stderr;
xtrerr = xtrace_file;

doshfunc(shf, args, 0);

Expand Down
6 changes: 4 additions & 2 deletions Src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,10 @@ init_io(char *cmd)
SHTTY = -1;
}

/* Send xtrace output to stderr -- see execcmd() */
xtrerr = stderr;
/* Send xtrace output to zsh_xtracefd file descriptor -- see execcmd() */
if (zsh_xtracefd == 0)
zsh_xtracefd = 2;
xtracefdassign();

/* Make sure the tty is opened read/write. */
if (isatty(0)) {
Expand Down
66 changes: 65 additions & 1 deletion Src/params.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ mod_export zlong
zterm_lines, /* $LINES */
rprompt_indent, /* $ZLE_RPROMPT_INDENT */
ppid, /* $PPID */
zsh_subshell; /* $ZSH_SUBSHELL */
zsh_subshell, /* $ZSH_SUBSHELL */
zsh_xtracefd; /* $ZSH_XTRACEFD */

/* $FUNCNEST */
/**/
Expand Down Expand Up @@ -270,6 +271,9 @@ static const struct gsu_array pipestatus_gsu =
static const struct gsu_integer rprompt_indent_gsu =
{ intvargetfn, zlevarsetfn, rprompt_indent_unsetfn };

static const struct gsu_integer xtracefd_gsu =
{ intvargetfn, xtracefdsetfn, xtracefdunsetfn };

/* Nodes for special parameters for parameter hash table */

#ifdef HAVE_UNION_INIT
Expand Down Expand Up @@ -359,6 +363,7 @@ IPDEF5("LINES", &zterm_lines, zlevar_gsu),
IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, rprompt_indent_gsu),
IPDEF5("SHLVL", &shlvl, varinteger_gsu),
IPDEF5("FUNCNEST", &zsh_funcnest, varinteger_gsu),
IPDEF5("ZSH_XTRACEFD", &zsh_xtracefd, xtracefd_gsu),

/* Don't import internal integer status variables. */
#define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
Expand Down Expand Up @@ -4562,6 +4567,65 @@ setsecondstype(Param pm, int on, int off)
return 0;
}

/* Open / assign the XTRACE fd */

/**/
void xtracefdassign(void)
{
int fd = (int)zsh_xtracefd;
switch (fd)
{
case 0: /* bizarre, but handle for consistency */
xtrerr = stdin;
break;

case 1:
xtrerr = stdout;
break;

case 2:
xtrerr = stderr;
break;

default:
xtrerr = fdopen(fd, "w");
break;
}
xtrace_file = xtrerr;
}

/* Function to set value of special parameter `ZSH_XTRACEFD' */

/**/
void
xtracefdsetfn(Param pm, zlong fd)
{
/* Check that the given file descriptor is valid */
if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
intvarsetfn(pm, fd);
xtracefdassign();
} else
zwarn("file descriptor %d is not valid", fd);

}

/* Function to unset value of special parameter `ZSH_XTRACEFD' */

/**/
void
xtracefdunsetfn(Param pm, UNUSED(int exp))
{
int current_fd = intvargetfn(pm);
if (current_fd == 2) /* Nothing to do, already using stderr */
return;
else { /* Reset to file descriptor 2 (stderr) */
intvarsetfn(pm, 2);
// if (current_fd > 2)
// fclose(xtrerr); /* Never close standard descriptors */
xtrerr = xtrace_file = stderr;
}
}

/* Function to get value for special parameter `USERNAME' */

/**/
Expand Down
9 changes: 8 additions & 1 deletion Src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -1699,12 +1699,19 @@ checkmailpath(char **s)
/**/
FILE *xtrerr = 0;

/* This records the last file XTRACE was open too.
* It's used for restoring XTRACE after a possible redirection.
*/

/**/
FILE *xtrace_file;

/**/
void
printprompt4(void)
{
if (!xtrerr)
xtrerr = stderr;
xtracefdassign();
if (prompt4) {
int l, t = opts[XTRACE];
char *s = dupstring(prompt4);
Expand Down
67 changes: 67 additions & 0 deletions Test/A04redirect.ztst
Original file line number Diff line number Diff line change
Expand Up @@ -721,3 +721,70 @@
>Works
>Works
?(eval):6: file exists: foo

rm -f redir
set -x
ZSH_XTRACEFD=4 print 'This is ZSH_XTRACEFD redir' 4>redir
set +x
cat redir
0:Redirect xtrace output to ZSH_XTRACEFD file descriptor
>This is ZSH_XTRACEFD redir
>+(eval):3> print 'This is ZSH_XTRACEFD redir'
?+(eval):3> ZSH_XTRACEFD=4 +(eval):4> set +x

rm -f redir
A() {
local ZSH_XTRACEFD=5
B
print 'Function A to file descriptor 5'
unset ZSH_XTRACEFD
print 'Function A to file descriptor 2'
}
B() {
local ZSH_XTRACEFD=6
print 'Function B to file descriptor 6'
}
exec 4>redir4 5>redir5 6>redir6
ZSH_XTRACEFD=4
set -x
print 'Main to file descriptor 4'
A
print 'Main to file descriptor 4 again\n'
a=0 ZSH_XTRACEFD=5 # appears as blank line in redir5
ZSH_XTRACEFD=6 # appears as blank line in redir6
unset ZSH_XTRACEFD
set +x
print "end of file redir4" >> redir4
cat redir4
print
print "end of file redir5" >> redir5
cat redir5
print
print "end of file redir6" >> redir6
cat redir6
0:Scoped ZSH_XTRACEFD correctly set and restored
>Main to file descriptor 4
>Function B to file descriptor 6
>Function A to file descriptor 5
>Function A to file descriptor 2
>Main to file descriptor 4 again
>
>+(eval):16> print 'Main to file descriptor 4'
>+(eval):17> A
>+A:1> local ZSH_XTRACEFD=5
>+(eval):18> print 'Main to file descriptor 4 again\n'
>end of file redir4
>
>+A:2> B
>+B:1> local ZSH_XTRACEFD=6
>+A:3> print 'Function A to file descriptor 5'
>+A:4> unset ZSH_XTRACEFD
>
>end of file redir5
>
>+B:2> print 'Function B to file descriptor 6'
>
>+(eval):21> unset ZSH_XTRACEFD
>end of file redir6
?+A:5> print 'Function A to file descriptor 2'
?+(eval):22> set +x