Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Feature request: ZSH_XTRACEFD variable
Sorry, I hit control-enter by mistake and sent the mail before finishing
writing it...
There is one place where I didn't change the code, because I wasn't sure it
was needed, in exec.c line 3571
if (isset(XTRACE) && xtrerr == stderr &&
(type < WC_SUBSH || type == WC_TIMED)) {
if ((newxtrerr = fdopen(movefd(dup(fileno(stderr))), "w"))) {
xtrerr = newxtrerr;
fdtable[fileno(xtrerr)] = FDT_XTRACE;
}
}
and later at line 4247
if (newxtrerr) {
fil = fileno(newxtrerr);
fclose(newxtrerr);
xtrerr = oxtrerr;
zclose(fil);
}
It seems these two blocks are executed only when xtrerr == stderr, which is
the default case,
therefore I did not modify any of this, but maybe it should be updated as
well.
Regards,
Timothée Mazzucotelli
On Wed, Jul 31, 2019 at 9:40 PM Timothée Mazzucotelli <
timothee.mazzucotelli@xxxxxxxxx> wrote:
> Thank you Peter for your hints.
>
> Here is a first draft:
>
> diff --git a/Src/exec.c b/Src/exec.c
> index 2acb2c0bc..5e550cb24 100644
> --- a/Src/exec.c
> +++ b/Src/exec.c
> @@ -5393,7 +5393,7 @@ execshfunc(Shfunc shf, LinkList args)
> cmdsp = 0;
> if ((osfc = sfcontext) == SFC_NONE)
> sfcontext = SFC_DIRECT;
> - xtrerr = stderr;
> + xtrerr = fdopen(zsh_xtracefd, "w");
>
> doshfunc(shf, args, 0);
>
> diff --git a/Src/init.c b/Src/init.c
> index 445cd3937..396f13556 100644
> --- a/Src/init.c
> +++ b/Src/init.c
> @@ -609,8 +609,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;
> + xtrerr = fdopen(zsh_xtracefd, "w");
>
> /* Make sure the tty is opened read/write. */
> if (isatty(0)) {
> diff --git a/Src/params.c b/Src/params.c
> index 1499e3a40..5e3f5cdbf 100644
> --- a/Src/params.c
> +++ b/Src/params.c
> @@ -102,7 +102,8 @@ zlong lastval, /* $? */
> zterm_lines, /* $LINES */
> rprompt_indent, /* $ZLE_RPROMPT_INDENT */
> ppid, /* $PPID */
> - zsh_subshell; /* $ZSH_SUBSHELL */
> + zsh_subshell, /* $ZSH_SUBSHELL */
> + zsh_xtracefd; /* $ZSH_XTRACEFD */
>
> /* $FUNCNEST */
> /**/
> @@ -264,6 +265,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
> @@ -353,6 +357,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}
> @@ -4387,6 +4392,45 @@ setsecondstype(Param pm, int on, int off)
> return 0;
> }
>
> +/* Function to set value of special parameter `ZSH_XTRACEFD' */
> +
> +/**/
> +void
> +xtracefdsetfn(Param pm, zlong fd)
> +{
> + int current_fd;
> +
> + /* Check that the given file descriptor is valid */
> + if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
> + current_fd = intvargetfn(pm);
> + /* We never close file descriptors 0 (stdin), 1 (stdout) or 2
> (stderr) */
> + if (current_fd > 2) {
> + close(current_fd);
> + fclose(xtrerr);
> + }
> + intvarsetfn(pm, fd);
> + xtrerr = fdopen(fd, "w");
> + } 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 > 1) fclose(xtrerr); /* Never close stdin or stdout
> */
> + xtrerr = stderr;
> + }
> +}
> +
> /* Function to get value for special parameter `USERNAME' */
>
> /**/
> diff --git a/Src/utils.c b/Src/utils.c
> index 46cf7bcf6..93ea8044f 100644
> --- a/Src/utils.c
> +++ b/Src/utils.c
> @@ -1765,7 +1765,7 @@ void
> printprompt4(void)
> {
> if (!xtrerr)
> - xtrerr = stderr;
> + xtrerr = fdopen(zsh_xtracefd, "w");
> if (prompt4) {
> int l, t = opts[XTRACE];
> char *s = dupstring(prompt4);
>
>
> And some notes:
>
> There is one place where I didn't change the code, because I wasn't sure
> it was needed:
>
>
> > Doing this without creating leaks or crashes on bad file descriptors
> could be interesting.
>
> About leaks, I think file pointers are all freed in the params.c set and
> unset functions.
> However I'm not sure about exec.c, line 5396, in function execshfunc,
> where xtrerr was
> previously always reassigned to stderr. Now it is reassigned to a new file
> pointer obtained
> with fdopen(zsh_xtracefd, "w") each time, and maybe this could cause
> memory leaks.
>
> About crashes on bad file descriptors, I used if (fcntl(fd, F_GETFD) != -1
> || errno != EBADF) as a condition
> to test the validity of a file descriptor, but I'm not sure it can handle
> all the cases, or if it even makes
> sense. It's working with basic cases though.
>
>
>
>
> On Sun, Jul 21, 2019 at 5:23 PM Peter Stephenson <p.stephenson@xxxxxxxxxxx>
> wrote:
>
>> On Sun, 2019-07-21 at 17:08 +0200, Timothée Mazzucotelli wrote:
>> > I'm willing to help implementing this feature (equivalent of Bash's
>> > BASH_XTRACEFD). Any advice where I should start? Who I should get in
>> touch
>> > with?
>>
>> This is the right place. Certainly feel free to investigate.
>>
>> Have a look at the way the FILE *xtrerr is handed in the source code.
>> This
>> is going to need some more careful management. Doing this without
>> creating
>> leaks or crashes on bad file descriptors could be interesting.
>> In most places, once it is reopened to a different file the redirection
>> should "just work", but there maybe some interesting special cases
>> as we do do slightly funny things with xtrerr at some points.
>>
>> I think you're going to need a special integer variable that manages
>> this file based on someone setting the FD. params.c has this sort
>> of handling --- see various special integer variables with
>> their own get / set functions, e.g. intsecondssetfn shows you
>> what happens when someone sets SECONDS. You're going to have
>> a function of that sort that instead closes and reopens
>> xtrerr.
>>
>> I guess ZSH_XTRACEFD is the obvious name.
>>
>> Cheers
>> pws
>>
>>
Messages sorted by:
Reverse Date,
Date,
Thread,
Author