Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/statx.c
48529 views
1
/*
2
* SPDX-License-Identifier: MIT
3
*
4
* Copyright (c) 2025, Rob Norris <[email protected]>
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a copy
7
* of this software and associated documentation files (the "Software"), to
8
* deal in the Software without restriction, including without limitation the
9
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
* sell copies of the Software, and to permit persons to whom the Software is
11
* furnished to do so, subject to the following conditions:
12
*
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
* IN THE SOFTWARE.
23
*/
24
25
#include <stdint.h>
26
#include <stdio.h>
27
#include <string.h>
28
#include <errno.h>
29
#include <fcntl.h>
30
#include <sys/syscall.h>
31
#include <unistd.h>
32
33
/*
34
* statx() may be available in the kernel, but not in the libc, so we build
35
* our own wrapper if we can't link one.
36
*/
37
38
#ifndef __NR_statx
39
#if defined(__x86_64__)
40
#define __NR_statx (332)
41
#elif defined(__i386__)
42
#define __NR_statx (383)
43
#elif defined(__s390__)
44
#define __NR_statx (379)
45
#elif defined(__arm__)
46
#define __NR_statx (397)
47
#elif defined(__aarch64__)
48
#define __NR_statx (291)
49
#elif defined(__powerpc__)
50
#define __NR_statx (383)
51
#else
52
#error "no definition of __NR_statx for this platform"
53
#endif
54
#endif /* __NR_statx */
55
56
57
int
58
statx(int, const char *, int, unsigned int, void *)
59
__attribute__((weak));
60
61
static inline int
62
_statx(int fd, const char *path, int flags, unsigned int mask, void *stx)
63
{
64
if (statx)
65
return (statx(fd, path, flags, mask, stx));
66
else
67
return (syscall(__NR_statx, fd, path, flags, mask, stx));
68
}
69
70
#ifndef STATX_TYPE
71
#define STATX_TYPE (1<<0)
72
#endif
73
#ifndef STATX_MODE
74
#define STATX_MODE (1<<1)
75
#endif
76
#ifndef STATX_NLINK
77
#define STATX_NLINK (1<<2)
78
#endif
79
#ifndef STATX_UID
80
#define STATX_UID (1<<3)
81
#endif
82
#ifndef STATX_GID
83
#define STATX_GID (1<<4)
84
#endif
85
#ifndef STATX_ATIME
86
#define STATX_ATIME (1<<5)
87
#endif
88
#ifndef STATX_MTIME
89
#define STATX_MTIME (1<<6)
90
#endif
91
#ifndef STATX_CTIME
92
#define STATX_CTIME (1<<7)
93
#endif
94
#ifndef STATX_INO
95
#define STATX_INO (1<<8)
96
#endif
97
#ifndef STATX_SIZE
98
#define STATX_SIZE (1<<9)
99
#endif
100
#ifndef STATX_BLOCKS
101
#define STATX_BLOCKS (1<<10)
102
#endif
103
#ifndef STATX_BTIME
104
#define STATX_BTIME (1<<11)
105
#endif
106
#ifndef STATX_MNT_ID
107
#define STATX_MNT_ID (1<<12)
108
#endif
109
#ifndef STATX_DIOALIGN
110
#define STATX_DIOALIGN (1<<13)
111
#endif
112
#ifndef S_IFMT
113
#define S_IFMT 0170000
114
#endif
115
116
typedef struct {
117
int64_t tv_sec;
118
uint32_t tv_nsec;
119
int32_t _pad;
120
} stx_timestamp_t;
121
_Static_assert(sizeof (stx_timestamp_t) == 0x10,
122
"stx_timestamp_t not 16 bytes");
123
124
typedef struct {
125
uint32_t stx_mask;
126
uint32_t stx_blksize;
127
uint64_t stx_attributes;
128
uint32_t stx_nlink;
129
uint32_t stx_uid;
130
uint32_t stx_gid;
131
uint16_t stx_mode;
132
uint16_t _pad1;
133
uint64_t stx_ino;
134
uint64_t stx_size;
135
uint64_t stx_blocks;
136
uint64_t stx_attributes_mask;
137
stx_timestamp_t stx_atime;
138
stx_timestamp_t stx_btime;
139
stx_timestamp_t stx_ctime;
140
stx_timestamp_t stx_mtime;
141
uint32_t stx_rdev_major;
142
uint32_t stx_rdev_minor;
143
uint32_t stx_dev_major;
144
uint32_t stx_dev_minor;
145
uint64_t stx_mnt_id;
146
uint32_t stx_dio_mem_align;
147
uint32_t stx_dio_offset_align;
148
uint64_t _pad2[12];
149
} stx_t;
150
_Static_assert(sizeof (stx_t) == 0x100, "stx_t not 256 bytes");
151
152
typedef struct {
153
const char *name;
154
unsigned int mask;
155
} stx_field_t;
156
157
stx_field_t fields[] = {
158
{ "type", STATX_TYPE },
159
{ "mode", STATX_MODE },
160
{ "nlink", STATX_NLINK },
161
{ "uid", STATX_UID },
162
{ "gid", STATX_GID },
163
{ "atime", STATX_ATIME },
164
{ "mtime", STATX_MTIME },
165
{ "ctime", STATX_CTIME },
166
{ "ino", STATX_INO },
167
{ "size", STATX_SIZE },
168
{ "blocks", STATX_BLOCKS },
169
{ "btime", STATX_BTIME },
170
{ "mnt_id", STATX_MNT_ID },
171
{ "dioalign", STATX_DIOALIGN },
172
{ NULL },
173
};
174
175
static int
176
usage(void)
177
{
178
printf(
179
"usage: statx <field[,field,field]> <file>\n"
180
"available fields:\n");
181
182
int w = 0;
183
for (stx_field_t *f = fields; f->name != NULL; f++) {
184
if (w > 0 && (w + strlen(f->name) + 1) > 60) {
185
fputc('\n', stdout);
186
w = 0;
187
}
188
if (w == 0)
189
fputc(' ', stdout);
190
w += printf(" %s", f->name);
191
}
192
if (w > 0)
193
fputc('\n', stdout);
194
return (1);
195
}
196
197
int
198
main(int argc, char **argv)
199
{
200
if (argc < 3)
201
return (usage());
202
203
unsigned int mask = 0;
204
205
char *name;
206
while ((name = strsep(&argv[1], ",")) != NULL) {
207
stx_field_t *f;
208
for (f = fields; f->name != NULL; f++) {
209
if (strcmp(name, f->name) == 0) {
210
mask |= f->mask;
211
break;
212
}
213
}
214
if (f->name == NULL) {
215
fprintf(stderr, "unknown field name: %s\n", name);
216
return (usage());
217
}
218
}
219
220
int fd = open(argv[2], O_PATH);
221
if (fd < 0) {
222
fprintf(stderr, "open: %s: %s\n", argv[2], strerror(errno));
223
return (1);
224
}
225
226
stx_t stx = {};
227
228
if (_statx(fd, "",
229
AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, mask, &stx) < 0) {
230
fprintf(stderr, "statx: %s: %s\n", argv[2], strerror(errno));
231
close(fd);
232
return (1);
233
}
234
235
int rc = 0;
236
237
for (stx_field_t *f = fields; f->name != NULL; f++) {
238
if (!(mask & f->mask))
239
continue;
240
if (!(stx.stx_mask & f->mask)) {
241
printf("statx: kernel did not return field: %s\n",
242
f->name);
243
rc = 2;
244
continue;
245
}
246
}
247
248
if (rc > 0)
249
return (rc);
250
251
for (stx_field_t *f = fields; f->name != NULL; f++) {
252
if (!(mask & f->mask))
253
continue;
254
255
switch (f->mask) {
256
case STATX_TYPE:
257
printf("type: %u\n", stx.stx_mode & S_IFMT);
258
break;
259
case STATX_MODE:
260
printf("mode: %u\n", stx.stx_mode & ~S_IFMT);
261
break;
262
case STATX_NLINK:
263
printf("nlink: %u\n", stx.stx_nlink);
264
break;
265
case STATX_UID:
266
printf("uid: %u\n", stx.stx_uid);
267
break;
268
case STATX_GID:
269
printf("gid: %u\n", stx.stx_gid);
270
break;
271
case STATX_ATIME:
272
printf("atime: %ld.%u\n",
273
stx.stx_atime.tv_sec, stx.stx_atime.tv_nsec);
274
break;
275
case STATX_MTIME:
276
printf("mtime: %ld.%u\n",
277
stx.stx_mtime.tv_sec, stx.stx_mtime.tv_nsec);
278
break;
279
case STATX_CTIME:
280
printf("ctime: %ld.%u\n",
281
stx.stx_ctime.tv_sec, stx.stx_ctime.tv_nsec);
282
break;
283
case STATX_INO:
284
printf("ino: %lu\n", stx.stx_ino);
285
break;
286
case STATX_SIZE:
287
printf("size: %lu\n", stx.stx_size);
288
break;
289
case STATX_BLOCKS:
290
printf("blocks: %lu\n", stx.stx_blocks);
291
break;
292
case STATX_BTIME:
293
printf("btime: %ld.%u\n",
294
stx.stx_btime.tv_sec, stx.stx_btime.tv_nsec);
295
break;
296
case STATX_MNT_ID:
297
printf("mnt_id: %lu\n", stx.stx_mnt_id);
298
break;
299
case STATX_DIOALIGN:
300
printf("dioalign: %u %u\n",
301
stx.stx_dio_mem_align, stx.stx_dio_offset_align);
302
break;
303
}
304
}
305
306
return (rc);
307
}
308
309