diff --git a/doc/management.txt b/doc/management.txt index 36b196ff9..3bc64212b 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -2685,9 +2685,19 @@ show events [] [-w] [-n] combined with "-w" to only report new events. For convenience, "-wn" or "-nw" may be used to enable both options at once. -show fd [] +show fd [-!plcfbsd]* [] Dump the list of either all open file descriptors or just the one number - if specified. This is only aimed at developers who need to observe internal + if specified. A set of flags may optionally be passed to restrict the dump + only to certain FD types or to omit certain FD types. When '-' or '!' are + encountered, the selection is inverted for the following characters in the + same argument. The inversion is reset before each argument word delimited by + white spaces. Selectable FD types include 'p' for pipes, 'l' for listeners, + 'c' for connections (any type), 'f' for frontend connections, 'b' for backend + connections (any type), 's' for connections to servers, 'd' for connections + to the "dispatch" address or the backend's transparent address. With this, + 'b' is a shortcut for 'sd' and 'c' for 'fb' or 'fsd'. 'c!f' is equivalent to + 'b' ("any connections except frontend connections" are indeed backend + connections). This is only aimed at developers who need to observe internal states in order to debug complex issues such as abnormal CPU usages. One fd is reported per lines, and for each of them, its state in the poller using upper case letters for enabled flags and lower case for disabled flags, using diff --git a/src/cli.c b/src/cli.c index e09ac692d..11780090d 100644 --- a/src/cli.c +++ b/src/cli.c @@ -93,9 +93,20 @@ struct show_env_ctx { }; /* CLI context for the "show fd" command */ +/* flags for show_fd_ctx->show_mask */ +#define CLI_SHOWFD_F_PI 0x00000001 /* pipes */ +#define CLI_SHOWFD_F_LI 0x00000002 /* listeners */ +#define CLI_SHOWFD_F_FE 0x00000004 /* frontend conns */ +#define CLI_SHOWFD_F_SV 0x00000010 /* server-only conns */ +#define CLI_SHOWFD_F_PX 0x00000020 /* proxy-only conns */ +#define CLI_SHOWFD_F_BE 0x00000030 /* backend: srv+px */ +#define CLI_SHOWFD_F_CO 0x00000034 /* conn: be+fe */ +#define CLI_SHOWFD_F_ANY 0x0000003f /* any type */ + struct show_fd_ctx { int fd; /* first FD to show */ int show_one; /* stop after showing one FD */ + uint show_mask; /* CLI_SHOWFD_F_xxx */ }; /* CLI context for the "show cli sockets" command */ @@ -1259,6 +1270,7 @@ static int cli_io_handler_show_fd(struct appctx *appctx) { struct stconn *sc = appctx_sc(appctx); struct show_fd_ctx *fdctx = appctx->svcctx; + uint match = fdctx->show_mask; int fd = fdctx->fd; int ret = 1; @@ -1321,6 +1333,17 @@ static int cli_io_handler_show_fd(struct appctx *appctx) else if (fdt.iocb == sock_accept_iocb) li = fdt.owner; + if (!((conn && + ((match & CLI_SHOWFD_F_SV && sv) || + (match & CLI_SHOWFD_F_PX && px) || + (match & CLI_SHOWFD_F_FE && li))) || + (!conn && + ((match & CLI_SHOWFD_F_LI && li) || + (match & CLI_SHOWFD_F_PI && !li /* only pipes match this */))))) { + /* not a desired type */ + goto skip; + } + if (!fdt.thread_mask) suspicious = 1; @@ -1573,14 +1596,52 @@ static int cli_parse_show_env(char **args, char *payload, struct appctx *appctx, static int cli_parse_show_fd(char **args, char *payload, struct appctx *appctx, void *private) { struct show_fd_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); + const char *c; + int arg; if (!cli_has_level(appctx, ACCESS_LVL_OPER)) return 1; - if (*args[2]) { + arg = 2; + + /* when starting with an inversion we preset every flag */ + if (*args[arg] == '!' || *args[arg] == '-') + ctx->show_mask = CLI_SHOWFD_F_ANY; + + while (*args[arg] && !isdigit((uchar)*args[arg])) { + uint flag = 0, inv = 0; + c = args[arg]; + while (*c) { + switch (*c) { + case '!': inv = !inv; break; + case '-': inv = !inv; break; + case 'p': flag = CLI_SHOWFD_F_PI; break; + case 'l': flag = CLI_SHOWFD_F_LI; break; + case 'c': flag = CLI_SHOWFD_F_CO; break; + case 'f': flag = CLI_SHOWFD_F_FE; break; + case 'b': flag = CLI_SHOWFD_F_BE; break; + case 's': flag = CLI_SHOWFD_F_SV; break; + case 'd': flag = CLI_SHOWFD_F_PX; break; + default: return cli_err(appctx, "Invalid FD type\n"); + } + c++; + if (!inv) + ctx->show_mask |= flag; + else + ctx->show_mask &= ~flag; + } + arg++; + } + + /* default mask is to show everything */ + if (!ctx->show_mask) + ctx->show_mask = CLI_SHOWFD_F_ANY; + + if (*args[arg]) { ctx->fd = atoi(args[2]); ctx->show_one = 1; } + return 0; } @@ -3158,7 +3219,7 @@ static struct cli_kw_list cli_kws = {{ },{ { { "show", "env", NULL }, "show env [var] : dump environment variables known to the process", cli_parse_show_env, cli_io_handler_show_env, NULL }, { { "show", "cli", "sockets", NULL }, "show cli sockets : dump list of cli sockets", cli_parse_default, cli_io_handler_show_cli_sock, NULL, NULL, ACCESS_MASTER }, { { "show", "cli", "level", NULL }, "show cli level : display the level of the current CLI session", cli_parse_show_lvl, NULL, NULL, NULL, ACCESS_MASTER}, - { { "show", "fd", NULL }, "show fd [num] : dump list of file descriptors in use or a specific one", cli_parse_show_fd, cli_io_handler_show_fd, NULL }, + { { "show", "fd", NULL }, "show fd [-!plcfbsd]* [num] : dump list of file descriptors in use or a specific one", cli_parse_show_fd, cli_io_handler_show_fd, NULL }, { { "show", "version", NULL }, "show version : show version of the current process", cli_parse_show_version, NULL, NULL, NULL, ACCESS_MASTER }, { { "operator", NULL }, "operator : lower the level of the current CLI session to operator", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER}, { { "user", NULL }, "user : lower the level of the current CLI session to user", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER},