util-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 1/4] misc-utils: add the pipesz utility
       [not found] <20220412045930.236051-1-nwsharp@live.com>
@ 2022-04-12  4:59 ` Nathan Sharp
  2022-05-04 10:50   ` Karel Zak
  2022-04-12  4:59 ` [PATCH RFC 2/4] pipesz: add tests Nathan Sharp
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Nathan Sharp @ 2022-04-12  4:59 UTC (permalink / raw)
  To: util-linux; +Cc: Nathan Sharp

pipesz is a utility to examine and adjust the size of pipe buffers.

It uses fctnl F_GETPIPE_SZ and F_SETPIPE_SZ to examine and resize
these buffers. This functionality is unique to Linux and was added in
version 2.6.35. Minor bugfixes were made in 4.9, but these do not
obviate the use of pipesz prior to that release.

Signed-off-by: Nathan Sharp <nwsharp@live.com>
---
 .gitignore               |   1 +
 configure.ac             |   8 +
 include/pathnames.h      |   4 +
 meson.build              |  12 ++
 meson_options.txt        |   2 +
 misc-utils/Makemodule.am |   7 +
 misc-utils/meson.build   |   4 +
 misc-utils/pipesz.c      | 347 +++++++++++++++++++++++++++++++++++++++
 8 files changed, 385 insertions(+)
 create mode 100644 misc-utils/pipesz.c

diff --git a/.gitignore b/.gitignore
index 840f646..a31e7e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -143,6 +143,7 @@ ylwrap
 /nsenter
 /partx
 /pg
+/pipesz
 /pivot_root
 /prlimit
 /raw
diff --git a/configure.ac b/configure.ac
index 2c3b432..3ac79a5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1785,6 +1785,14 @@ AC_ARG_ENABLE([whereis],
 UL_BUILD_INIT([whereis])
 AM_CONDITIONAL([BUILD_WHEREIS], [test "x$build_whereis" = xyes])
 
+AC_ARG_ENABLE([pipesz],
+  AS_HELP_STRING([--disable-pipesz], [do not build pipesz]),
+  [], [UL_DEFAULT_ENABLE([pipesz])]
+)
+UL_BUILD_INIT([pipesz])
+UL_REQUIRES_LINUX([pipesz])
+AM_CONDITIONAL([BUILD_PIPESZ], [test "x$build_pipesz" = xyes])
+
 UL_BUILD_INIT([getopt], [yes])
 AM_CONDITIONAL([BUILD_GETOPT], [test "x$build_getopt" = xyes])
 
diff --git a/include/pathnames.h b/include/pathnames.h
index d86d9d5..0887bd7 100644
--- a/include/pathnames.h
+++ b/include/pathnames.h
@@ -198,6 +198,10 @@
 #define _PATH_PROC_UCLAMP_MIN	_PATH_PROC_KERNEL "/sched_util_clamp_min"
 #define _PATH_PROC_UCLAMP_MAX	_PATH_PROC_KERNEL "/sched_util_clamp_max"
 
+/* sysctl fs paths */
+#define _PATH_PROC_SYS_FS	"/proc/sys/fs"
+#define _PATH_PROC_PIPE_MAX_SIZE	_PATH_PROC_SYS_FS "/pipe-max-size"
+
 /* irqtop paths */
 #define _PATH_PROC_INTERRUPTS	"/proc/interrupts"
 #define _PATH_PROC_SOFTIRQS	"/proc/softirqs"
diff --git a/meson.build b/meson.build
index 0642ab5..358572e 100644
--- a/meson.build
+++ b/meson.build
@@ -2678,6 +2678,18 @@ if not is_disabler(exe)
   bashcompletions += ['hardlink']
 endif
 
+opt = not get_option('build-pipesz').disabled()
+exe = executable(
+  'pipesz',
+  pipesz_sources,
+  include_directories : includes,
+  link_with : [lib_common],
+  install_dir : usrbin_exec_dir,
+  install : true)
+if opt and not is_disabler(exe)
+  exes += exe
+endif
+
 exe = executable(
   'test_cal',
   cal_sources,
diff --git a/meson_options.txt b/meson_options.txt
index 64c9924..5272cb3 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -150,6 +150,8 @@ option('build-more', type : 'feature',
        description : 'build more')
 option('build-pg', type : 'feature',
        description : 'build pg')
+option('build-pipesz', type : 'feature',
+       description : 'build pipesz')
 option('build-setterm', type : 'feature',
        description : 'build setterm')
 option('build-schedutils', type : 'feature',
diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am
index cc18acb..60c7fe1 100644
--- a/misc-utils/Makemodule.am
+++ b/misc-utils/Makemodule.am
@@ -266,3 +266,10 @@ lsfd_SOURCES = \
 lsfd_LDADD = $(LDADD) libsmartcols.la libcommon.la
 lsfd_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
 endif
+
+if BUILD_PIPESZ
+bin_PROGRAMS += pipesz
+pipesz_SOURCES = misc-utils/pipesz.c
+pipesz_LDADD = $(LDADD) libcommon.la
+pipesz_CFLAGS = $(AM_CFLAGS)
+endif
diff --git a/misc-utils/meson.build b/misc-utils/meson.build
index d435207..16310a9 100644
--- a/misc-utils/meson.build
+++ b/misc-utils/meson.build
@@ -140,3 +140,7 @@ hardlink_sources = files(
 cal_sources = files(
   'cal.c',
 )
+
+pipesz_sources = files(
+  'pipesz.c',
+)
diff --git a/misc-utils/pipesz.c b/misc-utils/pipesz.c
new file mode 100644
index 0000000..1283d86
--- /dev/null
+++ b/misc-utils/pipesz.c
@@ -0,0 +1,347 @@
+/*
+ * pipesz(1) - Set or examine pipe buffer sizes.
+ *
+ * Copyright (c) 2022 Nathan Sharp
+ * Written by Nathan Sharp <nwsharp@live.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <getopt.h>
+#include <sys/ioctl.h>		/* FIONREAD */
+#include <fcntl.h>		/* F_GETPIPE_SZ F_SETPIPE_SZ */
+
+#include "c.h"
+#include "nls.h"
+
+#include "closestream.h"	/* close_stdout_atexit */
+#include "optutils.h"		/* err_exclusive_options */
+#include "path.h"		/* ul_path_read_s32 */
+#include "pathnames.h"		/* _PATH_PROC_PIPE_MAX_SIZE */
+#include "strutils.h"		/* strtos32_or_err strtosize_or_err */
+
+static char opt_check = 0;	/* --check */
+static char opt_get = 0; 	/* --get */
+static char opt_quiet = 0;	/* --quiet */
+static int opt_size = -1;	/* --set <size> */
+static char opt_verbose = 0;	/* --verbose */
+
+/* fallback file for default size */
+#ifndef PIPESZ_DEFAULT_SIZE_FILE
+#define PIPESZ_DEFAULT_SIZE_FILE _PATH_PROC_PIPE_MAX_SIZE
+#endif
+
+/* convenience macros, since pipesz is by default very lenient */
+#define check(FMT...) do {			\
+	if (opt_check) {			\
+		err(EXIT_FAILURE, FMT);		\
+	} else if (!opt_quiet)	{		\
+		warn(FMT);			\
+	}					\
+} while (0)
+
+#define checkx(FMT...) do {			\
+	if (opt_check) {			\
+		errx(EXIT_FAILURE, FMT);	\
+	} else if (!opt_quiet) {		\
+		warnx(FMT);			\
+	}					\
+} while (0)
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+	fputs(USAGE_HEADER, stdout);
+	printf(_(" %s [options] [--set <size>] [--] [command]\n"), program_invocation_short_name);
+	printf(_(" %s [options] --get\n"), program_invocation_short_name);
+
+	fputs(USAGE_SEPARATOR, stdout);
+	/* TRANSLATORS: 'command' refers to a program argument */
+	puts(_("Set or examine pipe buffer sizes and optionally execute command."));
+
+	fputs(USAGE_OPTIONS, stdout);
+	puts(_(" -g, --get          examine pipe buffers"));
+	/* TRANSLATORS: '%s' refers to a system file */
+	printf(_(" -s, --set <size>  set pipe buffer sizes\n"
+		"                      size defaults to %s\n"
+	), PIPESZ_DEFAULT_SIZE_FILE);
+
+	fputs(USAGE_SEPARATOR, stdout);
+	puts(_(" -f, --file <path>  act on a file"));
+	puts(_(" -n, --fd <num>     act on a file descriptor"));
+	puts(_(" -i, --stdin        act on standard input"));
+	puts(_(" -o, --stdout       act on standard output"));
+	puts(_(" -e, --stderr       act on standard error"));
+
+	fputs(USAGE_SEPARATOR, stdout);
+	puts(_(" -c, --check        do not continue after an error"));
+	puts(_(" -q, --quiet        do not warn of non-fatal errors"));
+	puts(_(" -v, --verbose      provide detailed output"));
+
+	fputs(USAGE_SEPARATOR, stdout);
+	printf(USAGE_HELP_OPTIONS(20));
+
+	printf(USAGE_MAN_TAIL("pipesz(1)"));
+
+	exit(EXIT_SUCCESS);
+}
+
+/*
+ * performs F_GETPIPE_SZ and FIONREAD
+ * outputs a table row
+ */
+static void do_get(int fd, const char *name)
+{
+	int sz, used;
+	
+	sz = fcntl(fd, F_GETPIPE_SZ);
+	if (sz < 0) {
+		/* TRANSLATORS: '%s' refers to a file */
+		check(_("cannot get pipe buffer size of %s"), name);
+		return;
+	}
+
+	if (ioctl(fd, FIONREAD, &used))
+		used = 0;
+
+	printf("%s\t%d\t%d\n", name, sz, used);
+}
+
+/*
+ * performs F_SETPIPE_SZ
+ */
+static void do_set(int fd, const char *name)
+{
+	int sz;
+	
+	sz = fcntl(fd, F_SETPIPE_SZ, opt_size);
+	if (sz < 0)
+		/* TRANSLATORS: '%s' refers to a file */
+		check(_("cannot set pipe buffer size of %s"), name);
+	else if (opt_verbose)
+		/* TRANSLATORS: '%s' refers to a file, '%d' to a buffer size in bytes */
+		warnx(_("%s pipe buffer size set to %d"), name, sz);
+}
+
+/*
+ * does the requested operation on an fd
+ */
+static void do_fd(int fd)
+{
+	char name[sizeof(stringify(INT_MIN)) + 3];
+
+	sprintf(name, "fd %d", fd);
+
+	if (opt_get)
+		do_get(fd, name);
+	else
+		do_set(fd, name);
+}
+
+/*
+ * does the requested operation on a file
+ */
+static void do_file(const char *path)
+{
+	int fd;
+
+	fd = open(path, O_RDONLY | O_CLOEXEC);
+	if (fd < 0) {
+		/* TRANSLATORS: '%s' refers to a file */
+		check(_("cannot open %s"), path);
+		return;
+	}
+
+	if (opt_get)
+		do_get(fd, path);
+	else
+		do_set(fd, path);
+
+	close(fd);
+}
+
+/*
+ * if necessary, determines a default buffer size and places it in opt_size
+ * returns FALSE if this could not be done
+ */
+static char set_size_default(void)
+{
+	if (opt_size >= 0)
+		return TRUE;
+
+	if (ul_path_read_s32(NULL, &opt_size, PIPESZ_DEFAULT_SIZE_FILE)) {
+		/* TRANSLATORS: '%s' refers to a system file */
+		check(_("cannot parse %s"), PIPESZ_DEFAULT_SIZE_FILE);
+		return FALSE;
+	}
+
+	if (opt_size < 0) {
+		/* TRANSLATORS: '%s' refers to a system file */
+		checkx(_("cannot parse %s"), PIPESZ_DEFAULT_SIZE_FILE);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+int main(int argc, char **argv)
+{
+	static const char shortopts[] = "+cef:ghin:oqs:vV";
+	static const struct option longopts[] = {
+		{ "check",     no_argument,       NULL, 'c' },
+		{ "fd",        required_argument, NULL, 'n' },
+		{ "file",      required_argument, NULL, 'f' },
+		{ "get",       no_argument,       NULL, 'g' },
+		{ "help",      no_argument,       NULL, 'h' },
+		{ "quiet",     no_argument,       NULL, 'q' },
+		{ "set",       required_argument, NULL, 's' },
+		{ "stdin",     no_argument,       NULL, 'i' },
+		{ "stdout",    no_argument,       NULL, 'o' },
+		{ "stderr",    no_argument,       NULL, 'e' },
+		{ "verbose",   no_argument,       NULL, 'v' },
+		{ "version",   no_argument,       NULL, 'V' },
+		{ NULL, 0, NULL, 0 }
+	};
+	static const ul_excl_t excl[] = {
+		{ 'g', 's' },
+		{ 0 }
+	};
+
+	int c, fd, n_opt_pipe = 0, n_opt_size = 0;
+	uintmax_t sz;
+
+	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+	close_stdout_atexit();
+
+	/* check for --help or --version */
+	while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1)
+		switch (c) {
+		case 'h':
+			usage();
+		case 'V':
+			print_version(EXIT_SUCCESS);
+		}
+
+	/* gather normal options */
+	optind = 1;
+	while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
+		err_exclusive_options(c, longopts, excl, excl_st);
+
+		switch (c) {
+		case 'c':
+			opt_check = TRUE;
+			break;
+		case 'e':
+			++n_opt_pipe;
+			break;
+		case 'f':
+			++n_opt_pipe;
+			break;
+		case 'g':
+			opt_get = TRUE;
+			break;
+		case 'i':
+			++n_opt_pipe;
+			break;
+		case 'n':
+			fd = strtos32_or_err(optarg, _("invalid fd argument"));
+			++n_opt_pipe;
+			break;
+		case 'o':
+			++n_opt_pipe;
+			break;
+		case 'q':
+			opt_quiet = TRUE;
+			break;
+		case 's':
+			sz = strtosize_or_err(optarg, _("invalid size argument"));
+			opt_size = sz >= INT_MAX ? INT_MAX : (int)sz;
+			break;
+		case 'v':
+			opt_verbose = TRUE;
+			break;
+		default:
+			errtryhelp(EXIT_FAILURE);
+		}
+	}
+
+	/* check arguments */
+	if (opt_get) {
+		if (argv[optind])
+			errx(EXIT_FAILURE, _("cannot specify a command with --get"));
+
+		/* print column headers, if requested */
+		if (opt_verbose)
+			printf("%s\t%s\t%s\n",
+/* TRANSLATORS: a column that contains the names of files that are unix pipes */
+				_("pipe"),
+/* TRANSLATORS: a column that contains buffer sizes in bytes */
+				_("size"),
+/* TRANSLATORS: a column that contains an amount of data which has not been used by a program */
+				_("unread")
+			);
+
+		/* special behavior for --get */
+		if (!n_opt_pipe) {
+			do_fd(STDIN_FILENO);
+			return EXIT_SUCCESS;
+		}
+	} else {
+		if (!set_size_default())
+			goto execute_command;
+
+		if (!opt_quiet && n_opt_size > 1)
+			warnx(_("using last specified size"));
+
+		/* special behavior for --set */
+		if (!n_opt_pipe) {
+			do_fd(STDOUT_FILENO);
+			goto execute_command;
+		}
+	}
+
+	/* go through the arguments again and do the requested operations */
+	optind = 1;
+	while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1)
+		switch (c) {
+		case 'e':
+			do_fd(STDERR_FILENO);
+			break;
+		case 'f':
+			do_file(optarg);
+			break;
+		case 'i':
+			do_fd(STDIN_FILENO);
+			break;
+		case 'n':
+			/* optarg was checked before, but it's best to be safe */
+			fd = strtos32_or_err(optarg, _("invalid fd argument"));
+			do_fd(fd);
+			break;
+		case 'o':
+			do_fd(STDOUT_FILENO);
+			break;
+		}
+
+execute_command:
+	/* exec the command, if it's present */
+	if (!argv[optind])
+		return EXIT_SUCCESS;
+
+	execvp(argv[optind], &argv[optind]);
+	errexec(argv[optind]);
+}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 2/4] pipesz: add tests
       [not found] <20220412045930.236051-1-nwsharp@live.com>
  2022-04-12  4:59 ` [PATCH RFC 1/4] misc-utils: add the pipesz utility Nathan Sharp
