blob: 4f9d58282f0893bdcc69d0647f522b2156cb6a3c [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) Zilogic Systems Pvt. Ltd., 2018
* Email: code@zilogic.com
*/
/*
* Test statx
*
* This code tests the functionality of statx system call.
*
* TESTCASE 1:
* The metadata for normal file are tested against predefined values:
* 1) gid
* 2) uid
* 3) mode
* 4) blocks
* 5) size
*
* A file is created and metadata values are set with
* predefined values.
* Then the values obtained using statx is checked against
* the predefined values.
*
* TESTCASE 2:
* The metadata for device file are tested against predefined values:
* 1) MAJOR number
* 2) MINOR number
*
* A device file is created seperately using mknod(must be a root user).
* The major number and minor number are set while creation.
* Major and minor numbers obtained using statx is checked against
* predefined values.
* Minimum kernel version required is 4.11.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include "tst_test.h"
#include "tst_safe_macros.h"
#include "lapi/stat.h"
#include <string.h>
#include <inttypes.h>
#define TESTFILE "test_file"
#define MNTPOINT "mntpoint/"
#define DEVICEFILE MNTPOINT"blk_dev"
#define MODE 0644
#define SIZE 256
#define MAJOR 8
#define MINOR 1
static void test_normal_file(void)
{
struct statx buff;
TEST(statx(AT_FDCWD, TESTFILE, 0, 0, &buff));
if (TST_RET == 0)
tst_res(TPASS,
"statx(AT_FDCWD, %s, 0, 0, &buff)", TESTFILE);
else
tst_brk(TFAIL | TTERRNO,
"statx(AT_FDCWD, %s, 0, 0, &buff)", TESTFILE);
if (geteuid() == buff.stx_uid)
tst_res(TPASS, "stx_uid(%u) is correct", buff.stx_uid);
else
tst_res(TFAIL, "stx_uid(%u) is different from euid(%u)",
buff.stx_uid, geteuid());
if (getegid() == buff.stx_gid)
tst_res(TPASS, "stx_gid(%u) is correct", buff.stx_gid);
else
tst_res(TFAIL, "stx_gid(%u) is different from egid(%u)",
buff.stx_gid, getegid());
if (buff.stx_size == SIZE)
tst_res(TPASS,
"stx_size(%"PRIu64") is correct", buff.stx_size);
else
tst_res(TFAIL,
"stx_size(%"PRIu64") is different from expected(%u)",
buff.stx_size, SIZE);
if ((buff.stx_mode & ~(S_IFMT)) == MODE)
tst_res(TPASS, "stx_mode(%u) is correct", buff.stx_mode);
else
tst_res(TFAIL, "stx_mode(%u) is different from expected(%u)",
buff.stx_mode, MODE);
if (buff.stx_blocks <= buff.stx_blksize/512 * 2)
tst_res(TPASS, "stx_blocks(%"PRIu64") is valid",
buff.stx_blocks);
else
tst_res(TFAIL, "stx_blocks(%"PRIu64") is invalid",
buff.stx_blocks);
}
static void test_device_file(void)
{
struct statx buff;
TEST(statx(AT_FDCWD, DEVICEFILE, 0, 0, &buff));
if (TST_RET == 0)
tst_res(TPASS,
"statx(AT_FDCWD, %s, 0, 0, &buff)", DEVICEFILE);
else
tst_brk(TFAIL | TTERRNO,
"statx(AT_FDCWD, %s, 0, 0, &buff)", DEVICEFILE);
if (buff.stx_rdev_major == MAJOR)
tst_res(TPASS, "stx_rdev_major(%u) is correct",
buff.stx_rdev_major);
else
tst_res(TFAIL,
"stx_rdev_major(%u) is different from expected(%u)",
buff.stx_rdev_major, MAJOR);
if (buff.stx_rdev_minor == MINOR)
tst_res(TPASS, "stx_rdev_minor(%u) is correct",
buff.stx_rdev_minor);
else
tst_res(TFAIL,
"stx_rdev_minor(%u) is different from expected(%u)",
buff.stx_rdev_minor, MINOR);
}
struct tcase {
void (*tfunc)(void);
} tcases[] = {
{&test_normal_file},
{&test_device_file}
};
static void run(unsigned int i)
{
tcases[i].tfunc();
}
static void setup(void)
{
char data_buff[SIZE];
int file_fd;
memset(data_buff, '@', sizeof(data_buff));
file_fd = SAFE_OPEN(TESTFILE, O_RDWR|O_CREAT, MODE);
SAFE_WRITE(1, file_fd, data_buff, sizeof(data_buff));
SAFE_CLOSE(file_fd);
SAFE_MKNOD(DEVICEFILE, S_IFBLK | 0777, makedev(MAJOR, MINOR));
}
static struct tst_test test = {
.test = run,
.tcnt = ARRAY_SIZE(tcases),
.setup = setup,
.min_kver = "4.11",
.needs_devfs = 1,
.mntpoint = MNTPOINT,
.needs_root = 1,
};