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