Bug 21902 - RFE: set_fileno(fp, fd). use case: shell needs to change fd in a FILE
Summary: RFE: set_fileno(fp, fd). use case: shell needs to change fd in a FILE
Status: UNCONFIRMED
Alias: None
Product: glibc
Classification: Unclassified
Component: stdio (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-08-03 20:11 UTC by Denis Vlasenko
Modified: 2018-01-24 17:18 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Denis Vlasenko 2017-08-03 20:11:16 UTC
I'm using ordinary FILE i/o for reading scripts in the code of hush shell, instead of rolling my own implementation, so that I can reuse buffering code in libc, through the use of fgetc().

This works for almost all cases, except this one: if in script I have a redirect which says shell wants to open a fd which happens to be equal to the fd (say, 10) shell already used for script FILE object:

    exec 10>FILE

What other shells do in this situation is they simply dup and close script fd [in real code, they use fcntl(F_DUPFD) instead of dup() since they want to avoid getting low fds], so that fd is "moved" and no longer collides with the redirect.

I can do this trick, but since I use FILE interface, then I need to inform libc that it needs to use new fd for this FILE.

"fileno(fp) = new_fd;" is non-portable and does not work in glibc: it's a function, not a macro referencing (fp)->field_holding_fd.

"fclose(fp); fp = fdopen(new_fd);" is not good since fp may have some buffered input, which will be lost by such code.

How about adding a "set_fileno(fp, fd)" extension, with some easy define to probe for to conditionally use it?

To make life easier for implementers, I propose that API definition of it should say that any buffered input or output data is not discarded
or sent to previous fd during/after the call - the function only
changes internal fd. It does neither flushing nor seeking nor discarding of buffers. Essentially, user has to take care and fflush(fp)
before he starts messing with fds, or buffered data may end up up written to a wrong fd.

While bouncing around this idea on IRC with other people, some said it could be a thing which would help them with another problem they had. They had a FILE object which they wanted to stop using and free it, but to _not_ close the underlying fd. Along the lines of:

fflush(fp);
fd = fileno(fp);
fclose_but_not_close(fp);

and having fd still open. (They could not work around with dup(fd) before fclose(), since this was in a library code, fd had to stay the same due to concurrency and API issues).

They say that if set_fileno() would exist and would allow set_fileno(fp, -1), it would do what they want.