• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /* Test the statx() system call.
3   *
4   * Note that the output of this program is intended to look like the output of
5   * /bin/stat where possible.
6   *
7   * Copyright (C) 2015 Red Hat, Inc. All Rights Reserved.
8   * Written by David Howells (dhowells@redhat.com)
9   */
10  
11  #define _GNU_SOURCE
12  #define _ATFILE_SOURCE
13  #include <stdio.h>
14  #include <stdlib.h>
15  #include <string.h>
16  #include <unistd.h>
17  #include <ctype.h>
18  #include <errno.h>
19  #include <time.h>
20  #include <sys/syscall.h>
21  #include <sys/types.h>
22  #include <linux/stat.h>
23  #include <linux/fcntl.h>
24  #define statx foo
25  #define statx_timestamp foo_timestamp
26  struct statx;
27  struct statx_timestamp;
28  #include <sys/stat.h>
29  #undef statx
30  #undef statx_timestamp
31  
32  #define AT_STATX_SYNC_TYPE	0x6000
33  #define AT_STATX_SYNC_AS_STAT	0x0000
34  #define AT_STATX_FORCE_SYNC	0x2000
35  #define AT_STATX_DONT_SYNC	0x4000
36  
37  #ifndef __NR_statx
38  #define __NR_statx -1
39  #endif
40  
41  static __attribute__((unused))
statx(int dfd,const char * filename,unsigned flags,unsigned int mask,struct statx * buffer)42  ssize_t statx(int dfd, const char *filename, unsigned flags,
43  	      unsigned int mask, struct statx *buffer)
44  {
45  	return syscall(__NR_statx, dfd, filename, flags, mask, buffer);
46  }
47  
print_time(const char * field,struct statx_timestamp * ts)48  static void print_time(const char *field, struct statx_timestamp *ts)
49  {
50  	struct tm tm;
51  	time_t tim;
52  	char buffer[100];
53  	int len;
54  
55  	tim = ts->tv_sec;
56  	if (!localtime_r(&tim, &tm)) {
57  		perror("localtime_r");
58  		exit(1);
59  	}
60  	len = strftime(buffer, 100, "%F %T", &tm);
61  	if (len == 0) {
62  		perror("strftime");
63  		exit(1);
64  	}
65  	printf("%s", field);
66  	fwrite(buffer, 1, len, stdout);
67  	printf(".%09u", ts->tv_nsec);
68  	len = strftime(buffer, 100, "%z", &tm);
69  	if (len == 0) {
70  		perror("strftime2");
71  		exit(1);
72  	}
73  	fwrite(buffer, 1, len, stdout);
74  	printf("\n");
75  }
76  
dump_statx(struct statx * stx)77  static void dump_statx(struct statx *stx)
78  {
79  	char buffer[256], ft = '?';
80  
81  	printf("results=%x\n", stx->stx_mask);
82  
83  	printf(" ");
84  	if (stx->stx_mask & STATX_SIZE)
85  		printf(" Size: %-15llu", (unsigned long long)stx->stx_size);
86  	if (stx->stx_mask & STATX_BLOCKS)
87  		printf(" Blocks: %-10llu", (unsigned long long)stx->stx_blocks);
88  	printf(" IO Block: %-6llu", (unsigned long long)stx->stx_blksize);
89  	if (stx->stx_mask & STATX_TYPE) {
90  		switch (stx->stx_mode & S_IFMT) {
91  		case S_IFIFO:	printf("  FIFO\n");			ft = 'p'; break;
92  		case S_IFCHR:	printf("  character special file\n");	ft = 'c'; break;
93  		case S_IFDIR:	printf("  directory\n");		ft = 'd'; break;
94  		case S_IFBLK:	printf("  block special file\n");	ft = 'b'; break;
95  		case S_IFREG:	printf("  regular file\n");		ft = '-'; break;
96  		case S_IFLNK:	printf("  symbolic link\n");		ft = 'l'; break;
97  		case S_IFSOCK:	printf("  socket\n");			ft = 's'; break;
98  		default:
99  			printf(" unknown type (%o)\n", stx->stx_mode & S_IFMT);
100  			break;
101  		}
102  	} else {
103  		printf(" no type\n");
104  	}
105  
106  	sprintf(buffer, "%02x:%02x", stx->stx_dev_major, stx->stx_dev_minor);
107  	printf("Device: %-15s", buffer);
108  	if (stx->stx_mask & STATX_INO)
109  		printf(" Inode: %-11llu", (unsigned long long) stx->stx_ino);
110  	if (stx->stx_mask & STATX_NLINK)
111  		printf(" Links: %-5u", stx->stx_nlink);
112  	if (stx->stx_mask & STATX_TYPE) {
113  		switch (stx->stx_mode & S_IFMT) {
114  		case S_IFBLK:
115  		case S_IFCHR:
116  			printf(" Device type: %u,%u",
117  			       stx->stx_rdev_major, stx->stx_rdev_minor);
118  			break;
119  		}
120  	}
121  	printf("\n");
122  
123  	if (stx->stx_mask & STATX_MODE)
124  		printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c)  ",
125  		       stx->stx_mode & 07777,
126  		       ft,
127  		       stx->stx_mode & S_IRUSR ? 'r' : '-',
128  		       stx->stx_mode & S_IWUSR ? 'w' : '-',
129  		       stx->stx_mode & S_IXUSR ? 'x' : '-',
130  		       stx->stx_mode & S_IRGRP ? 'r' : '-',
131  		       stx->stx_mode & S_IWGRP ? 'w' : '-',
132  		       stx->stx_mode & S_IXGRP ? 'x' : '-',
133  		       stx->stx_mode & S_IROTH ? 'r' : '-',
134  		       stx->stx_mode & S_IWOTH ? 'w' : '-',
135  		       stx->stx_mode & S_IXOTH ? 'x' : '-');
136  	if (stx->stx_mask & STATX_UID)
137  		printf("Uid: %5d   ", stx->stx_uid);
138  	if (stx->stx_mask & STATX_GID)
139  		printf("Gid: %5d\n", stx->stx_gid);
140  
141  	if (stx->stx_mask & STATX_ATIME)
142  		print_time("Access: ", &stx->stx_atime);
143  	if (stx->stx_mask & STATX_MTIME)
144  		print_time("Modify: ", &stx->stx_mtime);
145  	if (stx->stx_mask & STATX_CTIME)
146  		print_time("Change: ", &stx->stx_ctime);
147  	if (stx->stx_mask & STATX_BTIME)
148  		print_time(" Birth: ", &stx->stx_btime);
149  
150  	if (stx->stx_attributes_mask) {
151  		unsigned char bits, mbits;
152  		int loop, byte;
153  
154  		static char attr_representation[64 + 1] =
155  			/* STATX_ATTR_ flags: */
156  			"????????"	/* 63-56 */
157  			"????????"	/* 55-48 */
158  			"????????"	/* 47-40 */
159  			"????????"	/* 39-32 */
160  			"????????"	/* 31-24	0x00000000-ff000000 */
161  			"????????"	/* 23-16	0x00000000-00ff0000 */
162  			"???me???"	/* 15- 8	0x00000000-0000ff00 */
163  			"?dai?c??"	/*  7- 0	0x00000000-000000ff */
164  			;
165  
166  		printf("Attributes: %016llx (",
167  		       (unsigned long long)stx->stx_attributes);
168  		for (byte = 64 - 8; byte >= 0; byte -= 8) {
169  			bits = stx->stx_attributes >> byte;
170  			mbits = stx->stx_attributes_mask >> byte;
171  			for (loop = 7; loop >= 0; loop--) {
172  				int bit = byte + loop;
173  
174  				if (!(mbits & 0x80))
175  					putchar('.');	/* Not supported */
176  				else if (bits & 0x80)
177  					putchar(attr_representation[63 - bit]);
178  				else
179  					putchar('-');	/* Not set */
180  				bits <<= 1;
181  				mbits <<= 1;
182  			}
183  			if (byte)
184  				putchar(' ');
185  		}
186  		printf(")\n");
187  	}
188  }
189  
dump_hex(unsigned long long * data,int from,int to)190  static void dump_hex(unsigned long long *data, int from, int to)
191  {
192  	unsigned offset, print_offset = 1, col = 0;
193  
194  	from /= 8;
195  	to = (to + 7) / 8;
196  
197  	for (offset = from; offset < to; offset++) {
198  		if (print_offset) {
199  			printf("%04x: ", offset * 8);
200  			print_offset = 0;
201  		}
202  		printf("%016llx", data[offset]);
203  		col++;
204  		if ((col & 3) == 0) {
205  			printf("\n");
206  			print_offset = 1;
207  		} else {
208  			printf(" ");
209  		}
210  	}
211  
212  	if (!print_offset)
213  		printf("\n");
214  }
215  
main(int argc,char ** argv)216  int main(int argc, char **argv)
217  {
218  	struct statx stx;
219  	int ret, raw = 0, atflag = AT_SYMLINK_NOFOLLOW;
220  
221  	unsigned int mask = STATX_BASIC_STATS | STATX_BTIME;
222  
223  	for (argv++; *argv; argv++) {
224  		if (strcmp(*argv, "-F") == 0) {
225  			atflag &= ~AT_STATX_SYNC_TYPE;
226  			atflag |= AT_STATX_FORCE_SYNC;
227  			continue;
228  		}
229  		if (strcmp(*argv, "-D") == 0) {
230  			atflag &= ~AT_STATX_SYNC_TYPE;
231  			atflag |= AT_STATX_DONT_SYNC;
232  			continue;
233  		}
234  		if (strcmp(*argv, "-L") == 0) {
235  			atflag &= ~AT_SYMLINK_NOFOLLOW;
236  			continue;
237  		}
238  		if (strcmp(*argv, "-O") == 0) {
239  			mask &= ~STATX_BASIC_STATS;
240  			continue;
241  		}
242  		if (strcmp(*argv, "-A") == 0) {
243  			atflag |= AT_NO_AUTOMOUNT;
244  			continue;
245  		}
246  		if (strcmp(*argv, "-R") == 0) {
247  			raw = 1;
248  			continue;
249  		}
250  
251  		memset(&stx, 0xbf, sizeof(stx));
252  		ret = statx(AT_FDCWD, *argv, atflag, mask, &stx);
253  		printf("statx(%s) = %d\n", *argv, ret);
254  		if (ret < 0) {
255  			perror(*argv);
256  			exit(1);
257  		}
258  
259  		if (raw)
260  			dump_hex((unsigned long long *)&stx, 0, sizeof(stx));
261  
262  		dump_statx(&stx);
263  	}
264  	return 0;
265  }
266