0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define _GNU_SOURCE
0012 #define _ATFILE_SOURCE
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <unistd.h>
0017 #include <ctype.h>
0018 #include <errno.h>
0019 #include <time.h>
0020 #include <sys/syscall.h>
0021 #include <sys/types.h>
0022 #include <linux/stat.h>
0023 #include <linux/fcntl.h>
0024 #define statx foo
0025 #define statx_timestamp foo_timestamp
0026 struct statx;
0027 struct statx_timestamp;
0028 #include <sys/stat.h>
0029 #undef statx
0030 #undef statx_timestamp
0031
0032 #define AT_STATX_SYNC_TYPE 0x6000
0033 #define AT_STATX_SYNC_AS_STAT 0x0000
0034 #define AT_STATX_FORCE_SYNC 0x2000
0035 #define AT_STATX_DONT_SYNC 0x4000
0036
0037 #ifndef __NR_statx
0038 #define __NR_statx -1
0039 #endif
0040
0041 static __attribute__((unused))
0042 ssize_t statx(int dfd, const char *filename, unsigned flags,
0043 unsigned int mask, struct statx *buffer)
0044 {
0045 return syscall(__NR_statx, dfd, filename, flags, mask, buffer);
0046 }
0047
0048 static void print_time(const char *field, struct statx_timestamp *ts)
0049 {
0050 struct tm tm;
0051 time_t tim;
0052 char buffer[100];
0053 int len;
0054
0055 tim = ts->tv_sec;
0056 if (!localtime_r(&tim, &tm)) {
0057 perror("localtime_r");
0058 exit(1);
0059 }
0060 len = strftime(buffer, 100, "%F %T", &tm);
0061 if (len == 0) {
0062 perror("strftime");
0063 exit(1);
0064 }
0065 printf("%s", field);
0066 fwrite(buffer, 1, len, stdout);
0067 printf(".%09u", ts->tv_nsec);
0068 len = strftime(buffer, 100, "%z", &tm);
0069 if (len == 0) {
0070 perror("strftime2");
0071 exit(1);
0072 }
0073 fwrite(buffer, 1, len, stdout);
0074 printf("\n");
0075 }
0076
0077 static void dump_statx(struct statx *stx)
0078 {
0079 char buffer[256], ft = '?';
0080
0081 printf("results=%x\n", stx->stx_mask);
0082
0083 printf(" ");
0084 if (stx->stx_mask & STATX_SIZE)
0085 printf(" Size: %-15llu", (unsigned long long)stx->stx_size);
0086 if (stx->stx_mask & STATX_BLOCKS)
0087 printf(" Blocks: %-10llu", (unsigned long long)stx->stx_blocks);
0088 printf(" IO Block: %-6llu", (unsigned long long)stx->stx_blksize);
0089 if (stx->stx_mask & STATX_TYPE) {
0090 switch (stx->stx_mode & S_IFMT) {
0091 case S_IFIFO: printf(" FIFO\n"); ft = 'p'; break;
0092 case S_IFCHR: printf(" character special file\n"); ft = 'c'; break;
0093 case S_IFDIR: printf(" directory\n"); ft = 'd'; break;
0094 case S_IFBLK: printf(" block special file\n"); ft = 'b'; break;
0095 case S_IFREG: printf(" regular file\n"); ft = '-'; break;
0096 case S_IFLNK: printf(" symbolic link\n"); ft = 'l'; break;
0097 case S_IFSOCK: printf(" socket\n"); ft = 's'; break;
0098 default:
0099 printf(" unknown type (%o)\n", stx->stx_mode & S_IFMT);
0100 break;
0101 }
0102 } else {
0103 printf(" no type\n");
0104 }
0105
0106 sprintf(buffer, "%02x:%02x", stx->stx_dev_major, stx->stx_dev_minor);
0107 printf("Device: %-15s", buffer);
0108 if (stx->stx_mask & STATX_INO)
0109 printf(" Inode: %-11llu", (unsigned long long) stx->stx_ino);
0110 if (stx->stx_mask & STATX_NLINK)
0111 printf(" Links: %-5u", stx->stx_nlink);
0112 if (stx->stx_mask & STATX_TYPE) {
0113 switch (stx->stx_mode & S_IFMT) {
0114 case S_IFBLK:
0115 case S_IFCHR:
0116 printf(" Device type: %u,%u",
0117 stx->stx_rdev_major, stx->stx_rdev_minor);
0118 break;
0119 }
0120 }
0121 printf("\n");
0122
0123 if (stx->stx_mask & STATX_MODE)
0124 printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c) ",
0125 stx->stx_mode & 07777,
0126 ft,
0127 stx->stx_mode & S_IRUSR ? 'r' : '-',
0128 stx->stx_mode & S_IWUSR ? 'w' : '-',
0129 stx->stx_mode & S_IXUSR ? 'x' : '-',
0130 stx->stx_mode & S_IRGRP ? 'r' : '-',
0131 stx->stx_mode & S_IWGRP ? 'w' : '-',
0132 stx->stx_mode & S_IXGRP ? 'x' : '-',
0133 stx->stx_mode & S_IROTH ? 'r' : '-',
0134 stx->stx_mode & S_IWOTH ? 'w' : '-',
0135 stx->stx_mode & S_IXOTH ? 'x' : '-');
0136 if (stx->stx_mask & STATX_UID)
0137 printf("Uid: %5d ", stx->stx_uid);
0138 if (stx->stx_mask & STATX_GID)
0139 printf("Gid: %5d\n", stx->stx_gid);
0140
0141 if (stx->stx_mask & STATX_ATIME)
0142 print_time("Access: ", &stx->stx_atime);
0143 if (stx->stx_mask & STATX_MTIME)
0144 print_time("Modify: ", &stx->stx_mtime);
0145 if (stx->stx_mask & STATX_CTIME)
0146 print_time("Change: ", &stx->stx_ctime);
0147 if (stx->stx_mask & STATX_BTIME)
0148 print_time(" Birth: ", &stx->stx_btime);
0149
0150 if (stx->stx_attributes_mask) {
0151 unsigned char bits, mbits;
0152 int loop, byte;
0153
0154 static char attr_representation[64 + 1] =
0155
0156 "????????"
0157 "????????"
0158 "????????"
0159 "????????"
0160 "????????"
0161 "????????"
0162 "???me???"
0163 "?dai?c??"
0164 ;
0165
0166 printf("Attributes: %016llx (",
0167 (unsigned long long)stx->stx_attributes);
0168 for (byte = 64 - 8; byte >= 0; byte -= 8) {
0169 bits = stx->stx_attributes >> byte;
0170 mbits = stx->stx_attributes_mask >> byte;
0171 for (loop = 7; loop >= 0; loop--) {
0172 int bit = byte + loop;
0173
0174 if (!(mbits & 0x80))
0175 putchar('.');
0176 else if (bits & 0x80)
0177 putchar(attr_representation[63 - bit]);
0178 else
0179 putchar('-');
0180 bits <<= 1;
0181 mbits <<= 1;
0182 }
0183 if (byte)
0184 putchar(' ');
0185 }
0186 printf(")\n");
0187 }
0188 }
0189
0190 static void dump_hex(unsigned long long *data, int from, int to)
0191 {
0192 unsigned offset, print_offset = 1, col = 0;
0193
0194 from /= 8;
0195 to = (to + 7) / 8;
0196
0197 for (offset = from; offset < to; offset++) {
0198 if (print_offset) {
0199 printf("%04x: ", offset * 8);
0200 print_offset = 0;
0201 }
0202 printf("%016llx", data[offset]);
0203 col++;
0204 if ((col & 3) == 0) {
0205 printf("\n");
0206 print_offset = 1;
0207 } else {
0208 printf(" ");
0209 }
0210 }
0211
0212 if (!print_offset)
0213 printf("\n");
0214 }
0215
0216 int main(int argc, char **argv)
0217 {
0218 struct statx stx;
0219 int ret, raw = 0, atflag = AT_SYMLINK_NOFOLLOW;
0220
0221 unsigned int mask = STATX_BASIC_STATS | STATX_BTIME;
0222
0223 for (argv++; *argv; argv++) {
0224 if (strcmp(*argv, "-F") == 0) {
0225 atflag &= ~AT_STATX_SYNC_TYPE;
0226 atflag |= AT_STATX_FORCE_SYNC;
0227 continue;
0228 }
0229 if (strcmp(*argv, "-D") == 0) {
0230 atflag &= ~AT_STATX_SYNC_TYPE;
0231 atflag |= AT_STATX_DONT_SYNC;
0232 continue;
0233 }
0234 if (strcmp(*argv, "-L") == 0) {
0235 atflag &= ~AT_SYMLINK_NOFOLLOW;
0236 continue;
0237 }
0238 if (strcmp(*argv, "-O") == 0) {
0239 mask &= ~STATX_BASIC_STATS;
0240 continue;
0241 }
0242 if (strcmp(*argv, "-A") == 0) {
0243 atflag |= AT_NO_AUTOMOUNT;
0244 continue;
0245 }
0246 if (strcmp(*argv, "-R") == 0) {
0247 raw = 1;
0248 continue;
0249 }
0250
0251 memset(&stx, 0xbf, sizeof(stx));
0252 ret = statx(AT_FDCWD, *argv, atflag, mask, &stx);
0253 printf("statx(%s) = %d\n", *argv, ret);
0254 if (ret < 0) {
0255 perror(*argv);
0256 exit(1);
0257 }
0258
0259 if (raw)
0260 dump_hex((unsigned long long *)&stx, 0, sizeof(stx));
0261
0262 dump_statx(&stx);
0263 }
0264 return 0;
0265 }