test-statx.c 6.6 KB

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