@ 2022-04-12  4:59 ` Nathan Sharp
  2022-06-03 11:49   ` Anatoly Pugachev
  2022-04-12  4:59 ` [PATCH RFC 3/4] pipesz: add manpage Nathan Sharp
  2022-04-12  4:59 ` [PATCH RFC 4/4] pipesz: add bash-completion script Nathan Sharp
  3 siblings, 1 reply; 13+ messages in thread
From: Nathan Sharp @ 2022-04-12  4:59 UTC (permalink / raw)
  To: util-linux; +Cc: Nathan Sharp

Signed-off-by: Nathan Sharp <nwsharp@live.com>
---
 tests/commands.sh                           |  1 +
 tests/expected/misc/pipesz-exec             |  1 +
 tests/expected/misc/pipesz-get-fd           |  1 +
 tests/expected/misc/pipesz-get-fd-bad.err   |  1 +
 tests/expected/misc/pipesz-get-file         |  1 +
 tests/expected/misc/pipesz-get-file-bad.err |  1 +
 tests/expected/misc/pipesz-set-fd-bad.err   |  1 +
 tests/expected/misc/pipesz-set-file-bad.err |  1 +
 tests/ts/misc/pipesz                        | 73 +++++++++++++++++++++
 9 files changed, 81 insertions(+)
 create mode 100644 tests/expected/misc/pipesz-exec
 create mode 100644 tests/expected/misc/pipesz-get-fd
 create mode 100644 tests/expected/misc/pipesz-get-fd-bad.err
 create mode 100644 tests/expected/misc/pipesz-get-file
 create mode 100644 tests/expected/misc/pipesz-get-file-bad.err
 create mode 100644 tests/expected/misc/pipesz-set-fd-bad.err
 create mode 100644 tests/expected/misc/pipesz-set-file-bad.err
 create mode 100755 tests/ts/misc/pipesz

