18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Test the statx() system call. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Note that the output of this program is intended to look like the output of 58c2ecf20Sopenharmony_ci * /bin/stat where possible. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2015 Red Hat, Inc. All Rights Reserved. 88c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define _GNU_SOURCE 128c2ecf20Sopenharmony_ci#define _ATFILE_SOURCE 138c2ecf20Sopenharmony_ci#include <stdio.h> 148c2ecf20Sopenharmony_ci#include <stdlib.h> 158c2ecf20Sopenharmony_ci#include <string.h> 168c2ecf20Sopenharmony_ci#include <unistd.h> 178c2ecf20Sopenharmony_ci#include <ctype.h> 188c2ecf20Sopenharmony_ci#include <errno.h> 198c2ecf20Sopenharmony_ci#include <time.h> 208c2ecf20Sopenharmony_ci#include <sys/syscall.h> 218c2ecf20Sopenharmony_ci#include <sys/types.h> 228c2ecf20Sopenharmony_ci#include <linux/stat.h> 238c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 248c2ecf20Sopenharmony_ci#define statx foo 258c2ecf20Sopenharmony_ci#define statx_timestamp foo_timestamp 268c2ecf20Sopenharmony_cistruct statx; 278c2ecf20Sopenharmony_cistruct statx_timestamp; 288c2ecf20Sopenharmony_ci#include <sys/stat.h> 298c2ecf20Sopenharmony_ci#undef statx 308c2ecf20Sopenharmony_ci#undef statx_timestamp 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define AT_STATX_SYNC_TYPE 0x6000 338c2ecf20Sopenharmony_ci#define AT_STATX_SYNC_AS_STAT 0x0000 348c2ecf20Sopenharmony_ci#define AT_STATX_FORCE_SYNC 0x2000 358c2ecf20Sopenharmony_ci#define AT_STATX_DONT_SYNC 0x4000 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#ifndef __NR_statx 388c2ecf20Sopenharmony_ci#define __NR_statx -1 398c2ecf20Sopenharmony_ci#endif 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic __attribute__((unused)) 428c2ecf20Sopenharmony_cissize_t statx(int dfd, const char *filename, unsigned flags, 438c2ecf20Sopenharmony_ci unsigned int mask, struct statx *buffer) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return syscall(__NR_statx, dfd, filename, flags, mask, buffer); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void print_time(const char *field, struct statx_timestamp *ts) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct tm tm; 518c2ecf20Sopenharmony_ci time_t tim; 528c2ecf20Sopenharmony_ci char buffer[100]; 538c2ecf20Sopenharmony_ci int len; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci tim = ts->tv_sec; 568c2ecf20Sopenharmony_ci if (!localtime_r(&tim, &tm)) { 578c2ecf20Sopenharmony_ci perror("localtime_r"); 588c2ecf20Sopenharmony_ci exit(1); 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci len = strftime(buffer, 100, "%F %T", &tm); 618c2ecf20Sopenharmony_ci if (len == 0) { 628c2ecf20Sopenharmony_ci perror("strftime"); 638c2ecf20Sopenharmony_ci exit(1); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci printf("%s", field); 668c2ecf20Sopenharmony_ci fwrite(buffer, 1, len, stdout); 678c2ecf20Sopenharmony_ci printf(".%09u", ts->tv_nsec); 688c2ecf20Sopenharmony_ci len = strftime(buffer, 100, "%z", &tm); 698c2ecf20Sopenharmony_ci if (len == 0) { 708c2ecf20Sopenharmony_ci perror("strftime2"); 718c2ecf20Sopenharmony_ci exit(1); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci fwrite(buffer, 1, len, stdout); 748c2ecf20Sopenharmony_ci printf("\n"); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void dump_statx(struct statx *stx) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci char buffer[256], ft = '?'; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci printf("results=%x\n", stx->stx_mask); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci printf(" "); 848c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_SIZE) 858c2ecf20Sopenharmony_ci printf(" Size: %-15llu", (unsigned long long)stx->stx_size); 868c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_BLOCKS) 878c2ecf20Sopenharmony_ci printf(" Blocks: %-10llu", (unsigned long long)stx->stx_blocks); 888c2ecf20Sopenharmony_ci printf(" IO Block: %-6llu", (unsigned long long)stx->stx_blksize); 898c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_TYPE) { 908c2ecf20Sopenharmony_ci switch (stx->stx_mode & S_IFMT) { 918c2ecf20Sopenharmony_ci case S_IFIFO: printf(" FIFO\n"); ft = 'p'; break; 928c2ecf20Sopenharmony_ci case S_IFCHR: printf(" character special file\n"); ft = 'c'; break; 938c2ecf20Sopenharmony_ci case S_IFDIR: printf(" directory\n"); ft = 'd'; break; 948c2ecf20Sopenharmony_ci case S_IFBLK: printf(" block special file\n"); ft = 'b'; break; 958c2ecf20Sopenharmony_ci case S_IFREG: printf(" regular file\n"); ft = '-'; break; 968c2ecf20Sopenharmony_ci case S_IFLNK: printf(" symbolic link\n"); ft = 'l'; break; 978c2ecf20Sopenharmony_ci case S_IFSOCK: printf(" socket\n"); ft = 's'; break; 988c2ecf20Sopenharmony_ci default: 998c2ecf20Sopenharmony_ci printf(" unknown type (%o)\n", stx->stx_mode & S_IFMT); 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci printf(" no type\n"); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci sprintf(buffer, "%02x:%02x", stx->stx_dev_major, stx->stx_dev_minor); 1078c2ecf20Sopenharmony_ci printf("Device: %-15s", buffer); 1088c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_INO) 1098c2ecf20Sopenharmony_ci printf(" Inode: %-11llu", (unsigned long long) stx->stx_ino); 1108c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_NLINK) 1118c2ecf20Sopenharmony_ci printf(" Links: %-5u", stx->stx_nlink); 1128c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_TYPE) { 1138c2ecf20Sopenharmony_ci switch (stx->stx_mode & S_IFMT) { 1148c2ecf20Sopenharmony_ci case S_IFBLK: 1158c2ecf20Sopenharmony_ci case S_IFCHR: 1168c2ecf20Sopenharmony_ci printf(" Device type: %u,%u", 1178c2ecf20Sopenharmony_ci stx->stx_rdev_major, stx->stx_rdev_minor); 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci printf("\n"); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_MODE) 1248c2ecf20Sopenharmony_ci printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c) ", 1258c2ecf20Sopenharmony_ci stx->stx_mode & 07777, 1268c2ecf20Sopenharmony_ci ft, 1278c2ecf20Sopenharmony_ci stx->stx_mode & S_IRUSR ? 'r' : '-', 1288c2ecf20Sopenharmony_ci stx->stx_mode & S_IWUSR ? 'w' : '-', 1298c2ecf20Sopenharmony_ci stx->stx_mode & S_IXUSR ? 'x' : '-', 1308c2ecf20Sopenharmony_ci stx->stx_mode & S_IRGRP ? 'r' : '-', 1318c2ecf20Sopenharmony_ci stx->stx_mode & S_IWGRP ? 'w' : '-', 1328c2ecf20Sopenharmony_ci stx->stx_mode & S_IXGRP ? 'x' : '-', 1338c2ecf20Sopenharmony_ci stx->stx_mode & S_IROTH ? 'r' : '-', 1348c2ecf20Sopenharmony_ci stx->stx_mode & S_IWOTH ? 'w' : '-', 1358c2ecf20Sopenharmony_ci stx->stx_mode & S_IXOTH ? 'x' : '-'); 1368c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_UID) 1378c2ecf20Sopenharmony_ci printf("Uid: %5d ", stx->stx_uid); 1388c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_GID) 1398c2ecf20Sopenharmony_ci printf("Gid: %5d\n", stx->stx_gid); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_ATIME) 1428c2ecf20Sopenharmony_ci print_time("Access: ", &stx->stx_atime); 1438c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_MTIME) 1448c2ecf20Sopenharmony_ci print_time("Modify: ", &stx->stx_mtime); 1458c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_CTIME) 1468c2ecf20Sopenharmony_ci print_time("Change: ", &stx->stx_ctime); 1478c2ecf20Sopenharmony_ci if (stx->stx_mask & STATX_BTIME) 1488c2ecf20Sopenharmony_ci print_time(" Birth: ", &stx->stx_btime); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (stx->stx_attributes_mask) { 1518c2ecf20Sopenharmony_ci unsigned char bits, mbits; 1528c2ecf20Sopenharmony_ci int loop, byte; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci static char attr_representation[64 + 1] = 1558c2ecf20Sopenharmony_ci /* STATX_ATTR_ flags: */ 1568c2ecf20Sopenharmony_ci "????????" /* 63-56 */ 1578c2ecf20Sopenharmony_ci "????????" /* 55-48 */ 1588c2ecf20Sopenharmony_ci "????????" /* 47-40 */ 1598c2ecf20Sopenharmony_ci "????????" /* 39-32 */ 1608c2ecf20Sopenharmony_ci "????????" /* 31-24 0x00000000-ff000000 */ 1618c2ecf20Sopenharmony_ci "????????" /* 23-16 0x00000000-00ff0000 */ 1628c2ecf20Sopenharmony_ci "???me???" /* 15- 8 0x00000000-0000ff00 */ 1638c2ecf20Sopenharmony_ci "?dai?c??" /* 7- 0 0x00000000-000000ff */ 1648c2ecf20Sopenharmony_ci ; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci printf("Attributes: %016llx (", 1678c2ecf20Sopenharmony_ci (unsigned long long)stx->stx_attributes); 1688c2ecf20Sopenharmony_ci for (byte = 64 - 8; byte >= 0; byte -= 8) { 1698c2ecf20Sopenharmony_ci bits = stx->stx_attributes >> byte; 1708c2ecf20Sopenharmony_ci mbits = stx->stx_attributes_mask >> byte; 1718c2ecf20Sopenharmony_ci for (loop = 7; loop >= 0; loop--) { 1728c2ecf20Sopenharmony_ci int bit = byte + loop; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!(mbits & 0x80)) 1758c2ecf20Sopenharmony_ci putchar('.'); /* Not supported */ 1768c2ecf20Sopenharmony_ci else if (bits & 0x80) 1778c2ecf20Sopenharmony_ci putchar(attr_representation[63 - bit]); 1788c2ecf20Sopenharmony_ci else 1798c2ecf20Sopenharmony_ci putchar('-'); /* Not set */ 1808c2ecf20Sopenharmony_ci bits <<= 1; 1818c2ecf20Sopenharmony_ci mbits <<= 1; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci if (byte) 1848c2ecf20Sopenharmony_ci putchar(' '); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci printf(")\n"); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void dump_hex(unsigned long long *data, int from, int to) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci unsigned offset, print_offset = 1, col = 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci from /= 8; 1958c2ecf20Sopenharmony_ci to = (to + 7) / 8; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci for (offset = from; offset < to; offset++) { 1988c2ecf20Sopenharmony_ci if (print_offset) { 1998c2ecf20Sopenharmony_ci printf("%04x: ", offset * 8); 2008c2ecf20Sopenharmony_ci print_offset = 0; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci printf("%016llx", data[offset]); 2038c2ecf20Sopenharmony_ci col++; 2048c2ecf20Sopenharmony_ci if ((col & 3) == 0) { 2058c2ecf20Sopenharmony_ci printf("\n"); 2068c2ecf20Sopenharmony_ci print_offset = 1; 2078c2ecf20Sopenharmony_ci } else { 2088c2ecf20Sopenharmony_ci printf(" "); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!print_offset) 2138c2ecf20Sopenharmony_ci printf("\n"); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ciint main(int argc, char **argv) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct statx stx; 2198c2ecf20Sopenharmony_ci int ret, raw = 0, atflag = AT_SYMLINK_NOFOLLOW; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci unsigned int mask = STATX_BASIC_STATS | STATX_BTIME; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci for (argv++; *argv; argv++) { 2248c2ecf20Sopenharmony_ci if (strcmp(*argv, "-F") == 0) { 2258c2ecf20Sopenharmony_ci atflag &= ~AT_STATX_SYNC_TYPE; 2268c2ecf20Sopenharmony_ci atflag |= AT_STATX_FORCE_SYNC; 2278c2ecf20Sopenharmony_ci continue; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci if (strcmp(*argv, "-D") == 0) { 2308c2ecf20Sopenharmony_ci atflag &= ~AT_STATX_SYNC_TYPE; 2318c2ecf20Sopenharmony_ci atflag |= AT_STATX_DONT_SYNC; 2328c2ecf20Sopenharmony_ci continue; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci if (strcmp(*argv, "-L") == 0) { 2358c2ecf20Sopenharmony_ci atflag &= ~AT_SYMLINK_NOFOLLOW; 2368c2ecf20Sopenharmony_ci continue; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci if (strcmp(*argv, "-O") == 0) { 2398c2ecf20Sopenharmony_ci mask &= ~STATX_BASIC_STATS; 2408c2ecf20Sopenharmony_ci continue; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci if (strcmp(*argv, "-A") == 0) { 2438c2ecf20Sopenharmony_ci atflag |= AT_NO_AUTOMOUNT; 2448c2ecf20Sopenharmony_ci continue; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci if (strcmp(*argv, "-R") == 0) { 2478c2ecf20Sopenharmony_ci raw = 1; 2488c2ecf20Sopenharmony_ci continue; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci memset(&stx, 0xbf, sizeof(stx)); 2528c2ecf20Sopenharmony_ci ret = statx(AT_FDCWD, *argv, atflag, mask, &stx); 2538c2ecf20Sopenharmony_ci printf("statx(%s) = %d\n", *argv, ret); 2548c2ecf20Sopenharmony_ci if (ret < 0) { 2558c2ecf20Sopenharmony_ci perror(*argv); 2568c2ecf20Sopenharmony_ci exit(1); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (raw) 2608c2ecf20Sopenharmony_ci dump_hex((unsigned long long *)&stx, 0, sizeof(stx)); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci dump_statx(&stx); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 266