1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Test the statx() system call.
4 * Note that the output of this program is intended to look like the output of
5 * /bin/stat where possible.
7 * Copyright (C) 2015 Red Hat, Inc. All Rights Reserved.
8 * Written by David Howells (dhowells@redhat.com)
12 #define _ATFILE_SOURCE
20 #include <sys/syscall.h>
21 #include <sys/types.h>
22 #include <linux/stat.h>
23 #include <linux/fcntl.h>
25 #define statx_timestamp foo_timestamp
28 #undef statx_timestamp
30 #define AT_STATX_SYNC_TYPE 0x6000
31 #define AT_STATX_SYNC_AS_STAT 0x0000
32 #define AT_STATX_FORCE_SYNC 0x2000
33 #define AT_STATX_DONT_SYNC 0x4000
39 static __attribute__((unused
))
40 ssize_t
statx(int dfd
, const char *filename
, unsigned flags
,
41 unsigned int mask
, struct statx
*buffer
)
43 return syscall(__NR_statx
, dfd
, filename
, flags
, mask
, buffer
);
46 static void print_time(const char *field
, struct statx_timestamp
*ts
)
54 if (!localtime_r(&tim
, &tm
)) {
55 perror("localtime_r");
58 len
= strftime(buffer
, 100, "%F %T", &tm
);
64 fwrite(buffer
, 1, len
, stdout
);
65 printf(".%09u", ts
->tv_nsec
);
66 len
= strftime(buffer
, 100, "%z", &tm
);
71 fwrite(buffer
, 1, len
, stdout
);
75 static void dump_statx(struct statx
*stx
)
77 char buffer
[256], ft
= '?';
79 printf("results=%x\n", stx
->stx_mask
);
82 if (stx
->stx_mask
& STATX_SIZE
)
83 printf(" Size: %-15llu", (unsigned long long)stx
->stx_size
);
84 if (stx
->stx_mask
& STATX_BLOCKS
)
85 printf(" Blocks: %-10llu", (unsigned long long)stx
->stx_blocks
);
86 printf(" IO Block: %-6llu", (unsigned long long)stx
->stx_blksize
);
87 if (stx
->stx_mask
& STATX_TYPE
) {
88 switch (stx
->stx_mode
& S_IFMT
) {
89 case S_IFIFO
: printf(" FIFO\n"); ft
= 'p'; break;
90 case S_IFCHR
: printf(" character special file\n"); ft
= 'c'; break;
91 case S_IFDIR
: printf(" directory\n"); ft
= 'd'; break;
92 case S_IFBLK
: printf(" block special file\n"); ft
= 'b'; break;
93 case S_IFREG
: printf(" regular file\n"); ft
= '-'; break;
94 case S_IFLNK
: printf(" symbolic link\n"); ft
= 'l'; break;
95 case S_IFSOCK
: printf(" socket\n"); ft
= 's'; break;
97 printf(" unknown type (%o)\n", stx
->stx_mode
& S_IFMT
);
101 printf(" no type\n");
104 sprintf(buffer
, "%02x:%02x", stx
->stx_dev_major
, stx
->stx_dev_minor
);
105 printf("Device: %-15s", buffer
);
106 if (stx
->stx_mask
& STATX_INO
)
107 printf(" Inode: %-11llu", (unsigned long long) stx
->stx_ino
);
108 if (stx
->stx_mask
& STATX_NLINK
)
109 printf(" Links: %-5u", stx
->stx_nlink
);
110 if (stx
->stx_mask
& STATX_TYPE
) {
111 switch (stx
->stx_mode
& S_IFMT
) {
114 printf(" Device type: %u,%u",
115 stx
->stx_rdev_major
, stx
->stx_rdev_minor
);
121 if (stx
->stx_mask
& STATX_MODE
)
122 printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c) ",
123 stx
->stx_mode
& 07777,
125 stx
->stx_mode
& S_IRUSR
? 'r' : '-',
126 stx
->stx_mode
& S_IWUSR
? 'w' : '-',
127 stx
->stx_mode
& S_IXUSR
? 'x' : '-',
128 stx
->stx_mode
& S_IRGRP
? 'r' : '-',
129 stx
->stx_mode
& S_IWGRP
? 'w' : '-',
130 stx
->stx_mode
& S_IXGRP
? 'x' : '-',
131 stx
->stx_mode
& S_IROTH
? 'r' : '-',
132 stx
->stx_mode
& S_IWOTH
? 'w' : '-',
133 stx
->stx_mode
& S_IXOTH
? 'x' : '-');
134 if (stx
->stx_mask
& STATX_UID
)
135 printf("Uid: %5d ", stx
->stx_uid
);
136 if (stx
->stx_mask
& STATX_GID
)
137 printf("Gid: %5d\n", stx
->stx_gid
);
139 if (stx
->stx_mask
& STATX_ATIME
)
140 print_time("Access: ", &stx
->stx_atime
);
141 if (stx
->stx_mask
& STATX_MTIME
)
142 print_time("Modify: ", &stx
->stx_mtime
);
143 if (stx
->stx_mask
& STATX_CTIME
)
144 print_time("Change: ", &stx
->stx_ctime
);
145 if (stx
->stx_mask
& STATX_BTIME
)
146 print_time(" Birth: ", &stx
->stx_btime
);
148 if (stx
->stx_attributes_mask
) {
149 unsigned char bits
, mbits
;
152 static char attr_representation
[64 + 1] =
153 /* STATX_ATTR_ flags: */
154 "????????" /* 63-56 */
155 "????????" /* 55-48 */
156 "????????" /* 47-40 */
157 "????????" /* 39-32 */
158 "????????" /* 31-24 0x00000000-ff000000 */
159 "????????" /* 23-16 0x00000000-00ff0000 */
160 "???me???" /* 15- 8 0x00000000-0000ff00 */
161 "?dai?c??" /* 7- 0 0x00000000-000000ff */
164 printf("Attributes: %016llx (",
165 (unsigned long long)stx
->stx_attributes
);
166 for (byte
= 64 - 8; byte
>= 0; byte
-= 8) {
167 bits
= stx
->stx_attributes
>> byte
;
168 mbits
= stx
->stx_attributes_mask
>> byte
;
169 for (loop
= 7; loop
>= 0; loop
--) {
170 int bit
= byte
+ loop
;
173 putchar('.'); /* Not supported */
174 else if (bits
& 0x80)
175 putchar(attr_representation
[63 - bit
]);
177 putchar('-'); /* Not set */
188 static void dump_hex(unsigned long long *data
, int from
, int to
)
190 unsigned offset
, print_offset
= 1, col
= 0;
195 for (offset
= from
; offset
< to
; offset
++) {
197 printf("%04x: ", offset
* 8);
200 printf("%016llx", data
[offset
]);
202 if ((col
& 3) == 0) {
214 int main(int argc
, char **argv
)
217 int ret
, raw
= 0, atflag
= AT_SYMLINK_NOFOLLOW
;
219 unsigned int mask
= STATX_ALL
;
221 for (argv
++; *argv
; argv
++) {
222 if (strcmp(*argv
, "-F") == 0) {
223 atflag
&= ~AT_STATX_SYNC_TYPE
;
224 atflag
|= AT_STATX_FORCE_SYNC
;
227 if (strcmp(*argv
, "-D") == 0) {
228 atflag
&= ~AT_STATX_SYNC_TYPE
;
229 atflag
|= AT_STATX_DONT_SYNC
;
232 if (strcmp(*argv
, "-L") == 0) {
233 atflag
&= ~AT_SYMLINK_NOFOLLOW
;
236 if (strcmp(*argv
, "-O") == 0) {
237 mask
&= ~STATX_BASIC_STATS
;
240 if (strcmp(*argv
, "-A") == 0) {
241 atflag
|= AT_NO_AUTOMOUNT
;
244 if (strcmp(*argv
, "-R") == 0) {
249 memset(&stx
, 0xbf, sizeof(stx
));
250 ret
= statx(AT_FDCWD
, *argv
, atflag
, mask
, &stx
);
251 printf("statx(%s) = %d\n", *argv
, ret
);
258 dump_hex((unsigned long long *)&stx
, 0, sizeof(stx
));