diff --git a/tests/commands.sh b/tests/commands.sh
index 18467cb..aff324c 100644
--- a/tests/commands.sh
+++ b/tests/commands.sh
@@ -92,6 +92,7 @@ TS_CMD_MOUNT=${TS_CMD_MOUNT:-"${ts_commandsdir}mount"}
 TS_CMD_MOUNTPOINT=${TS_CMD_MOUNTPOINT:-"${ts_commandsdir}mountpoint"}
 TS_CMD_NAMEI=${TS_CMD_NAMEI-"${ts_commandsdir}namei"}
 TS_CMD_PARTX=${TS_CMD_PARTX-"${ts_commandsdir}partx"}
+TS_CMD_PIPESZ=${TS_CMD_PIPESZ-"${ts_commandsdir}pipesz"}
 TS_CMD_RENAME=${TS_CMD_RENAME-"${ts_commandsdir}rename"}
 TS_CMD_RUNUSER=${TS_CMD_RUNUSER-"${ts_commandsdir}runuser"}
 TS_CMD_REV=${TS_CMD_REV:-"${ts_commandsdir}rev"}
diff --git a/tests/expected/misc/pipesz-exec b/tests/expected/misc/pipesz-exec
new file mode 100644
index 0000000..1c6f03b
--- /dev/null
+++ b/tests/expected/misc/pipesz-exec
@@ -0,0 +1 @@
+this_should_be_output_by_cat
diff --git a/tests/expected/misc/pipesz-get-fd b/tests/expected/misc/pipesz-get-fd
new file mode 100644
index 0000000..ef103dc
--- /dev/null
+++ b/tests/expected/misc/pipesz-get-fd
@@ -0,0 +1 @@
+fd 0	65536	0
diff --git a/tests/expected/misc/pipesz-get-fd-bad.err b/tests/expected/misc/pipesz-get-fd-bad.err
new file mode 100644
index 0000000..0394206
--- /dev/null
+++ b/tests/expected/misc/pipesz-get-fd-bad.err
@@ -0,0 +1 @@
+pipesz: cannot get pipe buffer size of fd 42: Bad file descriptor
diff --git a/tests/expected/misc/pipesz-get-file b/tests/expected/misc/pipesz-get-file
new file mode 100644
index 0000000..c1e1a9d
--- /dev/null
+++ b/tests/expected/misc/pipesz-get-file
@@ -0,0 +1 @@
+/dev/stdin	65536	0
diff --git a/tests/expected/misc/pipesz-get-file-bad.err b/tests/expected/misc/pipesz-get-file-bad.err
new file mode 100644
index 0000000..793301d
--- /dev/null
+++ b/tests/expected/misc/pipesz-get-file-bad.err
@@ -0,0 +1 @@
+pipesz: cannot get pipe buffer size of /dev/null: Bad file descriptor
diff --git a/tests/expected/misc/pipesz-set-fd-bad.err b/tests/expected/misc/pipesz-set-fd-bad.err
new file mode 100644
index 0000000..199d18c
--- /dev/null
+++ b/tests/expected/misc/pipesz-set-fd-bad.err
@@ -0,0 +1 @@
+pipesz: cannot set pipe buffer size of fd 42: Bad file descriptor
diff --git a/tests/expected/misc/pipesz-set-file-bad.err b/tests/expected/misc/pipesz-set-file-bad.err
new file mode 100644
index 0000000..f97b1f8
--- /dev/null
+++ b/tests/expected/misc/pipesz-set-file-bad.err
@@ -0,0 +1 @@
+pipesz: cannot set pipe buffer size of /dev/null: Bad file descriptor
diff --git a/tests/ts/misc/pipesz b/tests/ts/misc/pipesz
new file mode 100755
index 0000000..be5eb45
--- /dev/null
+++ b/tests/ts/misc/pipesz
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="pipesz"
+
+. $TS_TOPDIR/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_PIPESZ"
+
+ts_init_subtest "set-fd-bad"
+$TS_CMD_PIPESZ --check --set 4096 --fd 42 >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -eq 0 ]] && ts_logerr "expected failure"
+ts_finalize_subtest
+
+ts_init_subtest "set-fd"
+echo -n | $TS_CMD_PIPESZ --check --set 4096 --stdin >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -ne 0 ]] && ts_logerr "expected success"
+ts_finalize_subtest
+
+ts_init_subtest "set-file-bad"
+$TS_CMD_PIPESZ --check --set 4096 --file "/dev/null" >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -eq 0 ]] && ts_logerr "expected failure"
+ts_finalize_subtest
+
+ts_init_subtest "set-file"
+echo -n | $TS_CMD_PIPESZ --check --set 4096 --file "/dev/stdin" >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -ne 0 ]] && ts_logerr "expected success"
+ts_finalize_subtest
+
+ts_init_subtest "get-fd-bad"
+$TS_CMD_PIPESZ --check --get --fd 42 >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -eq 0 ]] && ts_logerr "expected failure"
+ts_finalize_subtest
+
+ts_init_subtest "get-fd"
+echo -n | $TS_CMD_PIPESZ --check --get --stdin >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -ne 0 ]] && ts_logerr "expected success"
+ts_finalize_subtest
+
+ts_init_subtest "get-file-bad"
+$TS_CMD_PIPESZ --check --get --file "/dev/null" >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -eq 0 ]] && ts_logerr "expected failure"
+ts_finalize_subtest
+
+ts_init_subtest "get-file"
+echo -n | $TS_CMD_PIPESZ --check --get --file "/dev/stdin" >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -ne 0 ]] && ts_logerr "expected success"
+ts_finalize_subtest
+
+ts_init_subtest "pipe-max-size"
+echo -n | $TS_CMD_PIPESZ --check --stdin >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -ne 0 ]] && ts_logerr "expected success"
+ts_finalize_subtest
+
+ts_init_subtest "exec"
+echo this_should_be_output_by_cat | $TS_CMD_PIPESZ --check --stdin cat >> $TS_OUTPUT 2>> $TS_ERRLOG
+[[ $? -ne 0 ]] && ts_logerr "expected success"
+ts_finalize_subtest
+
+ts_finalize
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 3/4] pipesz: add manpage
       [not found] <20220412045930.236051-1-nwsharp@live.com>
  2022-04-12  4:59 ` [PATCH RFC 1/4] misc-utils: add the pipesz utility Nathan Sharp
  2022-04-12  4:59 ` [PATCH RFC 2/4] pipesz: add tests Nathan Sharp
