Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Test the statx() system call.
0003  *
0004  * Note that the output of this program is intended to look like the output of
0005  * /bin/stat where possible.
0006  *
0007  * Copyright (C) 2015 Red Hat, Inc. All Rights Reserved.
0008  * Written by David Howells (dhowells@redhat.com)
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             /* STATX_ATTR_ flags: */
0156             "????????"  /* 63-56 */
0157             "????????"  /* 55-48 */
0158             "????????"  /* 47-40 */
0159             "????????"  /* 39-32 */
0160             "????????"  /* 31-24    0x00000000-ff000000 */
0161             "????????"  /* 23-16    0x00000000-00ff0000 */
0162             "???me???"  /* 15- 8    0x00000000-0000ff00 */
0163             "?dai?c??"  /*  7- 0    0x00000000-000000ff */
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('.');   /* Not supported */
0176                 else if (bits & 0x80)
0177                     putchar(attr_representation[63 - bit]);
0178                 else
0179                     putchar('-');   /* Not set */
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 }