Hello Zelphir, Zelphir Kaltstahl <zelphirkaltst...@posteo.de> writes: > I have questions regarding this workaround: > > Can you explain how and why this works? I have tried to make sense of it and > here are my notes so far (reference: > https://notabug.org/ZelphirKaltstahl/guile-examples/src/2dead9f7bb9b40fc26eb490a93e1dc7abca7252c/shell/system-asterisk-stdout-to-stderr-redirection-bug.scm):
Note that here, I used undocumented behavior of open-pipe*, which can be understood by inspecting libguile/posix.c (look for piped-process) and module/ice-9/popen.scm (look for open-pipe*). > ~~~~ > (match-let (((input . output) (pipe))) > ;; Hack to work around Guile bug 52835 -- How does > ;; duplicating the port help? From the docs: "Returns a > ;; new port which is opened on a duplicate of the file > ;; descriptor underlying port, with mode string modes as > ;; for open-file. The two ports will share a file position > ;; and file status flags. [...]" > (define dup-output (duplicate-port output "w")) The above Guile bug occurs because the current output and error ports point to the same file descriptor. Using duplicate-port makes sure that we get a port with a duplicated file descriptor! > ;; Void pipe, but holds the pid for close-pipe. > (define dummy-pipe > ;; Set current-input-port to /dev/null. -- What will be > ;; read from there? Nothing? > (with-input-from-file "/dev/null" Yes, for our use-case we don't need to feed anything to the command, but it's always possible to hook this up to a pipe if you need to. > (lambda () > ;; Set the current-output-port to the one created > ;; above using (pipe). > (with-output-to-port output > (lambda () > ;; Set the error port to the duplicated output > ;; port. This might be the redirection of stderr > ;; to stdout. > (with-error-to-port dup-output Exactly, this is the redirection. > (lambda () > ;; Run open-file*, but why is there an empty > ;; string prepended to command? Perhaps to > ;; allow using either a list or a string as > ;; a command? > (apply open-pipe* (cons "" command))))))))) Here's the undefined behavior, the first argument of open-pipe* is a mode for the pipe it opens, but here we don't want it to open any pipes, all our default ports are setup so that start_child will set the child's stdin/out/err to their file descriptors. > (close-port output) > (close-port dup-output) > (handler input) > (close-port input) > (close-pipe dummy-pipe)) > ~~~~ > > My other question is: Do I still need this workaround, if I use the > following, > to run commands? And if so, why? In which cases would my code not do the > right > thing? (reference: > https://notabug.org/ZelphirKaltstahl/guile-examples/src/2dead9f7bb9b40fc26eb490a93e1dc7abca7252c/shell/example-03-using-popen-get-out-and-error.scm): Looking briefly at your code, I don't think that bug could be affecting you. You can have an issue if you're trying to redirect a standard fd to another standard fd, but if you're using fresh ports it should be ok. Best, -- Josselin Poiret