@ 2022-04-12  4:59 ` Nathan Sharp
  2022-04-12  4:59 ` [PATCH RFC 4/4] pipesz: add bash-completion script Nathan Sharp
  3 siblings, 0 replies; 13+ messages in thread
From: Nathan Sharp @ 2022-04-12  4:59 UTC (permalink / raw)
  To: util-linux; +Cc: Nathan Sharp

Signed-off-by: Nathan Sharp <nwsharp@live.com>
---
 meson.build              |   1 +
 misc-utils/Makemodule.am |   2 +
 misc-utils/pipesz.1.adoc | 109 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+)
 create mode 100644 misc-utils/pipesz.1.adoc

diff --git a/meson.build b/meson.build
index 358572e..a94b02f 100644
--- a/meson.build
+++ b/meson.build
@@ -2688,6 +2688,7 @@ exe = executable(
   install : true)
 if opt and not is_disabler(exe)
   exes += exe
+  manadocs += ['misc-utils/pipesz.1.adoc']
 endif
 
 exe = executable(
diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am
index 60c7fe1..5e08c9a 100644
--- a/misc-utils/Makemodule.am
+++ b/misc-utils/Makemodule.am
@@ -269,6 +269,8 @@ endif
 
 if BUILD_PIPESZ
 bin_PROGRAMS += pipesz
+MANPAGES += misc-utils/pipesz.1
+dist_noinst_DATA += misc-utils/pipesz.1.adoc
 pipesz_SOURCES = misc-utils/pipesz.c
 pipesz_LDADD = $(LDADD) libcommon.la
 pipesz_CFLAGS = $(AM_CFLAGS)
diff --git a/misc-utils/pipesz.1.adoc b/misc-utils/pipesz.1.adoc
new file mode 100644
index 0000000..a18d775
--- /dev/null
+++ b/misc-utils/pipesz.1.adoc
@@ -0,0 +1,109 @@
+//po4a: entry man manual
+= pipesz(1)
+:doctype: manpage
+:man manual: User Commands
+:man source: util-linux {release-version}
+:page-layout: base
+:command: pipesz
+
+== NAME
+
+pipesz - set or examine pipe and FIFO buffer sizes
+
+== SYNOPSIS
+
+*pipesz* [options] [--set _size_] [--] [_command_ [argument] ...]
+
+*pipesz* [options] --get
+
+== DESCRIPTION
+
+Pipes and FIFOs maintain an internal buffer used to transfer data between the read end and the write end. In some cases, the default size of this internal buffer may not be appropriate. This program provides facilities to set and examine the size of these buffers.
+
+The *--set* operation sets pipe buffer sizes. If it is specified, it must be specified with an explicit _size_. Otherwise, it is implied and the size is read from */proc/sys/fs/pipe-max-size*. The kernel may adjust _size_ as described in *fcntl*(2). To determine the actual buffer sizes set, use the *--verbose* option. If neither *--file* nor *--fd* are specified, *--set* acts on standard output.
+
+The *--set* operation permits an optional _command_ to execute after setting the pipe buffer sizes. This command is executed with the adjusted pipes.
+
+The *--get* operation outputs data in a tabular format. The first column is the name of the pipe as passed to *pipesz*. File descriptors are named as "fd _N_". The second column is the size, in bytes, of the pipe's internal buffer. The third column is the number of unread bytes currently in the pipe. The columns are separated by tabs ('\t', ASCII 09h). If *--verbose* is specified, a descriptive header is also emitted. If neither *--file* nor *--fd* are specified, *--get* acts on all file descriptors.
+
+Unless the *--check* option is specified, *pipesz* does _not_ exit if it encounters an error while manipulating a file or file descriptor. This allows *pipesz* to be used generically without fear of disrupting the execution of pipelines should the type of certain files be later changed. For minimal disruption, the *--quiet* option prevents warnings from being emitted in these cases.
+
+The kernel imposes limits on the amount of pipe buffer space unprivileged processes can use, though see *BUGS* below. The kernel will also refuse to shrink a pipe buffer if this would cause a loss of buffered data. See *pipe*(7) for additional details.
+
+*pipesz* supports specifying multiple short options consecutively, in the usual *getopt*(3) fashion. The first non-option argument is interpreted as _command_. If _command_ might begin with '-', use '--' to separate it from argument to *pipesz*. In shell scripts, it is good practice to use '--' when parameter expansion is involved. *pipesz* itself does not read from standard input and does not write to standard output unless *--get*, *--help*, or *--version* are specified.
+
+== OPTIONS
+
+*-g*, *--get*::
+Report the size of pipe buffers to standard output and exit. As a special behavior, if neither *--file* nor *--fd* are specified, *every* file descriptor passed to *pipesz* is examined. It is an error to specifiy this option in combination with *--set*.
+
+*-s*, *--set* _size_::
+Set the size of the pipe buffers, in bytes. This option may be suffixed by _K_, _M_, _G_, _KiB_, _MiB_, or _GiB_ to indicate multiples of 1024. Fractional values are supported in this case. Additional suffixes are supported but are unlikely to be useful. If this option is not specified, a default value is used, as described above. If this option is specified multiple times, a warning is emitted and only the last-specified value is used. It is an error to specify this option in combination with *--get*.
+
+*-f*, *--file* _path_::
+Set the buffer size of the FIFO or pipe at _path_, relative to the current working directory. You may specify this option multiple times to affect different files, and you may do so in combination with *--fd*. Generally, this option is used with FIFOs, but it will also operate on anonymous pipes such as those found in */proc/PID/fd*. Changes to the buffer size of FIFOs are not preserved across system restarts.
+
+*-n*, *--fd* _fd_::
+Set the buffer size of the pipe or FIFO passed to *pipesz* as the specified file descriptor number. You may specify this option multiple times to affect different file descriptors, and you may do so in combination with *--file*. Shorthand options are provided for the common cases of fd 0 (stdin), fd 1 (stdout), and fd 2 (stderr). These should suffice in most cases.
+
+*-i*, *--stdin*::
+Shorthand for *--fd 0*.
+
+*-o*, *--stdout*::
+Shorthand for *--fd 1*.
+
+*-e*, *--stderr*::
+Shorthand for *--fd 2*.
+
+*-c*, *--check*::
+Exit, without executing _command_, in case of any error while manipulating a file or file descriptor. The default behavior if this is not specified is to emit a warning to standard error and continue.
+
+*-q*, *--quiet*::
+Do not diagnose non-fatal errors to standard error. This option does not affect the normal output of *--get*, *--verbose*, *--help*, or *--version*.
+
+*-v*, *--verbose*::
+If specified with *--get*, *pipesz* will emit a descriptive header above the table. If specified with *--set*, *pipesz* will print the actual buffer sizes set by the kernel to standard error.
+
+include::man-common/help-version.adoc[]
+
+== EXAMPLES
+
+*pipesz* *dd* if=_file_ bs=1M | ...::
+Runs *dd*(1) with an expanded standard output pipe, allowing it to avoid context switches when piping around large blocks.
+
+*pipesz* -s1M -cf /run/my-service.fifo::
+Sets the pipe buffer size of a service FIFO to 1,048,576 bytes. If the buffer size could not be set, *pipesz* exits with an error.
+
+*echo* hello | *pipesz* -gi::
+Prints the size of pipe used by the shell to pass input to *pipesz*. Since *pipesz* does not read standard input, it may also report 6 unread bytes in the pipe, depending on relative timings.
+
+*find* /proc/_PID_/fd -exec *pipesz* -gqf '{}' ';'::
+Prints the size and number of unread bytes of all pipes in use by _PID_. If some pipes are routinely full, *pipesz* might be able to mitigate a processing bottleneck.
+
+== NOTES
+
+Linux supports adjusting the size of pipe buffers since kernel 2.6.35. This release also introduced */proc/sys/fs/pipe-max-size*.
+
+This program uses *fcntl*(2) *F_GETPIPE_SZ*/*F_SETPIPE_SZ* to get and set pipe buffer sizes.
+
+This program uses *ioctl*(2) *FIONREAD* to report the amount of unread data in pipes. If for some reason this fails, the amount of unread data is reported as 0.
+
+== BUGS
+
+Before Linux 4.9, some bugs affect how certain resource limits are enforced when setting pipe buffer sizes. See *pipe*(7) for details.
+
+== AUTHORS
+
+mailto:nwsharp@live.com[Nathan Sharp]
+
+== SEE ALSO
+
+*pipe*(7)
+
+include::man-common/bugreports.adoc[]
+
+include::man-common/footer.adoc[]
+
+ifdef::translation[]
+include::man-common/translation.adoc[]
+endif::[]
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH RFC 4/4] pipesz: add bash-completion script
       [not found] <20220412045930.236051-1-nwsharp@live.com>
                   ` (2 preceding siblings ...)
  2022-04-12  4:59 ` [PATCH RFC 3/4] pipesz: add manpage Nathan Sharp
@ 2022-04-12  4:59 ` Nathan Sharp
  3 siblings, 0 replies; 13+ messages in thread
From: Nathan Sharp @ 2022-04-12  4:59 UTC (permalink / raw)
  To: util-linux; +Cc: Nathan Sharp

Signed-off-by: Nathan Sharp <nwsharp@live.com>
---
 bash-completion/Makemodule.am |   3 +
 bash-completion/pipesz        | 102 ++++++++++++++++++++++++++++++++++
 meson.build                   |   1 +
 3 files changed, 106 insertions(+)
 create mode 100644 bash-completion/pipesz

diff --git a/bash-completion/Makemodule.am b/bash-completion/Makemodule.am
index f852114..5d59b55 100644
--- a/bash-completion/Makemodule.am
+++ b/bash-completion/Makemodule.am
@@ -335,5 +335,8 @@ endif
 if BUILD_HARDLINK
 dist_bashcompletion_DATA += bash-completion/hardlink
 endif
+if BUILD_PIPESZ
+dist_bashcompletion_DATA += bash-completion/pipesz
+endif
 
 endif # BUILD_BASH_COMPLETION
diff --git a/bash-completion/pipesz b/bash-completion/pipesz
new file mode 100644
index 0000000..592075c
--- /dev/null
+++ b/bash-completion/pipesz
@@ -0,0 +1,102 @@
+_pipesz_module()
+{
+	local WORD OPTS OPTARG OPTEND SOPT LOPT TARG
+	local SOPTS=(g s f n i o e c q v h V)
+	local LOPTS=(get set file fd stdin stdout stderr check quiet verbose help version)
+	local AOPTS=(0 1 1 1 0 0 0 0 0 0 0 0) # takes argument
+	local TOPTS=(1 0 1 1 1 1 1 0 0 0 0 0) # specifies target
+	local XOPTS=(0 0 0 0 0 0 0 0 0 0 1 1) # exits immediately
+	local MOPTS=(0 0 1 1 0 0 0 0 0 0 0 0) # repeatable
+	local NOPTS=(0 0 0 0 0 0 0 0 0 0 0 0) # number of repeats
+	local IDXG=0 IDXS=1                   # index of --get and --set
+
+	for ((i=1; i<COMP_CWORD; i++)); do
+		WORD=${COMP_WORDS[i]}
+
+		if [[ ${NOPTS[$IDXG]} -eq 0 ]]; then
+			case $WORD in
+				--)
+					_command_offset $((i+1))
+					return 0;;
+				[^-]*)
+					_command_offset $i
+					return 0;;
+			esac
+		fi
+
+		for ((j=0; j<${#NOPTS[@]}; j++)); do
+			SOPT=${SOPTS[$j]}
+			LOPT=${LOPTS[$j]}
+
+			case $WORD in
+				--$LOPT) OPTEND=l;;
+				--*) continue;;
+				-*$SOPT) OPTEND=s;;
+				-*$SOPT*) OPTEND=n;;
+				*) continue;;
+			esac
+
+			if [[ ${XOPTS[$j]} -ne 0 ]]; then
+				COMPREPLY=()
+				return 0
+			fi
+
+			((NOPTS[j]++))
+
+			[[ ${TOPTS[$j]} -ne 0 ]] && TARG=y
+			[[ $OPTEND != n ]] && ((i+=AOPTS[j]))
+			[[ $OPTEND == l ]] && break
+		done
+	done
+
+	case $3 in
+		--fd) OPTARG=n;;
+		--file) OPTARG=f;;
+		--size) OPTARG=s;;
+		--*) ;;
+		-*n) OPTARG=n;;
+		-*f) OPTARG=f;;
+		-*s) OPTARG=s;;
+	esac
+
+	case $OPTARG in
+		f)
+			compopt -o filenames
+			COMPREPLY=( $(compgen -f -- "$2") )
+			return 0;;
+		n)
+			COMPREPLY=( $(compgen -W "0 1 2" -- "$2") )
+			return 0;;
+		s)
+			WORD=$2
+			if [[ ! $WORD =~ ^[0-9]+[a-zA-Z]*$ ]]; then
+				COMPREPLY=()
+				return 0
+			fi
+
+			while [[ $WORD =~ [a-zA-Z]$ ]]; do WORD=${WORD:0:-1}; done
+
+			compopt -o nosort
+			COMPREPLY=( $(compgen -W "$WORD $WORD{K,M,G}{B,iB}" -- "$2") )
+			return 0;;
+	esac
+
+	for ((j=0; j<${#NOPTS[@]}; j++)); do
+		[[ $j -eq $IDXG && ${NOPTS[$IDXS]} -ne 0 ]] && continue
+		[[ $j -eq $IDXS && ${NOPTS[$IDXG]} -ne 0 ]] && continue
+		[[ $COMP_CWORD -ne 1 && ${XOPTS[$j]} -ne 0 ]] && continue
+		[[ ${NOPTS[$j]} -gt 0 && ${MOPTS[$j]} -eq 0 ]] && continue
+
+		[[ $2 != --* && $2 == -* ]] && OPTS+=" -${SOPTS[$j]}"
+		OPTS+=" --${LOPTS[$j]}"
+	done
+
+	if [[ ! $TARG || ${NOPTS[$IDXG]} -ne 0 ]]; then
+		COMPREPLY=( $(compgen -W "$OPTS" -- "$2") )
+	else
+		compopt -o filenames
+		COMPREPLY=( $(compgen -c -W "$OPTS --" -- "$2") )
+	fi
+}
+
+complete -F _pipesz_module pipesz
diff --git a/meson.build b/meson.build
index a94b02f..58b8ea6 100644
--- a/meson.build
+++ b/meson.build
@@ -2689,6 +2689,7 @@ exe = executable(
 if opt and not is_disabler(exe)
   exes += exe
   manadocs += ['misc-utils/pipesz.1.adoc']
+  bashcompletions += ['pipesz']
 endif
 
 exe = executable(
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 1/4] misc-utils: add the pipesz utility
  2022-04-12  4:59 ` [PATCH RFC 1/4] misc-utils: add the pipesz utility Nathan Sharp
@ 2022-05-04 10:50   ` Karel Zak
  2022-05-06  2:58     ` Nathan Sharp
  0 siblings, 1 reply; 13+ messages in thread
From: Karel Zak @ 2022-05-04 10:50 UTC (permalink / raw)
  To: Nathan Sharp; +Cc: util-linux

On Mon, Apr 11, 2022 at 10:59:27PM -0600, Nathan Sharp wrote:
>  .gitignore               |   1 +
>  configure.ac             |   8 +
>  include/pathnames.h      |   4 +
>  meson.build              |  12 ++
>  meson_options.txt        |   2 +
>  misc-utils/Makemodule.am |   7 +
>  misc-utils/meson.build   |   4 +
>  misc-utils/pipesz.c      | 347 +++++++++++++++++++++++++++++++++++++++
>  8 files changed, 385 insertions(+)
>  create mode 100644 misc-utils/pipesz.c

I had time to review it finally (sorry for delay). 

> +static void __attribute__((__noreturn__)) usage(void)
> +{
> +	fputs(USAGE_HEADER, stdout);
> +	printf(_(" %s [options] [--set <size>] [--] [command]\n"), program_invocation_short_name);
> +	printf(_(" %s [options] --get\n"), program_invocation_short_name);
> +
> +	fputs(USAGE_SEPARATOR, stdout);
> +	/* TRANSLATORS: 'command' refers to a program argument */
> +	puts(_("Set or examine pipe buffer sizes and optionally execute command."));
> +
> +	fputs(USAGE_OPTIONS, stdout);
> +	puts(_(" -g, --get          examine pipe buffers"));
> +	/* TRANSLATORS: '%s' refers to a system file */
> +	printf(_(" -s, --set <size>  set pipe buffer sizes\n"
> +		"                      size defaults to %s\n"
> +	), PIPESZ_DEFAULT_SIZE_FILE);
> +
> +	fputs(USAGE_SEPARATOR, stdout);
> +	puts(_(" -f, --file <path>  act on a file"));
> +	puts(_(" -n, --fd <num>     act on a file descriptor"));
> +	puts(_(" -i, --stdin        act on standard input"));
> +	puts(_(" -o, --stdout       act on standard output"));
> +	puts(_(" -e, --stderr       act on standard error"));
> +
> +	fputs(USAGE_SEPARATOR, stdout);
> +	puts(_(" -c, --check        do not continue after an error"));

Would be better to be paranoid (as expected by --check) by default and
implement --force for cases when user wants something crazy? That's
usual way utils are implemented.

...

> +	/* check for --help or --version */
> +	while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1)
> +		switch (c) {
> +		case 'h':
> +			usage();
> +		case 'V':
> +			print_version(EXIT_SUCCESS);
> +		}

Why we need multiple getopt_long() blocks? I guess --help and
--version could be together with other options. This is very unusual.

> +	/* gather normal options */
> +	optind = 1;
> +	while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
> +		err_exclusive_options(c, longopts, excl, excl_st);
> +
> +		switch (c) {
> +		case 'c':
> +			opt_check = TRUE;
> +			break;
> +		case 'e':
> +			++n_opt_pipe;
> +			break;
> +		case 'f':
> +			++n_opt_pipe;
> +			break;
> +		case 'g':
> +			opt_get = TRUE;
> +			break;
> +		case 'i':
> +			++n_opt_pipe;
> +			break;
> +		case 'n':
> +			fd = strtos32_or_err(optarg, _("invalid fd argument"));
> +			++n_opt_pipe;
> +			break;
> +		case 'o':
> +			++n_opt_pipe;
> +			break;
> +		case 'q':
> +			opt_quiet = TRUE;
> +			break;
> +		case 's':
> +			sz = strtosize_or_err(optarg, _("invalid size argument"));
> +			opt_size = sz >= INT_MAX ? INT_MAX : (int)sz;
> +			break;
> +		case 'v':
> +			opt_verbose = TRUE;
> +			break;
> +		default:
> +			errtryhelp(EXIT_FAILURE);
> +		}
> +	}

...

> +	/* go through the arguments again and do the requested operations */
> +	optind = 1;
> +	while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1)
> +		switch (c) {
> +		case 'e':
> +			do_fd(STDERR_FILENO);
> +			break;
> +		case 'f':
> +			do_file(optarg);
> +			break;
> +		case 'i':
> +			do_fd(STDIN_FILENO);
> +			break;
> +		case 'n':
> +			/* optarg was checked before, but it's best to be safe */
> +			fd = strtos32_or_err(optarg, _("invalid fd argument"));
> +			do_fd(fd);
> +			break;
> +		case 'o':
> +			do_fd(STDOUT_FILENO);
> +			break;
> +		}

... and another getopt_long() block.


What about to define

enum {
    PIPESZ_ON_STDERR = (1 << 1),
    PIPESZ_ON_STDIN  = (1 << 2),
    PIPESZ_ON_STDOUT = (1 << 3),
    PIPESZ_ON_FILE   = (1 << 4),
    PIPESZ_ON_FD     = (1 << 5)
};

and in the while (getopt_long()) block set operation |= PIPESZ_ON_xxxxx and
later in code use it? (also with variables 'filename' and 'fd'.

Then you can keep all arguments parsing on one place, right? :-)

The rest seems good.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 1/4] misc-utils: add the pipesz utility
  2022-05-04 10:50   ` Karel Zak
@ 2022-05-06  2:58     ` Nathan Sharp
  2022-05-18  9:04       ` Karel Zak
  0 siblings, 1 reply; 13+ messages in thread
From: Nathan Sharp @ 2022-05-06  2:58 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux

Thank you for your review, Karel! I appreciate all of your feedback.

> Would be better to be paranoid (as expected by --check) by default and implement --force for cases when user wants something crazy?

The manpage talks a bit about this. pipesz is designed to be opportunistic by default in order to avoid annoying users that are troubleshooting their pipelines.

For example, when I'm working on a script, I'll often need to cut it up into parts and dump intermediate data to the terminal or to a file. So, if I start with a script like "a | pipesz b | c | d" and realize that there's some problem with "b" I might end up running "a | pipesz b" at my terminal or commenting out the "| c | d". If pipesz weren't lenient, it'd spit out an error because stdout is now a tty. So now I've got two annoyances, "b" is broken *and*​ pipesz is whining. Incidentally, this is how pipesz was originally. I did not like it.

There's another more subtle reason, too. I don't think that failure to resize a pipe is a reason to make scripts suddenly stop working. If your box is low on memory or you're near pipe-user-pages-soft, you'd probably want to ignore the fact you can't get 1 meg for a pipe right now and just have your script run. If you really, really care that you've got your pipes and ttys and files and sockets and resource limits straight, that's what --check is for. I think that forgetting to specify --force is a footgun just waiting to take down an overnight batch job.

If you don't find this argument persuasive, I'll switch the sense of --check/-c to --ignore/-t (like ionice, since -i is taken), as requested. I find --force misleading, but I recognize it is long-standing convention and will do this instead of --ignore/-t if you insist.

> Why we need multiple getopt_long() blocks?

I had a feeling this would come up. I should have talked about this in the cover letter. I had a single argument processing loop originally, but in the end I felt that it was not worth the trade-offs involved.

In my mind there were 5 implementation strategies I could choose:

(1) Require -c/-g/-q/-v to precede other arguments, so we have all the information we need to process the other options immediately. This is not viable for a number of reasons that should become apparent quickly.
(2) Squirrel away -f/-n arguments into a liked list or xrealloc'ing arrays. This adds manual memory management, bookkeeping to keep valgrind happy on exit(), and an OOM failure case. I chose a list, and it ended up being about 1/3 of the total code using "list.h" and "xalloc.h".
(3) Squirrel away -f/-n arguments in fixed-sized arrays. This introduces a very small amount of bookkeeping, but also a bizarre failure mode should someone try to have too much fun with, e.g., xargs. Also, it would end up changing the order of operations unless done in a more complicated way.
(4) Only allow a single -f/-n argument (perhaps in addition to -i/-o/-e). I believe this is what you proposed. This could lead to some annoying repetitiveness in some cases. Additionally, it would complicate documentation if we permitted combining -f/-n with -i/-o/-e. Or lead to even more stuttering if we went for maximum simplicity and took only one of -f/-n/-i/-o/-e.
(5) Scan the argument list multiple times. The downside here is that's its unconventional. Heretical, even!

You caught on to this, but options 1-4 also annoy people like me who respond to invocation errors with "[up arrow] --help" instead of using readline shortcuts or shell history expansion.

Of the options above, excepting 5 of course, I lean heavily towards 4.

> The rest seems good.

Thank you! Let me know what changes you'd like to see and I'll whip up a v2!

Best wishes,
    - Nathan Sharp

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 1/4] misc-utils: add the pipesz utility
  2022-05-06  2:58     ` Nathan Sharp
