Re: [PATCH] eventfd: new command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Please find a little review of the code.

Le jeudi 19 août 2010 à 18:46 +0300, Alexander Shishkin a écrit :
> This is a new utility that makes it possible and easy to make use of
> eventfd(2) IPC mechanism in shell scripts. It can be used for signalling
> between userspace processes and userspace and kernel (currently, cgroup
> notifications use this).

> diff --git a/configure.ac b/configure.ac
> index eaa5945..533c05c 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -673,6 +673,8 @@ dnl unshare could be available as libc function or as syscall only
>  UTIL_CHECK_SYSCALL([unshare])
>  AC_CHECK_FUNCS([unshare])
>  
> +AC_CHECK_FUNCS([eventfd])
> +

You should add a check for <sys/eventfd.h> too.

> diff --git a/sys-utils/eventfd.c b/sys-utils/eventfd.c
> new file mode 100644
> index 0000000..42f1522
> --- /dev/null
> +++ b/sys-utils/eventfd.c
> +

> +#define strtoeventfd(x)					\

What is "x" parameter ?

> +	({ sizeof(long) == 4				\
> +			? strtoull(optarg, NULL, 10)	\
> +			: strtoul(optarg, NULL, 10); })
> +

Why not using strtoull() in all cases, since this macro is used to read
a uint64_t ?

> +static void watcher(int fd, const char *cmd)
> +{
> +	struct pollfd fds = { .fd = fd, .events = POLLIN };
> +
> +	while (poll(&fds, 1, -1) > 0) {
> +		uint64_t efdval;
> +		size_t len;

len should be ssize_t 

> +		char s[BUFSIZ];
> +
> +		len = read(fd, &efdval, sizeof efdval);
> +		if (len != sizeof(uint64_t)) {

Be consistent: use either sizeof(uint64_t) or sizeof efdval

> +			perror(_("short read from eventfd"));
> +			exit(EXIT_FAILURE);
> +		}
> +
> +		snprintf(s, BUFSIZ, "%lu", efdval);

%lu could not be used to format an uint64_t (without a cast at least).

> +
> +		setenv("__EVENTFDVAL", s, 1);
> +		system(cmd);
> +	}
> +
> +	fprintf(stderr, _("eventfd poll failed\n"));

Use perror() here too.

> +}
> +
> +static pid_t watcher_pid = -1;
> +
> +static void watcher_start(int fd, char *watchcmd)
> +{
> +	watcher_pid = fork();
> +
> +	if (watcher_pid < 0) {
> +		perror(_("fork failed"));
> +		exit(EXIT_FAILURE);
> +	} else if (!watcher_pid)
> +		watcher(fd, watchcmd);
> +}
> +
> +/* Quis custodiet ipsos custodes? */

In english

> +static void watcher_reap(void)
> +{
> +	if (watcher_pid <= 0)
> +		return;
> +
> +	kill(watcher_pid, SIGTERM);
> +	while (waitpid(watcher_pid, NULL, 0) != watcher_pid)
> +		;
> +}
> +
> +static int writer(char *varname, uint64_t echoval)
> +{
> +	char *fdstr = getenv(varname);
> +	int fd;
> +	ssize_t len;
> +
> +	if (!fdstr) {
> +		fprintf(stderr, _("$%s is empty\n"), varname);
> +		return EXIT_FAILURE;
> +	}
> +
> +	fd = atoi(fdstr);

Check fdstr content. You could also use strtol here.

> +	len = write(fd, &echoval, 8);

8 ... use sizeof(uint64_t)

> +	if (len == -1) {
> +		perror(_("write failed"));
> +		return EXIT_FAILURE;
> +	}
> +
> +	return EXIT_SUCCESS;
> +}
> +
> +static const struct option options[] = {
> +	{ "nofork",	0, 0, 'F' },
> +	{ "echo",	1, 0, 'e' },
> +	{ "varname",	1, 0, 'n' },
> +	{ "watchcmd",	1, 0, 'w' },
> +	{ "init",	1, 0, 'i' },
> +	{ "help",	0, 0, 'h' },
> +	{ NULL,		0, 0, 0   },
> +};
> +
> +static const char *optdescs[] = {
> +	"exec the main process without forking",
> +	"echo a number into eventfd",
> +	"eventfd variable name",
> +	"command to launch upon signal arrival",
> +	"initial value of the eventfd counter",
> +	"print help message"
> +};
> +
> +static void usage(int exitcode)
> +{
> +	int i;
> +
> +	printf(_("usage: %s [OPTIONS] <program> ...\n\n"
> +		 "Create, write and poll eventfds.\nOPTIONS:\n"),
> +		program_invocation_short_name);
> +	for (i = 0; options[i].name; i++)
> +		printf("  -%c, --%-10s %s\n", options[i].val, options[i].name,
> +		       _(optdescs[i]));
> +
> +	exit(exitcode);
> +}
> +
> +static const char optstr[] = "Fe:n:w:i:h";
> +
> +int main(int argc, char *argv[])
> +{
> +	uint64_t echoval = 0;
> +	unsigned int initval = 0;
> +	int fd, c, loptidx, nofork = 0;
> +	char *varname = "EVENTFD";
> +	char val[BUFSIZ];
> +	char **nargv;
> +	char *watchcmd = NULL;
> +
> +	for (;;) {
> +		c = getopt_long(argc, argv, optstr, options, NULL);
> +		if (c == -1)
> +			break;
> +
> +		switch (c) {
> +			case 'e':
> +				echoval = strtoeventfd(optarg);
> +				break;
> +			case 'i':
> +				initval = strtoul(optarg, NULL, 10);
> +				break;
> +			case 'n':
> +				varname = strdup(optarg);
> +				break;
> +			case 'F':
> +				nofork++;
> +				break;
> +			case 'w':
> +				watchcmd = strdup(optarg);
> +				break;
> +			case 'h':
> +				usage(EXIT_SUCCESS);
> +			default:
> +				usage(EXIT_FAILURE);
> +		}
> +	}

Could you check strtoul{l}() return in order to catch error in
argument ?

> +
> +	if (echoval)
> +		return writer(varname, echoval);
> +

So this is impossible to echo the value 0 ?


Regards

-- 
Yann Droneaud



--
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux