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