public inbox for ltp@lists.linux.it
 help / color / mirror / Atom feed
From: Cyril Hrubis <chrubis@suse.cz>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH v5 1/7] API: Add safe openat, printfat, readat and unlinkat
Date: Fri, 30 Apr 2021 16:22:53 +0200	[thread overview]
Message-ID: <YIwSvc/KY0AX9Yeb@yuki> (raw)
In-Reply-To: <20210430112649.16302-2-rpalethorpe@suse.com>

Hi!
> Add 'at' variants for a number of system calls and LTP SAFE API
> functions. This avoids using sprintf everywhere to build paths.
> 
> Also adds tst_decode_fd which allows us to retrieve the path for an FD
> for debugging purposes without having to store it ourselves. However
> the proc symlink may not be available on some systems.
> 
> Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
> Reviewed-by: Petr Vorel <pvorel@suse.cz>
> ---
>  include/tst_safe_file_at.h |  51 +++++++++++
>  lib/tst_safe_file_at.c     | 176 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 227 insertions(+)
>  create mode 100644 include/tst_safe_file_at.h
>  create mode 100644 lib/tst_safe_file_at.c
> 
> diff --git a/include/tst_safe_file_at.h b/include/tst_safe_file_at.h
> new file mode 100644
> index 000000000..fbb63b4a8
> --- /dev/null
> +++ b/include/tst_safe_file_at.h
> @@ -0,0 +1,51 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2021 SUSE LLC <rpalethorpe@suse.com>
> + */
> +
> +#ifndef TST_SAFE_FILE_AT_H
> +#define TST_SAFE_FILE_AT_H
> +
> +#include <sys/types.h>
> +#include <stdarg.h>
> +
> +#define SAFE_OPENAT(dirfd, path, oflags, ...)			\
> +	safe_openat(__FILE__, __LINE__,				\
> +		    (dirfd), (path), (oflags), ## __VA_ARGS__)
> +
> +#define SAFE_FILE_READAT(dirfd, path, buf, nbyte)			\
> +	safe_file_readat(__FILE__, __LINE__,				\
> +			 (dirfd), (path), (buf), (nbyte))
> +
> +
> +#define SAFE_FILE_PRINTFAT(dirfd, path, fmt, ...)			\
> +	safe_file_printfat(__FILE__, __LINE__,				\
> +			   (dirfd), (path), (fmt), __VA_ARGS__)
> +
> +#define SAFE_UNLINKAT(dirfd, path, flags)				\
> +	safe_unlinkat(__FILE__, __LINE__, (dirfd), (path), (flags))
> +
> +char *tst_decode_fd(int fd);
> +
> +int safe_openat(const char *file, const int lineno,
> +		int dirfd, const char *path, int oflags, ...);
> +
> +ssize_t safe_file_readat(const char *file, const int lineno,
> +			 int dirfd, const char *path, char *buf, size_t nbyte);
> +
> +int tst_file_vprintfat(int dirfd, const char *path, const char *fmt, va_list va);
> +int tst_file_printfat(int dirfd, const char *path, const char *fmt, ...)
> +			__attribute__ ((format (printf, 3, 4)));
> +
> +int safe_file_vprintfat(const char *file, const int lineno,
> +			int dirfd, const char *path,
> +			const char *fmt, va_list va);
> +
> +int safe_file_printfat(const char *file, const int lineno,
> +		       int dirfd, const char *path, const char *fmt, ...)
> +			__attribute__ ((format (printf, 5, 6)));
> +
> +int safe_unlinkat(const char *file, const int lineno,
> +		  int dirfd, const char *path, int flags);
> +
> +#endif
> diff --git a/lib/tst_safe_file_at.c b/lib/tst_safe_file_at.c
> new file mode 100644
> index 000000000..43372998e
> --- /dev/null
> +++ b/lib/tst_safe_file_at.c
> @@ -0,0 +1,176 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2021 SUSE LLC <rpalethorpe@suse.com>
> + */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include "lapi/fcntl.h"
> +#include "tst_safe_file_at.h"
> +
> +#define TST_NO_DEFAULT_MAIN
> +#include "tst_test.h"
> +
> +char fd_path[PATH_MAX];

^
static otherwise the symbol will end up exported in the object file

> +char *tst_decode_fd(int fd)
> +{
> +	ssize_t ret;
> +	char proc_path[32];
> +
> +	if (fd < 0)
> +		return "!";
> +
> +	sprintf(proc_path, "/proc/self/fd/%d", fd);
> +	ret = readlink(proc_path, fd_path, sizeof(fd_path));
> +
> +	if (ret < 0)
> +		return "?";
> +
> +	fd_path[ret] = '\0';
> +
> +	return fd_path;
> +}
> +
> +int safe_openat(const char *file, const int lineno,
> +		int dirfd, const char *path, int oflags, ...)
> +{
> +	va_list ap;
> +	int fd;
> +	mode_t mode;
> +
> +	va_start(ap, oflags);
> +	mode = va_arg(ap, int);
> +	va_end(ap);
> +
> +	fd = openat(dirfd, path, oflags, mode);
> +	if (fd > -1)
> +		return fd;
> +
> +	tst_brk_(file, lineno, TBROK | TERRNO,
> +		 "openat(%d<%s>, '%s', %o, %o)",
> +		 dirfd, tst_decode_fd(dirfd), path, oflags, mode);
> +
> +	return fd;
> +}
> +
> +ssize_t safe_file_readat(const char *file, const int lineno,
> +			 int dirfd, const char *path, char *buf, size_t nbyte)
> +{
> +	int fd = safe_openat(file, lineno, dirfd, path, O_RDONLY);
> +	ssize_t rval;
> +
> +	if (fd < 0)
> +		return -1;
> +
> +	rval = safe_read(file, lineno, NULL, 0, fd, buf, nbyte - 1);
> +	if (rval < 0)
> +		return -1;
> +
> +	close(fd);
> +	buf[rval] = '\0';
> +
> +	if (rval >= (ssize_t)nbyte - 1) {
> +		tst_brk_(file, lineno, TBROK,
> +			"Buffer length %zu too small to read %d<%s>/%s",
> +			nbyte, dirfd, tst_decode_fd(dirfd), path);
> +	}
> +
> +	return rval;
> +}
> +
> +int tst_file_vprintfat(int dirfd, const char *path, const char *fmt, va_list va)
> +{
> +	int fd = openat(dirfd, path, O_WRONLY);
> +
> +	if (fd < 0)
> +		return -1;
> +
> +	TEST(vdprintf(fd, fmt, va));

Can we please avoid using the TEST() macro in the test library?

The value of TST_RET is supposed not to change unless actuall test code
does that.

> +	close(fd);
> +
> +	if (TST_RET < 0) {
> +		errno = TST_ERR;
> +		return -2;
> +	}
> +
> +	return TST_RET;
> +}
> +
> +int tst_file_printfat(int dirfd, const char *path, const char *fmt, ...)
> +{
> +	va_list va;
> +	int rval;
> +
> +	va_start(va, fmt);
> +	rval = tst_file_vprintfat(dirfd, path, fmt, va);
> +	va_end(va);
> +
> +	return rval;
> +}
> +
> +int safe_file_vprintfat(const char *file, const int lineno,
> +			int dirfd, const char *path,
> +			const char *fmt, va_list va)
> +{
> +	char buf[16];
> +	va_list vac;
> +	int rval;
> +
> +	va_copy(vac, va);
> +
> +	TEST(tst_file_vprintfat(dirfd, path, fmt, va));

Here as well.

> +	if (TST_RET == -2) {
> +		rval = vsnprintf(buf, sizeof(buf), fmt, vac);
> +		va_end(vac);
> +
> +		if (rval >= (ssize_t)sizeof(buf))
> +			strcpy(buf + sizeof(buf) - 5, "...");
> +
> +		tst_brk_(file, lineno, TBROK | TTERRNO,
> +			 "vdprintf(%d<%s>, '%s', '%s'<%s>)",
> +			 dirfd, tst_decode_fd(dirfd), path, fmt,
> +			 rval > 0 ? buf : "???");

I do not think that vsnprintf() can even return < 0 and the only way how
to make it return 0 is possibly with an empty fmt string. So I would
just skip this check.

> +		return -1;
> +	}
> +
> +	va_end(vac);
> +
> +	if (TST_RET == -1) {
> +		tst_brk_(file, lineno, TBROK | TTERRNO,
> +			"openat(%d<%s>, '%s', O_WRONLY)",
> +			dirfd, tst_decode_fd(dirfd), path);
> +	}
> +
> +	return TST_RET;
> +}
> +
> +int safe_file_printfat(const char *file, const int lineno,
> +		       int dirfd, const char *path,
> +		       const char *fmt, ...)
> +{
> +	va_list va;
> +	int rval;
> +
> +	va_start(va, fmt);
> +	rval = safe_file_vprintfat(file, lineno, dirfd, path, fmt, va);
> +	va_end(va);
> +
> +	return rval;
> +}
> +
> +int safe_unlinkat(const char *file, const int lineno,
> +		  int dirfd, const char *path, int flags)
> +{
> +	int rval = unlinkat(dirfd, path, flags);
> +
> +	if (rval > -1)
> +		return rval;

	if (!rval)
		return 0;

Anything else than 0 is either error or invalid.

> +	tst_brk_(file, lineno, TBROK | TERRNO,
> +		 "unlinkat(%d<%s>, '%s', %s)", dirfd, tst_decode_fd(dirfd), path,
> +		 flags == AT_REMOVEDIR ? "AT_REMOVEDIR" : (flags ? "?" : "0"));
> +
> +	return rval;
> +}

The rest looks good.

With issues I pointed you can add:

Reviewed-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Cyril Hrubis
chrubis@suse.cz

  reply	other threads:[~2021-04-30 14:22 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-30 11:26 [LTP] [PATCH v5 0/7] CGroup API rewrite Richard Palethorpe
2021-04-30 11:26 ` [LTP] [PATCH v5 1/7] API: Add safe openat, printfat, readat and unlinkat Richard Palethorpe
2021-04-30 14:22   ` Cyril Hrubis [this message]
2021-05-04  8:31     ` Richard Palethorpe
2021-04-30 11:26 ` [LTP] [PATCH v5 2/7] API: Make tst_count_scanf_conversions public Richard Palethorpe
2021-04-30 14:23   ` Cyril Hrubis
2021-04-30 11:26 ` [LTP] [PATCH v5 3/7] Add new CGroups APIs Richard Palethorpe
2021-04-30 15:48   ` Cyril Hrubis
2021-04-30 11:26 ` [LTP] [PATCH v5 4/7] Add new CGroups API library tests Richard Palethorpe
2021-04-30 15:57   ` Cyril Hrubis
2021-04-30 11:26 ` [LTP] [PATCH v5 5/7] docs: Update CGroups API Richard Palethorpe
2021-04-30 11:26 ` [LTP] [PATCH v5 6/7] mem: Convert tests to new " Richard Palethorpe
2021-05-03 11:20   ` Cyril Hrubis
2021-05-04  9:03     ` Richard Palethorpe
2021-04-30 11:26 ` [LTP] [PATCH v5 7/7] madvise06: Convert " Richard Palethorpe
2021-05-03 13:28   ` Cyril Hrubis

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=YIwSvc/KY0AX9Yeb@yuki \
    --to=chrubis@suse.cz \
    --cc=ltp@lists.linux.it \
    /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
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox