annotate toys/pending/stat.c @ 917:b2697351ce6d

Stat cleanup. Move ftname out of GLOBALS into 'F' handler. Make 'i' zero pad output (zeroes in middle of ID can get lost).
author Rob Landley <rob@landley.net>
date Sun, 02 Jun 2013 00:52:14 -0500
parents b92cb3cc9696
children
rev   line source
rob@810 1 /* stat.c : display file or file system status
rob@810 2 * Copyright 2012 <warior.linux@gmail.com>
rob@917 3 * Copyright 2013 <anand.sinha85@gmail.com>
rob@810 4
felix@886 5 USE_STAT(NEWTOY(stat, "c:f", TOYFLAG_BIN))
rob@810 6
rob@747 7 config STAT
felix@871 8 bool stat
felix@871 9 default n
felix@871 10 help
felix@886 11 usage: stat [-f] [-c FORMAT] FILE...
felix@886 12
rob@912 13 Display status of files or filesystems.
felix@886 14
rob@912 15 -f display filesystem status instead of file status
rob@912 16 -c Output specified FORMAT string instead of default
felix@886 17
rob@912 18 The valid format escape sequences for files:
rob@912 19 %a Access bits (octal) |%A Access bits (flags)|%b Blocks allocated
rob@912 20 %B Bytes per block |%d Device ID (dec) |%D Device ID (hex)
rob@912 21 %f All mode bits (hex) |%F File type |%g Group ID
rob@912 22 %G Group name |%h Hard links |%i Inode
rob@912 23 %n Filename |%N Long filename |%o I/O block size
rob@912 24 %s Size (bytes) |%u User ID |%U User name
rob@912 25 %x Access time |%X Access unix time |%y File write time
rob@912 26 %Y File write unix time|%z Dir change time |%Z Dir change unix time
felix@886 27
rob@912 28 The valid format escape sequences for filesystems:
rob@912 29 %a Available blocks |%b Total blocks |%c Total inodes
rob@912 30 %d Free inodes |%f Free blocks |%i File system ID
rob@912 31 %l Max filename length |%n File name |%s Fragment size
rob@912 32 %S Best transfer size |%t File system type
rob@747 33 */
rob@747 34
rob@747 35 #define FOR_stat
rob@747 36 #include "toys.h"
rob@810 37
rob@747 38 GLOBALS(
rob@912 39 char *fmt;
rob@912 40
rob@914 41 union {
rob@914 42 struct stat st;
rob@914 43 struct statfs sf;
rob@914 44 } stat;
rob@912 45 struct passwd *user_name;
rob@912 46 struct group *group_name;
rob@747 47 )
rob@747 48
rob@747 49
rob@914 50 // Note: the atime, mtime, and ctime fields in struct stat are the start
rob@914 51 // of embedded struct timespec, but posix won't let them use that
rob@914 52 // struct definition for legacy/namespace reasons.
rob@914 53
rob@914 54 static void date_stat_format(struct timespec *ts)
rob@810 55 {
rob@914 56 strftime(toybuf, sizeof(toybuf), "%Y-%m-%d %H:%M:%S",
rob@914 57 localtime(&(ts->tv_sec)));
rob@914 58 xprintf("%s.%09d", toybuf, ts->tv_nsec);
rob@747 59 }
rob@747 60
rob@916 61 static void print_stat(char type)
rob@912 62 {
rob@914 63 struct stat *stat = (struct stat *)&TT.stat;
rob@912 64
rob@916 65 if (type == 'a') xprintf("%04lo", stat->st_mode & ~S_IFMT);
rob@916 66 else if (type == 'A') {
rob@916 67 char str[11];
rob@914 68
rob@916 69 mode_to_string(stat->st_mode, str);
rob@916 70 xprintf("%s", str);
rob@916 71 } else if (type == 'b') xprintf("%llu", stat->st_blocks);
rob@916 72 else if (type == 'B') xprintf("%lu", stat->st_blksize);
rob@916 73 else if (type == 'd') xprintf("%ldd", stat->st_dev);
rob@916 74 else if (type == 'D') xprintf("%llxh", stat->st_dev);
rob@916 75 else if (type == 'f') xprintf("%lx", stat->st_mode);
rob@917 76 else if (type == 'F') {
rob@917 77 char *t = "character device\0directory\0block device\0" \
rob@917 78 "regular file\0symbolic link\0socket\0FIFO (named pipe)";
rob@917 79 int i, filetype = stat->st_mode & S_IFMT;
rob@917 80
rob@917 81 for (i = 1; filetype != (i*8192) && i < 7; i++) t += strlen(t)+1;
rob@917 82 if (!stat->st_size && filetype == S_IFREG) t = "regular empty file";
rob@917 83 xprintf("%s", t);
rob@917 84 } else if (type == 'g') xprintf("%lu", stat->st_gid);
rob@916 85 else if (type == 'G') xprintf("%8s", TT.user_name->pw_name);
rob@916 86 else if (type == 'h') xprintf("%lu", stat->st_nlink);
rob@916 87 else if (type == 'i') xprintf("%llu", stat->st_ino);
rob@916 88 else if (type == 'N') {
rob@916 89 xprintf("`%s'", *toys.optargs);
rob@916 90 if (S_ISLNK(stat->st_mode))
rob@916 91 if (0<readlink(*toys.optargs, toybuf, sizeof(toybuf)))
rob@916 92 xprintf(" -> `%s'", toybuf);
rob@916 93 } else if (type == 'o') xprintf("%lu", stat->st_blksize);
rob@916 94 else if (type == 's') xprintf("%llu", stat->st_size);
rob@916 95 else if (type == 'u') xprintf("%lu", stat->st_uid);
rob@916 96 else if (type == 'U') xprintf("%8s", TT.user_name->pw_name);
rob@916 97 else if (type == 'x') date_stat_format((void *)&stat->st_atime);
rob@916 98 else if (type == 'X') xprintf("%llu", (long long)stat->st_atime);
rob@916 99 else if (type == 'y') date_stat_format((void *)&stat->st_mtime);
rob@916 100 else if (type == 'Y') xprintf("%llu", (long long)stat->st_mtime);
rob@916 101 else if (type == 'z') date_stat_format((void *)&stat->st_ctime);
rob@916 102 else if (type == 'Z') xprintf("%llu", (long long)stat->st_ctime);
rob@916 103 else xprintf("?");
rob@747 104 }
rob@747 105
rob@916 106 static void print_statfs(char type) {
rob@914 107 struct statfs *statfs = (struct statfs *)&TT.stat;
rob@912 108
rob@916 109 if (type == 'a') xprintf("%lu", statfs->f_bavail);
rob@916 110 else if (type == 'b') xprintf("%lu", statfs->f_blocks);
rob@916 111 else if (type == 'c') xprintf("%lu", statfs->f_files);
rob@916 112 else if (type == 'd') xprintf("%lu", statfs->f_ffree);
rob@916 113 else if (type == 'f') xprintf("%lu", statfs->f_bfree);
rob@916 114 else if (type == 'l') xprintf("%ld", statfs->f_namelen);
rob@916 115 else if (type == 't') xprintf("%lx", statfs->f_type);
rob@916 116 else if (type == 'i')
rob@917 117 xprintf("%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
rob@916 118 else if (type == 's') xprintf("%d", statfs->f_frsize);
rob@916 119 else if (type == 'S') xprintf("%d", statfs->f_bsize);
rob@916 120 else xprintf("?");
felix@910 121 }
felix@910 122
rob@810 123 void stat_main(void)
rob@810 124 {
rob@916 125 int flagf = toys.optflags & FLAG_f;
rob@916 126 char *format = flagf
rob@916 127 ? " File: \"%n\"\n ID: %i Namelen: %l Type: %t\n"
rob@916 128 "Block Size: %s Fundamental block size: %S\n"
rob@916 129 "Blocks: Total: %b\tFree: %f\tAvailable: %a\n"
rob@916 130 "Inodes: Total: %c\tFree: %d"
rob@916 131 : " File: %N\n Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n"
rob@916 132 "Device: %D\t Inode: %i\t Links: %h\n"
rob@916 133 "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n"
rob@916 134 "Access: %x\nModify: %y\nChange: %z";
felix@872 135
rob@916 136 if (toys.optflags & FLAG_c) format = TT.fmt;
felix@910 137
felix@910 138 for (; *toys.optargs; toys.optargs++) {
rob@916 139 char *f;
rob@916 140
rob@916 141 if (flagf && !statfs(*toys.optargs, (void *)&TT.stat));
rob@916 142 else if (!flagf && !lstat(*toys.optargs, (void *)&TT.stat)) {
rob@916 143 struct stat *stat = (struct stat*)&TT.stat;
rob@916 144
rob@916 145 // check user and group name
rob@916 146 TT.user_name = getpwuid(stat->st_uid);
rob@916 147 TT.group_name = getgrgid(stat->st_gid);
rob@916 148 } else {
felix@910 149 perror_msg("'%s'", *toys.optargs);
felix@910 150 continue;
felix@910 151 }
rob@916 152
rob@916 153 for (f = format; *f; f++) {
rob@916 154 if (*f != '%') putchar(*f);
rob@916 155 else {
rob@916 156 if (*++f == 'n') xprintf("%s", *toys.optargs);
rob@916 157 else if (flagf) print_statfs(*f);
rob@916 158 else print_stat(*f);
felix@911 159 }
felix@911 160 }
felix@911 161 xputc('\n');
felix@910 162 }
rob@747 163 }