From: Alexander Turenko <alexander.turenko@tarantool.org>
To: Cyrill Gorcunov <gorcunov@gmail.com>
Cc: tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH 12/12] popen: allow to close parent's end of std* fds
Date: Wed, 15 Apr 2020 07:21:12 +0300 [thread overview]
Message-ID: <20200415042112.ur5anngvrhn7mmrl@tkn_work_nb> (raw)
In-Reply-To: <20200414130507.GH3072@uranus>
> > +int
> > +popen_shutdown(struct popen_handle *handle, unsigned int flags)
> > +{
> > + assert(handle != NULL);
> > +
> > + if ((flags & (POPEN_FLAG_FD_STDIN |
> > + POPEN_FLAG_FD_STDOUT |
> > + POPEN_FLAG_FD_STDERR)) == 0) {
> > + diag_set(IllegalParams,
> > + "popen: neither stdin, stdout nor stderr is choosen");
> > + return -1;
> > + }
> > +
> > + /* Verify the operation. */
> > + for (int idx = STDIN_FILENO; idx < POPEN_FLAG_FD_STDEND_BIT; ++idx) {
>
> for (size_t i = 0; i < lengthof(pfd_map); i++)
>
> We already do a build time check for STDIN_x proper mapping to numbers,
> lets make it shorter.
Sure, changed.
The diff at bottom of the email.
>
>
> > + /* Operate only on asked fds. */
> > + unsigned int op_mask = pfd_map[idx].mask;
> > + if ((flags & op_mask) == 0)
> > + continue;
> > +
> > + if (popen_may_io(handle, idx, op_mask, true) != 0)
> > + return -1;
> > + }
> > +
> > + /* Perform the operation. */
> > + for (int idx = STDIN_FILENO; idx < POPEN_FLAG_FD_STDEND_BIT; ++idx) {
> > + /* Operate only on asked fds. */
> > + unsigned int op_mask = pfd_map[idx].mask;
> > + if ((flags & op_mask) == 0)
> > + continue;
> > +
> > + /* Skip already closed fds. */
> > + if (handle->ios[idx].fd < 0)
> > + continue;
> > +
> > + say_debug("popen: %d: shutdown idx [%s:%d] fd %s",
> > + handle->pid, stdX_str(idx), idx,
> > + handle->ios[idx].fd);
> > + coio_close_io(loop(), &handle->ios[idx]);
> > + }
>
> I don't get why we need two for() cycles?
The first loop is to check that we able to close all fds: all checks are
made first, then all close()'s are called. But the first loop actually
may be replaced with the following check:
| flags &= POPEN_FLAG_FD_STDIN |
| POPEN_FLAG_FD_STDOUT |
| POPEN_FLAG_FD_STDERR;
| if ((handle->flags & flags) != flags)
| /* Give an error here. */
It looks more clean, so I'll use this way. Thanks for catching this!
> Also, I don't like that we
> mangle popen_may_io(). The shutdown is special. Why not do something like
We should check for closed fd in popen_may_io(), because read / write
should give proper error in the case. I guess that here we agreed.
But I made this check conditional in popen_may_io() and I guess it is
what you complain about.
I agree that it looks a bit artificial and so I extracted setting of the
'not supported IO operation' error into a helper function and use it in
popen_shutdown() directly. This really looks better.
See the diff below.
>
> for (size_t idx = 0; i < lengthof(pfd_map); i++) {
> unsigned int op_mask = pfd_map[idx].mask;
> if ((flags & op_mask) == 0)
> continue;
>
> if (handle->ios[idx].fd < 0)
> continue;
>
> ...
> }
>
> Can't we do something like that?
Not exactly, but a kind of this. See below.
WBR, Alexander Turenko.
----
Incremental diff:
--- a/src/lib/core/popen.c 2020-04-15 01:44:51.387489580 +0300
+++ b/src/lib/core/popen.c 2020-04-15 01:44:35.118490605 +0300
@@ -245,21 +245,30 @@
}
/**
+ * Generate an error about IO operation that is not supported by
+ * a popen handle.
+ */
+static inline int
+popen_set_unsupported_io_error(void)
+{
+ diag_set(IllegalParams, "popen: handle does not support the "
+ "requested IO operation");
+ return -1;
+}
+
+/**
* Test if the handle can run a requested IO operation.
*
* Returns 0 if so and -1 otherwise (and set a diag).
*/
static inline int
popen_may_io(struct popen_handle *handle, unsigned int idx,
- unsigned int io_flags, bool allow_closed)
+ unsigned int io_flags)
{
- if (!(io_flags & handle->flags)) {
- diag_set(IllegalParams, "popen: handle does not support the "
- "requested IO operation");
- return -1;
- }
+ if (!(io_flags & handle->flags))
+ return popen_set_unsupported_io_error();
- if (! allow_closed && handle->ios[idx].fd < 0) {
+ if (handle->ios[idx].fd < 0) {
diag_set(IllegalParams, "popen: attempt to operate "
"on a closed file descriptor");
return -1;
@@ -374,7 +383,7 @@
int idx = STDIN_FILENO;
- if (popen_may_io(handle, idx, flags, false) != 0)
+ if (popen_may_io(handle, idx, flags) != 0)
return -1;
say_debug("popen: %d: write idx [%s:%d] buf %p count %zu "
@@ -439,7 +448,7 @@
int idx = flags & POPEN_FLAG_FD_STDOUT ?
STDOUT_FILENO : STDERR_FILENO;
- if (popen_may_io(handle, idx, flags, false) != 0)
+ if (popen_may_io(handle, idx, flags) != 0)
return -1;
say_debug("popen: %d: read idx [%s:%d] buf %p count %zu "
@@ -486,27 +495,29 @@
{
assert(handle != NULL);
- if ((flags & (POPEN_FLAG_FD_STDIN |
- POPEN_FLAG_FD_STDOUT |
- POPEN_FLAG_FD_STDERR)) == 0) {
+ /* Ignore irrelevant flags. */
+ flags &= POPEN_FLAG_FD_STDIN |
+ POPEN_FLAG_FD_STDOUT |
+ POPEN_FLAG_FD_STDERR;
+
+ /* At least one ..._FD_STDx flag should be set. */
+ if (flags == 0) {
diag_set(IllegalParams,
"popen: neither stdin, stdout nor stderr is choosen");
return -1;
}
- /* Verify the operation. */
- for (int idx = STDIN_FILENO; idx < POPEN_FLAG_FD_STDEND_BIT; ++idx) {
- /* Operate only on asked fds. */
- unsigned int op_mask = pfd_map[idx].mask;
- if ((flags & op_mask) == 0)
- continue;
-
- if (popen_may_io(handle, idx, op_mask, true) != 0)
- return -1;
- }
+ /*
+ * The handle should have all std*, which are asked to
+ * close, be piped.
+ *
+ * Otherwise the operation has no sense: we should close
+ * parent's end of a pipe, but it was not created at all.
+ */
+ if ((handle->flags & flags) != flags)
+ return popen_set_unsupported_io_error();
- /* Perform the operation. */
- for (int idx = STDIN_FILENO; idx < POPEN_FLAG_FD_STDEND_BIT; ++idx) {
+ for (size_t idx = 0; idx < lengthof(pfd_map); ++idx) {
/* Operate only on asked fds. */
unsigned int op_mask = pfd_map[idx].mask;
if ((flags & op_mask) == 0)
next prev parent reply other threads:[~2020-04-15 4:21 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-14 11:38 [Tarantool-patches] [PATCH 00/12] Popen Lua API: preliminary patches 2 Alexander Turenko
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 01/12] popen: allow to kill process group Alexander Turenko
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 02/12] popen: add ability to keep child on deletion Alexander Turenko
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 03/12] popen: log a reason of close inherited fds failure Alexander Turenko
2020-04-14 11:52 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 04/12] popen: add missed diag_set() in popen_new() Alexander Turenko
2020-04-14 11:54 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 05/12] popen: remove retval from popen_stat() Alexander Turenko
2020-04-14 11:54 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 06/12] popen: quote multiword command arguments Alexander Turenko
2020-04-14 11:58 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 07/12] popen: add logging of duplicated logger fd Alexander Turenko
2020-04-14 11:58 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 08/12] popen: fix close-on-exec flag setting Alexander Turenko
2020-04-14 12:03 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 09/12] popen: clarify popen_{signal, delete} contract Alexander Turenko
2020-04-14 12:29 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 10/12] popen: add FIXME re group signal flaw Alexander Turenko
2020-04-14 13:19 ` Cyrill Gorcunov
2020-04-15 4:21 ` Alexander Turenko
2020-04-15 7:27 ` Cyrill Gorcunov
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 11/12] popen: clarify popen_read_timeout error message Alexander Turenko
2020-04-14 12:32 ` Cyrill Gorcunov
2020-04-15 4:21 ` Alexander Turenko
2020-04-15 7:39 ` Cyrill Gorcunov
2020-04-15 21:45 ` Alexander Turenko
2020-04-14 11:38 ` [Tarantool-patches] [PATCH 12/12] popen: allow to close parent's end of std* fds Alexander Turenko
2020-04-14 13:05 ` Cyrill Gorcunov
2020-04-15 4:21 ` Alexander Turenko [this message]
2020-04-15 7:43 ` Cyrill Gorcunov
2020-04-15 21:45 ` Alexander Turenko
2020-04-15 4:25 ` [Tarantool-patches] [PATCH 13/13] popen: add caution comment for popen_may_io() Alexander Turenko
2020-04-15 7:44 ` Cyrill Gorcunov
2020-04-15 4:52 ` [Tarantool-patches] [PATCH 14/14] popen: fix popen_write_timeout retval type Alexander Turenko
2020-04-15 23:57 ` [Tarantool-patches] [PATCH 00/12] Popen Lua API: preliminary patches 2 Alexander Turenko
2020-04-16 0:00 ` Alexander Turenko
2020-04-16 11:52 ` Cyrill Gorcunov
2020-04-17 6:58 ` Kirill Yukhin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200415042112.ur5anngvrhn7mmrl@tkn_work_nb \
--to=alexander.turenko@tarantool.org \
--cc=gorcunov@gmail.com \
--cc=tarantool-patches@dev.tarantool.org \
--subject='Re: [Tarantool-patches] [PATCH 12/12] popen: allow to close parent'\''s end of std* fds' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox