1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 4f08c3bdfSopenharmony_ci * Email: code@zilogic.com 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This code tests the functionality of statx system call. 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * The metadata for normal file are tested against expected values: 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * - gid 15f08c3bdfSopenharmony_ci * - uid 16f08c3bdfSopenharmony_ci * - mode 17f08c3bdfSopenharmony_ci * - blocks 18f08c3bdfSopenharmony_ci * - size 19f08c3bdfSopenharmony_ci * - nlink 20f08c3bdfSopenharmony_ci * - mnt_id 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * The metadata for device file are tested against expected values: 23f08c3bdfSopenharmony_ci * 24f08c3bdfSopenharmony_ci * - MAJOR number 25f08c3bdfSopenharmony_ci * - MINOR number 26f08c3bdfSopenharmony_ci */ 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#define _GNU_SOURCE 29f08c3bdfSopenharmony_ci#include <stdio.h> 30f08c3bdfSopenharmony_ci#include <sys/types.h> 31f08c3bdfSopenharmony_ci#include <unistd.h> 32f08c3bdfSopenharmony_ci#include <sys/sysmacros.h> 33f08c3bdfSopenharmony_ci#include "tst_test.h" 34f08c3bdfSopenharmony_ci#include "tst_safe_macros.h" 35f08c3bdfSopenharmony_ci#include "lapi/stat.h" 36f08c3bdfSopenharmony_ci#include "lapi/fcntl.h" 37f08c3bdfSopenharmony_ci#include "tst_safe_stdio.h" 38f08c3bdfSopenharmony_ci#include <string.h> 39f08c3bdfSopenharmony_ci#include <inttypes.h> 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci#define TESTFILE "test_file" 42f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint/" 43f08c3bdfSopenharmony_ci#define DEVICEFILE MNTPOINT"blk_dev" 44f08c3bdfSopenharmony_ci#define MODE 0644 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci#define SIZE 256 47f08c3bdfSopenharmony_ci#define MAJOR 8 48f08c3bdfSopenharmony_ci#define MINOR 1 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_cistatic int file_fd = -1; 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_ci#ifdef HAVE_STRUCT_STATX_STX_MNT_ID 53f08c3bdfSopenharmony_cistatic void test_mnt_id(struct statx *buf) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci FILE *file; 56f08c3bdfSopenharmony_ci char line[PATH_MAX]; 57f08c3bdfSopenharmony_ci int pid, flag = 0; 58f08c3bdfSopenharmony_ci unsigned int line_mjr, line_mnr; 59f08c3bdfSopenharmony_ci uint64_t mnt_id; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_ci if (!(buf->stx_mask & STATX_MNT_ID)) { 62f08c3bdfSopenharmony_ci tst_res(TCONF, "stx_mnt_id is not supported until linux 5.8"); 63f08c3bdfSopenharmony_ci return; 64f08c3bdfSopenharmony_ci } 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci file = SAFE_FOPEN("/proc/self/mountinfo", "r"); 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci while (fgets(line, sizeof(line), file)) { 69f08c3bdfSopenharmony_ci if (sscanf(line, "%"SCNu64" %*d %d:%d", &mnt_id, &line_mjr, &line_mnr) != 3) 70f08c3bdfSopenharmony_ci continue; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci if (line_mjr == buf->stx_dev_major && line_mnr == buf->stx_dev_minor) { 73f08c3bdfSopenharmony_ci if (buf->stx_mnt_id == mnt_id) { 74f08c3bdfSopenharmony_ci flag = 1; 75f08c3bdfSopenharmony_ci break; 76f08c3bdfSopenharmony_ci } 77f08c3bdfSopenharmony_ci tst_res(TINFO, "%s doesn't contain %"PRIu64" %d:%d", 78f08c3bdfSopenharmony_ci line, (uint64_t)buf->stx_mnt_id, buf->stx_dev_major, buf->stx_dev_minor); 79f08c3bdfSopenharmony_ci } 80f08c3bdfSopenharmony_ci } 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_ci SAFE_FCLOSE(file); 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci if (flag) 85f08c3bdfSopenharmony_ci tst_res(TPASS, 86f08c3bdfSopenharmony_ci "statx.stx_mnt_id equals to mount_id(%"PRIu64") in /proc/self/mountinfo", 87f08c3bdfSopenharmony_ci mnt_id); 88f08c3bdfSopenharmony_ci else 89f08c3bdfSopenharmony_ci tst_res(TFAIL, 90f08c3bdfSopenharmony_ci "statx.stx_mnt_id(%"PRIu64") doesn't exist in /proc/self/mountinfo", 91f08c3bdfSopenharmony_ci (uint64_t)buf->stx_mnt_id); 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci pid = getpid(); 94f08c3bdfSopenharmony_ci snprintf(line, PATH_MAX, "/proc/%d/fdinfo/%d", pid, file_fd); 95f08c3bdfSopenharmony_ci TST_ASSERT_FILE_INT(line, "mnt_id:", buf->stx_mnt_id); 96f08c3bdfSopenharmony_ci} 97f08c3bdfSopenharmony_ci#endif 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_cistatic void test_normal_file(void) 100f08c3bdfSopenharmony_ci{ 101f08c3bdfSopenharmony_ci struct statx buff; 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci TEST(statx(AT_FDCWD, TESTFILE, 0, 0, &buff)); 104f08c3bdfSopenharmony_ci if (TST_RET == 0) 105f08c3bdfSopenharmony_ci tst_res(TPASS, 106f08c3bdfSopenharmony_ci "statx(AT_FDCWD, %s, 0, 0, &buff)", TESTFILE); 107f08c3bdfSopenharmony_ci else 108f08c3bdfSopenharmony_ci tst_brk(TFAIL | TTERRNO, 109f08c3bdfSopenharmony_ci "statx(AT_FDCWD, %s, 0, 0, &buff)", TESTFILE); 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci if (geteuid() == buff.stx_uid) 112f08c3bdfSopenharmony_ci tst_res(TPASS, "stx_uid(%u) is correct", buff.stx_uid); 113f08c3bdfSopenharmony_ci else 114f08c3bdfSopenharmony_ci tst_res(TFAIL, "stx_uid(%u) is different from euid(%u)", 115f08c3bdfSopenharmony_ci buff.stx_uid, geteuid()); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci if (getegid() == buff.stx_gid) 118f08c3bdfSopenharmony_ci tst_res(TPASS, "stx_gid(%u) is correct", buff.stx_gid); 119f08c3bdfSopenharmony_ci else 120f08c3bdfSopenharmony_ci tst_res(TFAIL, "stx_gid(%u) is different from egid(%u)", 121f08c3bdfSopenharmony_ci buff.stx_gid, getegid()); 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_ci if (buff.stx_size == SIZE) 124f08c3bdfSopenharmony_ci tst_res(TPASS, 125f08c3bdfSopenharmony_ci "stx_size(%"PRIu64") is correct", (uint64_t)buff.stx_size); 126f08c3bdfSopenharmony_ci else 127f08c3bdfSopenharmony_ci tst_res(TFAIL, 128f08c3bdfSopenharmony_ci "stx_size(%"PRIu64") is different from expected(%u)", 129f08c3bdfSopenharmony_ci (uint64_t)buff.stx_size, SIZE); 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci if ((buff.stx_mode & ~(S_IFMT)) == MODE) 132f08c3bdfSopenharmony_ci tst_res(TPASS, "stx_mode(%u) is correct", buff.stx_mode); 133f08c3bdfSopenharmony_ci else 134f08c3bdfSopenharmony_ci tst_res(TFAIL, "stx_mode(%u) is different from expected(%u)", 135f08c3bdfSopenharmony_ci buff.stx_mode, MODE); 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_ci if (buff.stx_blocks <= buff.stx_blksize/512 * 2) 138f08c3bdfSopenharmony_ci tst_res(TPASS, "stx_blocks(%"PRIu64") is valid", 139f08c3bdfSopenharmony_ci (uint64_t)buff.stx_blocks); 140f08c3bdfSopenharmony_ci else 141f08c3bdfSopenharmony_ci tst_res(TFAIL, "stx_blocks(%"PRIu64") is invalid", 142f08c3bdfSopenharmony_ci (uint64_t)buff.stx_blocks); 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci if (buff.stx_nlink == 1) 145f08c3bdfSopenharmony_ci tst_res(TPASS, "stx_nlink(1) is correct"); 146f08c3bdfSopenharmony_ci else 147f08c3bdfSopenharmony_ci tst_res(TFAIL, "stx_nlink(%u) is different from expected(1)", 148f08c3bdfSopenharmony_ci buff.stx_nlink); 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci#ifdef HAVE_STRUCT_STATX_STX_MNT_ID 151f08c3bdfSopenharmony_ci test_mnt_id(&buff); 152f08c3bdfSopenharmony_ci#else 153f08c3bdfSopenharmony_ci tst_res(TCONF, "stx_mnt_id is not defined in struct statx"); 154f08c3bdfSopenharmony_ci#endif 155f08c3bdfSopenharmony_ci} 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_cistatic void test_device_file(void) 158f08c3bdfSopenharmony_ci{ 159f08c3bdfSopenharmony_ci struct statx buff; 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci TEST(statx(AT_FDCWD, DEVICEFILE, 0, 0, &buff)); 162f08c3bdfSopenharmony_ci if (TST_RET == 0) 163f08c3bdfSopenharmony_ci tst_res(TPASS, 164f08c3bdfSopenharmony_ci "statx(AT_FDCWD, %s, 0, 0, &buff)", DEVICEFILE); 165f08c3bdfSopenharmony_ci else 166f08c3bdfSopenharmony_ci tst_brk(TFAIL | TTERRNO, 167f08c3bdfSopenharmony_ci "statx(AT_FDCWD, %s, 0, 0, &buff)", DEVICEFILE); 168f08c3bdfSopenharmony_ci 169f08c3bdfSopenharmony_ci if (buff.stx_rdev_major == MAJOR) 170f08c3bdfSopenharmony_ci tst_res(TPASS, "stx_rdev_major(%u) is correct", 171f08c3bdfSopenharmony_ci buff.stx_rdev_major); 172f08c3bdfSopenharmony_ci else 173f08c3bdfSopenharmony_ci tst_res(TFAIL, 174f08c3bdfSopenharmony_ci "stx_rdev_major(%u) is different from expected(%u)", 175f08c3bdfSopenharmony_ci buff.stx_rdev_major, MAJOR); 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_ci if (buff.stx_rdev_minor == MINOR) 178f08c3bdfSopenharmony_ci tst_res(TPASS, "stx_rdev_minor(%u) is correct", 179f08c3bdfSopenharmony_ci buff.stx_rdev_minor); 180f08c3bdfSopenharmony_ci else 181f08c3bdfSopenharmony_ci tst_res(TFAIL, 182f08c3bdfSopenharmony_ci "stx_rdev_minor(%u) is different from expected(%u)", 183f08c3bdfSopenharmony_ci buff.stx_rdev_minor, MINOR); 184f08c3bdfSopenharmony_ci} 185f08c3bdfSopenharmony_ci 186f08c3bdfSopenharmony_ci 187f08c3bdfSopenharmony_cistatic struct tcase { 188f08c3bdfSopenharmony_ci void (*tfunc)(void); 189f08c3bdfSopenharmony_ci} tcases[] = { 190f08c3bdfSopenharmony_ci {&test_normal_file}, 191f08c3bdfSopenharmony_ci {&test_device_file} 192f08c3bdfSopenharmony_ci}; 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_cistatic void run(unsigned int i) 195f08c3bdfSopenharmony_ci{ 196f08c3bdfSopenharmony_ci tcases[i].tfunc(); 197f08c3bdfSopenharmony_ci} 198f08c3bdfSopenharmony_ci 199f08c3bdfSopenharmony_cistatic void setup(void) 200f08c3bdfSopenharmony_ci{ 201f08c3bdfSopenharmony_ci char data_buff[SIZE]; 202f08c3bdfSopenharmony_ci 203f08c3bdfSopenharmony_ci umask(0); 204f08c3bdfSopenharmony_ci 205f08c3bdfSopenharmony_ci memset(data_buff, '@', sizeof(data_buff)); 206f08c3bdfSopenharmony_ci 207f08c3bdfSopenharmony_ci file_fd = SAFE_OPEN(TESTFILE, O_RDWR|O_CREAT, MODE); 208f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, file_fd, data_buff, sizeof(data_buff)); 209f08c3bdfSopenharmony_ci 210f08c3bdfSopenharmony_ci SAFE_MKNOD(DEVICEFILE, S_IFBLK | 0777, makedev(MAJOR, MINOR)); 211f08c3bdfSopenharmony_ci} 212f08c3bdfSopenharmony_ci 213f08c3bdfSopenharmony_cistatic void cleanup(void) 214f08c3bdfSopenharmony_ci{ 215f08c3bdfSopenharmony_ci if (file_fd > -1) 216f08c3bdfSopenharmony_ci SAFE_CLOSE(file_fd); 217f08c3bdfSopenharmony_ci} 218f08c3bdfSopenharmony_ci 219f08c3bdfSopenharmony_cistatic struct tst_test test = { 220f08c3bdfSopenharmony_ci .test = run, 221f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 222f08c3bdfSopenharmony_ci .setup = setup, 223f08c3bdfSopenharmony_ci .cleanup = cleanup, 224f08c3bdfSopenharmony_ci .min_kver = "4.11", 225f08c3bdfSopenharmony_ci .needs_devfs = 1, 226f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 227f08c3bdfSopenharmony_ci .needs_root = 1, 228f08c3bdfSopenharmony_ci}; 229