@ 2022-05-18  9:04       ` Karel Zak
  0 siblings, 0 replies; 13+ messages in thread
From: Karel Zak @ 2022-05-18  9:04 UTC (permalink / raw)
  To: Nathan Sharp; +Cc: util-linux

On Fri, May 06, 2022 at 02:58:07AM +0000, Nathan Sharp wrote:
> Thank you! Let me know what changes you'd like to see and I'll whip up a v2!

Applied, thanks. Unexpected :-), but you have convinced me that more
getopt_long() is better than allocating extra stuff for such simple
util like pipesz :-)

You should contribute more often; I like your perfectionism (man
pages, meson, bash-completion, ...) :-)

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH RFC 2/4] pipesz: add tests
  2022-04-12  4:59 ` [PATCH RFC 2/4] pipesz: add tests Nathan Sharp
@ 2022-06-03 11:49   ` Anatoly Pugachev
  2022-06-04  2:00     ` [PATCH] pipesz: use native PAGE_SIZE in tests Nathan Sharp
  0 siblings, 1 reply; 13+ messages in thread
From: Anatoly Pugachev @ 2022-06-03 11:49 UTC (permalink / raw)
  To: Nathan Sharp; +Cc: util-linux

Nathan,

at least 2 of those tests is not BE (big-endian) friendly:

mator@gcc203:~/util-linux.git/tests$ ./run.sh misc/pipesz

-------------------- util-linux regression tests --------------------

                    For development purpose only.
                 Don't execute on production system!

       kernel: 5.15.0-2-powerpc64

      options: --srcdir=/home/mator/util-linux.git/tests/.. \
               --builddir=/home/mator/util-linux.git/tests/..

         misc: pipesz                         ...
                : set-fd-bad                  ... OK
                : set-fd                      ... OK
                : set-file-bad                ... OK
                : set-file                    ... OK
                : get-fd-bad                  ... OK
                : get-fd                      ... FAILED (misc/pipesz-get-fd)
                : get-file-bad                ... OK
                : get-file                    ... FAILED (misc/pipesz-get-file)
                : pipe-max-size               ... OK
                : exec                        ... OK
           ... FAILED (2 from 10 sub-tests)

---------------------------------------------------------------------
  1 tests of 1 FAILED

      misc/pipesz
---------------------------------------------------------------------

running on a sparc64 (gcc202) and on powerpc64 (gcc203) machines :

gcc202:~/util-linux$ echo -n | ./pipesz --check --get --stdin
fd 0    131072  0

gcc203:~/util-linux.git$ echo -n | ./pipesz --check --get --stdin
fd 0    1048576 0


So on x86_64 tests expect stdin file to be 64Kb:
gcc202:~/util-linux$ cat tests/expected/misc/pipesz-get-file
/dev/stdin      65536   0
but on sparc64 it is 128Kb and on powerpc64 it is 1Mb...

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] pipesz: use native PAGE_SIZE in tests
  2022-06-03 11:49   ` Anatoly Pugachev
@ 2022-06-04  2:00     ` Nathan Sharp
  2022-06-04  8:16       ` Anatoly Pugachev
                         ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Nathan Sharp @ 2022-06-04  2:00 UTC (permalink / raw)
  To: util-linux; +Cc: Anatoly Pugachev

Reported-by: Anatoly Pugachev <matorola@gmail.com>
Signed-off-by: Nathan Sharp <nwsharp@live.com>
---
 tests/expected/misc/pipesz-get-fd   |  2 +-
 tests/expected/misc/pipesz-get-file |  2 +-
 tests/ts/misc/pipesz                | 10 ++++++++--
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/tests/expected/misc/pipesz-get-fd b/tests/expected/misc/pipesz-get-fd
index ef103dc9d..aa4cab188 100644
--- a/tests/expected/misc/pipesz-get-fd
+++ b/tests/expected/misc/pipesz-get-fd
@@ -1 +1 @@
-fd 0	65536	0
+fd 0	DEFAULT_PIPE_SIZE	0
diff --git a/tests/expected/misc/pipesz-get-file b/tests/expected/misc/pipesz-get-file
index c1e1a9d78..32dc6bd1d 100644
--- a/tests/expected/misc/pipesz-get-file
+++ b/tests/expected/misc/pipesz-get-file
@@ -1 +1 @@
-/dev/stdin	65536	0
+/dev/stdin	DEFAULT_PIPE_SIZE	0
diff --git a/tests/ts/misc/pipesz b/tests/ts/misc/pipesz
index be5eb45e6..25724cd4c 100755
--- a/tests/ts/misc/pipesz
+++ b/tests/ts/misc/pipesz
@@ -18,6 +18,10 @@ TS_DESC="pipesz"
 . $TS_TOPDIR/functions.sh
 ts_init "$*"
 
+set -o pipefail
+
+DEFAULT_PIPE_SIZE=$(($(getconf PAGE_SIZE) * 16))
+
 ts_check_test_command "$TS_CMD_PIPESZ"
 
 ts_init_subtest "set-fd-bad"
@@ -46,7 +50,7 @@ $TS_CMD_PIPESZ --check --get --fd 42 >> $TS_OUTPUT 2>> $TS_ERRLOG
 ts_finalize_subtest
 
 ts_init_subtest "get-fd"
-echo -n | $TS_CMD_PIPESZ --check --get --stdin >> $TS_OUTPUT 2>> $TS_ERRLOG
+echo -n | $TS_CMD_PIPESZ --check --get --stdin 2>> $TS_ERRLOG | sed "s/$DEFAULT_PIPE_SIZE/DEFAULT_PIPE_SIZE/g" >> $TS_OUTPUT
 [[ $? -ne 0 ]] && ts_logerr "expected success"
 ts_finalize_subtest
 
@@ -56,7 +60,7 @@ $TS_CMD_PIPESZ --check --get --file "/dev/null" >> $TS_OUTPUT 2>> $TS_ERRLOG
 ts_finalize_subtest
 
 ts_init_subtest "get-file"
-echo -n | $TS_CMD_PIPESZ --check --get --file "/dev/stdin" >> $TS_OUTPUT 2>> $TS_ERRLOG
+echo -n | $TS_CMD_PIPESZ --check --get --file "/dev/stdin" 2>> $TS_ERRLOG | sed "s/$DEFAULT_PIPE_SIZE/DEFAULT_PIPE_SIZE/g" >> $TS_OUTPUT
 [[ $? -ne 0 ]] && ts_logerr "expected success"
 ts_finalize_subtest
 
@@ -70,4 +74,6 @@ echo this_should_be_output_by_cat | $TS_CMD_PIPESZ --check --stdin cat >> $TS_OU
 [[ $? -ne 0 ]] && ts_logerr "expected success"
 ts_finalize_subtest
 
+set +o pipefail
+
 ts_finalize
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] pipesz: use native PAGE_SIZE in tests
  2022-06-04  2:00     ` [PATCH] pipesz: use native PAGE_SIZE in tests Nathan Sharp
