stat.c revision 1ca8a440323d04164efab68ed8f507f1c6ae84d9
1/* stat.c : display file or file system status 2 * Copyright 2012 <warior.linux@gmail.com> 3 * Copyright 2013 <anand.sinha85@gmail.com> 4 5USE_STAT(NEWTOY(stat, "c:f", TOYFLAG_BIN)) 6 7config STAT 8 bool stat 9 default y 10 help 11 usage: stat [-f] [-c FORMAT] FILE... 12 13 Display status of files or filesystems. 14 15 -f display filesystem status instead of file status 16 -c Output specified FORMAT string instead of default 17 18 The valid format escape sequences for files: 19 %a Access bits (octal) |%A Access bits (flags)|%b Blocks allocated 20 %B Bytes per block |%d Device ID (dec) |%D Device ID (hex) 21 %f All mode bits (hex) |%F File type |%g Group ID 22 %G Group name |%h Hard links |%i Inode 23 %n Filename |%N Long filename |%o I/O block size 24 %s Size (bytes) |%u User ID |%U User name 25 %x Access time |%X Access unix time |%y File write time 26 %Y File write unix time|%z Dir change time |%Z Dir change unix time 27 28 The valid format escape sequences for filesystems: 29 %a Available blocks |%b Total blocks |%c Total inodes 30 %d Free inodes |%f Free blocks |%i File system ID 31 %l Max filename length |%n File name |%s Fragment size 32 %S Best transfer size |%t Filesystem type |%T Filesystem type name 33*/ 34 35#define FOR_stat 36#include "toys.h" 37 38GLOBALS( 39 char *fmt; 40 41 union { 42 struct stat st; 43 struct statfs sf; 44 } stat; 45 struct passwd *user_name; 46 struct group *group_name; 47) 48 49 50// Note: the atime, mtime, and ctime fields in struct stat are the start 51// of embedded struct timespec, but posix won't let them use that 52// struct definition for legacy/namespace reasons. 53 54static void date_stat_format(struct timespec *ts) 55{ 56 strftime(toybuf, sizeof(toybuf), "%Y-%m-%d %H:%M:%S", 57 localtime(&(ts->tv_sec))); 58 xprintf("%s.%09d", toybuf, ts->tv_nsec); 59} 60 61static void print_stat(char type) 62{ 63 struct stat *stat = (struct stat *)&TT.stat; 64 65 if (type == 'a') xprintf("%lo", stat->st_mode & ~S_IFMT); 66 else if (type == 'A') { 67 char str[11]; 68 69 mode_to_string(stat->st_mode, str); 70 xprintf("%s", str); 71 } else if (type == 'b') xprintf("%llu", stat->st_blocks); 72 else if (type == 'B') xprintf("%lu", stat->st_blksize); 73 else if (type == 'd') xprintf("%ldd", stat->st_dev); 74 else if (type == 'D') xprintf("%llxh", stat->st_dev); 75 else if (type == 'f') xprintf("%lx", stat->st_mode); 76 else if (type == 'F') { 77 char *t = "character device\0directory\0block device\0" \ 78 "regular file\0symbolic link\0socket\0FIFO (named pipe)"; 79 int i, filetype = stat->st_mode & S_IFMT; 80 81 for (i = 1; filetype != (i*8192) && i < 7; i++) t += strlen(t)+1; 82 if (!stat->st_size && filetype == S_IFREG) t = "regular empty file"; 83 xprintf("%s", t); 84 } else if (type == 'g') xprintf("%lu", stat->st_gid); 85 else if (type == 'G') xprintf("%8s", TT.group_name->gr_name); 86 else if (type == 'h') xprintf("%lu", stat->st_nlink); 87 else if (type == 'i') xprintf("%llu", stat->st_ino); 88 else if (type == 'N') { 89 xprintf("`%s'", *toys.optargs); 90 if (S_ISLNK(stat->st_mode)) 91 if (0<readlink(*toys.optargs, toybuf, sizeof(toybuf))) 92 xprintf(" -> `%s'", toybuf); 93 } else if (type == 'o') xprintf("%lu", stat->st_blksize); 94 else if (type == 's') xprintf("%llu", stat->st_size); 95 else if (type == 'u') xprintf("%lu", stat->st_uid); 96 else if (type == 'U') xprintf("%8s", TT.user_name->pw_name); 97 else if (type == 'x') date_stat_format((void *)&stat->st_atime); 98 else if (type == 'X') xprintf("%llu", (long long)stat->st_atime); 99 else if (type == 'y') date_stat_format((void *)&stat->st_mtime); 100 else if (type == 'Y') xprintf("%llu", (long long)stat->st_mtime); 101 else if (type == 'z') date_stat_format((void *)&stat->st_ctime); 102 else if (type == 'Z') xprintf("%llu", (long long)stat->st_ctime); 103 else xprintf("?"); 104} 105 106static void print_statfs(char type) { 107 struct statfs *statfs = (struct statfs *)&TT.stat; 108 109 if (type == 'a') xprintf("%llu", statfs->f_bavail); 110 else if (type == 'b') xprintf("%llu", statfs->f_blocks); 111 else if (type == 'c') xprintf("%llu", statfs->f_files); 112 else if (type == 'd') xprintf("%llu", statfs->f_ffree); 113 else if (type == 'f') xprintf("%llu", statfs->f_bfree); 114 else if (type == 'l') xprintf("%ld", statfs->f_namelen); 115 else if (type == 't') xprintf("%lx", statfs->f_type); 116 else if (type == 'T') { 117 char *s = "unknown"; 118 struct {unsigned num; char *name;} nn[] = { 119 {0xADFF, "affs"}, {0x5346544e, "ntfs"}, {0x1Cd1, "devpts"}, 120 {0x137D, "ext"}, {0xEF51, "ext2"}, {0xEF53, "ext3"}, 121 {0x1BADFACE, "bfs"}, {0x9123683E, "btrfs"}, {0x28cd3d45, "cramfs"}, 122 {0x3153464a, "jfs"}, {0x7275, "romfs"}, {0x01021994, "tmpfs"}, 123 {0x3434, "nilfs"}, {0x6969, "nfs"}, {0x9fa0, "proc"}, 124 {0x534F434B, "sockfs"}, {0x62656572, "sysfs"}, {0x517B, "smb"}, 125 {0x4d44, "msdos"}, {0x4006, "fat"}, {0x43415d53, "smackfs"}, 126 {0x73717368, "squashfs"} 127 }; 128 int i; 129 130 for (i=0; i<ARRAY_LEN(nn); i++) 131 if (nn[i].num == statfs->f_type) s = nn[i].name; 132 xprintf(s); 133 } else if (type == 'i') 134 xprintf("%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]); 135 else if (type == 's') xprintf("%d", statfs->f_frsize); 136 else if (type == 'S') xprintf("%d", statfs->f_bsize); 137 else xprintf("?"); 138} 139 140void stat_main(void) 141{ 142 int flagf = toys.optflags & FLAG_f; 143 char *format = flagf 144 ? " File: \"%n\"\n ID: %i Namelen: %l Type: %t\n" 145 "Block Size: %s Fundamental block size: %S\n" 146 "Blocks: Total: %b\tFree: %f\tAvailable: %a\n" 147 "Inodes: Total: %c\tFree: %d" 148 : " File: %N\n Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n" 149 "Device: %D\t Inode: %i\t Links: %h\n" 150 "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n" 151 "Access: %x\nModify: %y\nChange: %z"; 152 153 if (toys.optflags & FLAG_c) format = TT.fmt; 154 155 for (; *toys.optargs; toys.optargs++) { 156 char *f; 157 158 if (flagf && !statfs(*toys.optargs, (void *)&TT.stat)); 159 else if (!flagf && !lstat(*toys.optargs, (void *)&TT.stat)) { 160 struct stat *stat = (struct stat*)&TT.stat; 161 162 // check user and group name 163 TT.user_name = getpwuid(stat->st_uid); 164 TT.group_name = getgrgid(stat->st_gid); 165 } else { 166 perror_msg("'%s'", *toys.optargs); 167 continue; 168 } 169 170 for (f = format; *f; f++) { 171 if (*f != '%') putchar(*f); 172 else { 173 if (*++f == 'n') xprintf("%s", *toys.optargs); 174 else if (flagf) print_statfs(*f); 175 else print_stat(*f); 176 } 177 } 178 xputc('\n'); 179 } 180} 181