test-statx.c 6.5 KB

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