Hello Robin.

First of all, thanks for using this MUA and reporting this issue.

Robin Humble wrote in
 <[email protected]>:
 |on current RHEL9 and Fedora40, and also on s-nail git master, I ran
 |into an issue that halts a backgrounded script connected to a tty.
 |
 |as an example on RHEL9 ->
 |
 | $ ( echo blah | Mail root ) &
 |[1] 2754649
 | $ ^M^M^M^M^C^C
 |
 |[1]+  Stopped                 ( echo blah | Mail root )
 | $ fg
 |( echo blah | Mail root )
 | $ 
 |
 |the mail is sent, but the calling script (just a subshell in this case)
 |is Stopped. the calling tty is confused and shows control characters.
 |^C is needed to get back to the shell.
 |
 |I dug a bit deeper and it seems s-nail mistakenly tries to set
 |terminal options in this use-case?

Yes and no.  You can work around this by redirecting standard
output to /dev/null:

 | $ ( echo blah | Mail root >/dev/null) &

This will do what you want.

 |I gather that tcsetattr causes the backgrounded script to get sent
 |SIGTTOU and the entire script (not just s-nail) goes to Stopped state.
 |mail gets sent, but the calling script is halted.
 |scripts launched via cron and systemd work fine, presumably because
 |those scripts are detached from a tty.
 |
 |I've narrowed the problem down to the below part of git master, but I
 |don't know enough about s-nail (or signals, ttys, ...) to fix it.

  [..termios stuff..]

 |can you please help?
 |
 |is there an internal mode that describes this style of usage of s-nail?
 |if so, maybe that could be used to avoid all tcsetattr entirely?

Yes.  I yet have to check *why* this went wrong, the problem is
that everywhere we do eg

                if(n_psonce & n_PSO_TTYANY){

but the real condition should be as in
mx_termios_controller_setup(), what!=mx_TERMIOS_SETUP_STARTUP:

  /* Semantics are a bit hairy and cast in stone in the manual, and
   * scattered all over the place, at least $COLUMNS, $LINES, -# */
  if(!su_state_has(su_STATE_REPRODUCIBLE) &&
        ((n_psonce & n_PSO_INTERACTIVE) ||
          ((n_psonce & n_PSO_TTYANY) && (n_poption & n_PO_BATCH_FLAG))
        )
    ){

Moreover TTYANY is

   n_PSO_TTYANY = n_PSO_TTYIN | n_PSO_TTYOUT, /* mx_tty_fp = TTY */

so (x&TTYANY)==TTYANY it should likely be, and INTERACTIVE is

        /* Assume we are interactive, then.
         * This state will become unset later for n_PO_QUICKRUN_MASK! */
        if((n_psonce & n_PSO_TTYANY) == n_PSO_TTYANY)
                n_psonce |= n_PSO_INTERACTIVE;

And before we have a big TODO

    /* TODO This is wrong: interactive is STDIN/STDERR for a POSIX sh(1).
     * TODO For now we get this wrong, all over the place, as this software
     * TODO has always been developed with stdout as an output channel.
     * TODO Start doing it right for at least explicit terminal-related things,
     * TODO but v15 should use ONLY this, also for terminal input! */

So if we were doing right the above instead really had to redirect
stderr to /dev/null, .. yet that is not correct at the moment, too.

I .. still try to wrap my head what would be the right thing to
do.  The POSIX standard says for the shell:

  APPLICATION USAGE
  Standard input and standard error are the files that determine
  whether a shell is interactive when -i is not specified. For
  example:
    sh > file
  and:
    sh 2> file
  create interactive and non-interactive shells,
  respectively. Although both accept terminal input, the results
  of error conditions are different[.]

But then again we currently *only* support standard input as
a terminal, so.  Hm.

Thanks for reporting this issue!  Again, direct success via
redirecting standard output in addition

 $ ( echo blah | Mail root >/dev/null) &

a real patch will be in v14.10 somewhen in fall i hope.
(Adding your email to THANKS is ok?)

Ciao!

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)

Reply via email to