1 /* Test the statx() system call.
3 * Note that the output of this program is intended to look like the output of
4 * /bin/stat where possible.
6 * Copyright (C) 2015 Red Hat, Inc. All Rights Reserved.
7 * Written by David Howells (dhowells@redhat.com)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public Licence
11 * as published by the Free Software Foundation; either version
12 * 2 of the Licence, or (at your option) any later version.
16 #define _ATFILE_SOURCE
24 #include <sys/syscall.h>
25 #include <sys/types.h>
26 #include <linux/stat.h>
27 #include <linux/fcntl.h>
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
35 static __attribute__((unused
))
36 ssize_t
statx(int dfd
, const char *filename
, unsigned flags
,
37 unsigned int mask
, struct statx
*buffer
)
39 return syscall(__NR_statx
, dfd
, filename
, flags
, mask
, buffer
);
42 static void print_time(const char *field
, struct statx_timestamp
*ts
)
50 if (!localtime_r(&tim
, &tm
)) {
51 perror("localtime_r");
54 len
= strftime(buffer
, 100, "%F %T", &tm
);
60 fwrite(buffer
, 1, len
, stdout
);
61 printf(".%09u", ts
->tv_nsec
);
62 len
= strftime(buffer
, 100, "%z", &tm
);
67 fwrite(buffer
, 1, len
, stdout
);
71 static void dump_statx(struct statx
*stx
)
73 char buffer
[256], ft
= '?';
75 printf("results=%x\n", stx
->stx_mask
);
78 if (stx
->stx_mask
& STATX_SIZE
)
79 printf(" Size: %-15llu", (unsigned long long)stx
->stx_size
);
80 if (stx
->stx_mask
& STATX_BLOCKS
)
81 printf(" Blocks: %-10llu", (unsigned long long)stx
->stx_blocks
);
82 printf(" IO Block: %-6llu", (unsigned long long)stx
->stx_blksize
);
83 if (stx
->stx_mask
& STATX_TYPE
) {
84 switch (stx
->stx_mode
& S_IFMT
) {
85 case S_IFIFO
: printf(" FIFO\n"); ft
= 'p'; break;
86 case S_IFCHR
: printf(" character special file\n"); ft
= 'c'; break;
87 case S_IFDIR
: printf(" directory\n"); ft
= 'd'; break;
88 case S_IFBLK
: printf(" block special file\n"); ft
= 'b'; break;
89 case S_IFREG
: printf(" regular file\n"); ft
= '-'; break;
90 case S_IFLNK
: printf(" symbolic link\n"); ft
= 'l'; break;
91 case S_IFSOCK
: printf(" socket\n"); ft
= 's'; break;
93 printf(" unknown type (%o)\n", stx
->stx_mode
& S_IFMT
);
100 sprintf(buffer
, "%02x:%02x", stx
->stx_dev_major
, stx
->stx_dev_minor
);
101 printf("Device: %-15s", buffer
);
102 if (stx
->stx_mask
& STATX_INO
)
103 printf(" Inode: %-11llu", (unsigned long long) stx
->stx_ino
);
104 if (stx
->stx_mask
& STATX_NLINK
)
105 printf(" Links: %-5u", stx
->stx_nlink
);
106 if (stx
->stx_mask
& STATX_TYPE
) {
107 switch (stx
->stx_mode
& S_IFMT
) {
110 printf(" Device type: %u,%u",
111 stx
->stx_rdev_major
, stx
->stx_rdev_minor
);
117 if (stx
->stx_mask
& STATX_MODE
)
118 printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c) ",
119 stx
->stx_mode
& 07777,
121 stx
->stx_mode
& S_IRUSR
? 'r' : '-',
122 stx
->stx_mode
& S_IWUSR
? 'w' : '-',
123 stx
->stx_mode
& S_IXUSR
? 'x' : '-',
124 stx
->stx_mode
& S_IRGRP
? 'r' : '-',
125 stx
->stx_mode
& S_IWGRP
? 'w' : '-',
126 stx
->stx_mode
& S_IXGRP
? 'x' : '-',
127 stx
->stx_mode
& S_IROTH
? 'r' : '-',
128 stx
->stx_mode
& S_IWOTH
? 'w' : '-',
129 stx
->stx_mode
& S_IXOTH
? 'x' : '-');
130 if (stx
->stx_mask
& STATX_UID
)
131 printf("Uid: %5d ", stx
->stx_uid
);
132 if (stx
->stx_mask
& STATX_GID
)
133 printf("Gid: %5d\n", stx
->stx_gid
);
135 if (stx
->stx_mask
& STATX_ATIME
)
136 print_time("Access: ", &stx
->stx_atime
);
137 if (stx
->stx_mask
& STATX_MTIME
)
138 print_time("Modify: ", &stx
->stx_mtime
);
139 if (stx
->stx_mask
& STATX_CTIME
)
140 print_time("Change: ", &stx
->stx_ctime
);
141 if (stx
->stx_mask
& STATX_BTIME
)
142 print_time(" Birth: ", &stx
->stx_btime
);
144 if (stx
->stx_attributes_mask
) {
145 unsigned char bits
, mbits
;
148 static char attr_representation
[64 + 1] =
149 /* STATX_ATTR_ flags: */
150 "????????" /* 63-56 */
151 "????????" /* 55-48 */
152 "????????" /* 47-40 */
153 "????????" /* 39-32 */
154 "????????" /* 31-24 0x00000000-ff000000 */
155 "????????" /* 23-16 0x00000000-00ff0000 */
156 "???me???" /* 15- 8 0x00000000-0000ff00 */
157 "?dai?c??" /* 7- 0 0x00000000-000000ff */
160 printf("Attributes: %016llx (", stx
->stx_attributes
);
161 for (byte
= 64 - 8; byte
>= 0; byte
-= 8) {
162 bits
= stx
->stx_attributes
>> byte
;
163 mbits
= stx
->stx_attributes_mask
>> byte
;
164 for (loop
= 7; loop
>= 0; loop
--) {
165 int bit
= byte
+ loop
;
168 putchar('.'); /* Not supported */
169 else if (bits
& 0x80)
170 putchar(attr_representation
[63 - bit
]);
172 putchar('-'); /* Not set */
183 static void dump_hex(unsigned long long *data
, int from
, int to
)
185 unsigned offset
, print_offset
= 1, col
= 0;
190 for (offset
= from
; offset
< to
; offset
++) {
192 printf("%04x: ", offset
* 8);
195 printf("%016llx", data
[offset
]);
197 if ((col
& 3) == 0) {
209 int main(int argc
, char **argv
)
212 int ret
, raw
= 0, atflag
= AT_SYMLINK_NOFOLLOW
;
214 unsigned int mask
= STATX_ALL
;
216 for (argv
++; *argv
; argv
++) {
217 if (strcmp(*argv
, "-F") == 0) {
218 atflag
&= ~AT_STATX_SYNC_TYPE
;
219 atflag
|= AT_STATX_FORCE_SYNC
;
222 if (strcmp(*argv
, "-D") == 0) {
223 atflag
&= ~AT_STATX_SYNC_TYPE
;
224 atflag
|= AT_STATX_DONT_SYNC
;
227 if (strcmp(*argv
, "-L") == 0) {
228 atflag
&= ~AT_SYMLINK_NOFOLLOW
;
231 if (strcmp(*argv
, "-O") == 0) {
232 mask
&= ~STATX_BASIC_STATS
;
235 if (strcmp(*argv
, "-A") == 0) {
236 atflag
|= AT_NO_AUTOMOUNT
;
239 if (strcmp(*argv
, "-R") == 0) {
244 memset(&stx
, 0xbf, sizeof(stx
));
245 ret
= statx(AT_FDCWD
, *argv
, atflag
, mask
, &stx
);
246 printf("statx(%s) = %d\n", *argv
, ret
);
253 dump_hex((unsigned long long *)&stx
, 0, sizeof(stx
));