@ 2022-06-04  8:16       ` Anatoly Pugachev
  2022-06-04  8:28       ` Anatoly Pugachev
  2022-06-06 10:24       ` Karel Zak
  2 siblings, 0 replies; 13+ messages in thread
From: Anatoly Pugachev @ 2022-06-04  8:16 UTC (permalink / raw)
  To: Nathan Sharp; +Cc: util-linux

On Sat, Jun 4, 2022 at 5:00 AM Nathan Sharp <nwsharp@live.com> wrote:
>
> Reported-by: Anatoly Pugachev <matorola@gmail.com>
> Signed-off-by: Nathan Sharp <nwsharp@live.com>
> ---
>  tests/expected/misc/pipesz-get-fd   |  2 +-
>  tests/expected/misc/pipesz-get-file |  2 +-
>  tests/ts/misc/pipesz                | 10 ++++++++--
>  3 files changed, 10 insertions(+), 4 deletions(-)


Thanks. This one fixes the issue.
(tested on both sparc64 and powerpc64)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] pipesz: use native PAGE_SIZE in tests
  2022-06-04  2:00     ` [PATCH] pipesz: use native PAGE_SIZE in tests Nathan Sharp
  2022-06-04  8:16       ` Anatoly Pugachev
@ 2022-06-04  8:28       ` Anatoly Pugachev
  2022-06-06 10:24         ` Karel Zak
  2022-06-06 10:24       ` Karel Zak
  2 siblings, 1 reply; 13+ messages in thread
From: Anatoly Pugachev @ 2022-06-04  8:28 UTC (permalink / raw)
  To: Nathan Sharp; +Cc: util-linux

On Sat, Jun 4, 2022 at 5:00 AM Nathan Sharp <nwsharp@live.com> wrote:
> Reported-by: Anatoly Pugachev <matorola@gmail.com>
> --- a/tests/ts/misc/pipesz
> +++ b/tests/ts/misc/pipesz
> @@ -18,6 +18,10 @@ TS_DESC="pipesz"
>  . $TS_TOPDIR/functions.sh
>  ts_init "$*"
>
> +set -o pipefail
> +
> +DEFAULT_PIPE_SIZE=$(($(getconf PAGE_SIZE) * 16))

DEFAULT_PIPE_SIZE=$(($($TS_HELPER_SYSINFO pagesize) * 16))

to be consistent with other tests

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] pipesz: use native PAGE_SIZE in tests
  2022-06-04  2:00     ` [PATCH] pipesz: use native PAGE_SIZE in tests Nathan Sharp
  2022-06-04  8:16       ` Anatoly Pugachev
  2022-06-04  8:28       ` Anatoly Pugachev
@ 2022-06-06 10:24       ` Karel Zak
  2 siblings, 0 replies; 13+ messages in thread
From: Karel Zak @ 2022-06-06 10:24 UTC (permalink / raw)
  To: Nathan Sharp; +Cc: util-linux, Anatoly Pugachev

On Fri, Jun 03, 2022 at 08:00:22PM -0600, Nathan Sharp wrote:
>  tests/expected/misc/pipesz-get-fd   |  2 +-
>  tests/expected/misc/pipesz-get-file |  2 +-
>  tests/ts/misc/pipesz                | 10 ++++++++--
>  3 files changed, 10 insertions(+), 4 deletions(-)

Applied, thanks.

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] pipesz: use native PAGE_SIZE in tests
  2022-06-04  8:28       ` Anatoly Pugachev
@ 2022-06-06 10:24         ` Karel Zak
  0 siblings, 0 replies; 13+ messages in thread
From: Karel Zak @ 2022-06-06 10:24 UTC (permalink / raw)
  To: Anatoly Pugachev; +Cc: Nathan Sharp, util-linux

On Sat, Jun 04, 2022 at 11:28:08AM +0300, Anatoly Pugachev wrote:
> On Sat, Jun 4, 2022 at 5:00 AM Nathan Sharp <nwsharp@live.com> wrote:
> > Reported-by: Anatoly Pugachev <matorola@gmail.com>
> > --- a/tests/ts/misc/pipesz
> > +++ b/tests/ts/misc/pipesz
> > @@ -18,6 +18,10 @@ TS_DESC="pipesz"
> >  . $TS_TOPDIR/functions.sh
> >  ts_init "$*"
> >
> > +set -o pipefail
> > +
> > +DEFAULT_PIPE_SIZE=$(($(getconf PAGE_SIZE) * 16))
> 
> DEFAULT_PIPE_SIZE=$(($($TS_HELPER_SYSINFO pagesize) * 16))
> 
> to be consistent with other tests

 Fixed.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-06-06 10:25 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20220412045930.236051-1-nwsharp@live.com>
2022-04-12  4:59 ` [PATCH RFC 1/4] misc-utils: add the pipesz utility Nathan Sharp
2022-05-04 10:50   ` Karel Zak
2022-05-06  2:58     ` Nathan Sharp
2022-05-18  9:04       ` Karel Zak
2022-04-12  4:59 ` [PATCH RFC 2/4] pipesz: add tests Nathan Sharp
2022-06-03 11:49   ` Anatoly Pugachev
2022-06-04  2:00     ` [PATCH] pipesz: use native PAGE_SIZE in tests Nathan Sharp
2022-06-04  8:16       ` Anatoly Pugachev
2022-06-04  8:28       ` Anatoly Pugachev
2022-06-06 10:24         ` Karel Zak
2022-06-06 10:24       ` Karel Zak
2022-04-12  4:59 ` [PATCH RFC 3/4] pipesz: add manpage Nathan Sharp
2022-04-12  4:59 ` [PATCH RFC 4/4] pipesz: add bash-completion script Nathan Sharp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).