aboutsummaryrefslogtreecommitdiff
path: root/toys/other/stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/other/stat.c')
-rw-r--r--toys/other/stat.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/toys/other/stat.c b/toys/other/stat.c
new file mode 100644
index 00000000..c5c96fcb
--- /dev/null
+++ b/toys/other/stat.c
@@ -0,0 +1,163 @@
+/* stat.c : display file or file system status
+ * Copyright 2012 <warior.linux@gmail.com>
+ * Copyright 2013 <anand.sinha85@gmail.com>
+
+USE_STAT(NEWTOY(stat, "c:f", TOYFLAG_BIN))
+
+config STAT
+ bool stat
+ default y
+ help
+ usage: stat [-f] [-c FORMAT] FILE...
+
+ Display status of files or filesystems.
+
+ -f display filesystem status instead of file status
+ -c Output specified FORMAT string instead of default
+
+ The valid format escape sequences for files:
+ %a Access bits (octal) |%A Access bits (flags)|%b Blocks allocated
+ %B Bytes per block |%d Device ID (dec) |%D Device ID (hex)
+ %f All mode bits (hex) |%F File type |%g Group ID
+ %G Group name |%h Hard links |%i Inode
+ %n Filename |%N Long filename |%o I/O block size
+ %s Size (bytes) |%u User ID |%U User name
+ %x Access time |%X Access unix time |%y File write time
+ %Y File write unix time|%z Dir change time |%Z Dir change unix time
+
+ The valid format escape sequences for filesystems:
+ %a Available blocks |%b Total blocks |%c Total inodes
+ %d Free inodes |%f Free blocks |%i File system ID
+ %l Max filename length |%n File name |%s Fragment size
+ %S Best transfer size |%t File system type
+*/
+
+#define FOR_stat
+#include "toys.h"
+
+GLOBALS(
+ char *fmt;
+
+ union {
+ struct stat st;
+ struct statfs sf;
+ } stat;
+ struct passwd *user_name;
+ struct group *group_name;
+)
+
+
+// Note: the atime, mtime, and ctime fields in struct stat are the start
+// of embedded struct timespec, but posix won't let them use that
+// struct definition for legacy/namespace reasons.
+
+static void date_stat_format(struct timespec *ts)
+{
+ strftime(toybuf, sizeof(toybuf), "%Y-%m-%d %H:%M:%S",
+ localtime(&(ts->tv_sec)));
+ xprintf("%s.%09d", toybuf, ts->tv_nsec);
+}
+
+static void print_stat(char type)
+{
+ struct stat *stat = (struct stat *)&TT.stat;
+
+ if (type == 'a') xprintf("%04lo", stat->st_mode & ~S_IFMT);
+ else if (type == 'A') {
+ char str[11];
+
+ mode_to_string(stat->st_mode, str);
+ xprintf("%s", str);
+ } else if (type == 'b') xprintf("%llu", stat->st_blocks);
+ else if (type == 'B') xprintf("%lu", stat->st_blksize);
+ else if (type == 'd') xprintf("%ldd", stat->st_dev);
+ else if (type == 'D') xprintf("%llxh", stat->st_dev);
+ else if (type == 'f') xprintf("%lx", stat->st_mode);
+ else if (type == 'F') {
+ char *t = "character device\0directory\0block device\0" \
+ "regular file\0symbolic link\0socket\0FIFO (named pipe)";
+ int i, filetype = stat->st_mode & S_IFMT;
+
+ for (i = 1; filetype != (i*8192) && i < 7; i++) t += strlen(t)+1;
+ if (!stat->st_size && filetype == S_IFREG) t = "regular empty file";
+ xprintf("%s", t);
+ } else if (type == 'g') xprintf("%lu", stat->st_gid);
+ else if (type == 'G') xprintf("%8s", TT.user_name->pw_name);
+ else if (type == 'h') xprintf("%lu", stat->st_nlink);
+ else if (type == 'i') xprintf("%llu", stat->st_ino);
+ else if (type == 'N') {
+ xprintf("`%s'", *toys.optargs);
+ if (S_ISLNK(stat->st_mode))
+ if (0<readlink(*toys.optargs, toybuf, sizeof(toybuf)))
+ xprintf(" -> `%s'", toybuf);
+ } else if (type == 'o') xprintf("%lu", stat->st_blksize);
+ else if (type == 's') xprintf("%llu", stat->st_size);
+ else if (type == 'u') xprintf("%lu", stat->st_uid);
+ else if (type == 'U') xprintf("%8s", TT.user_name->pw_name);
+ else if (type == 'x') date_stat_format((void *)&stat->st_atime);
+ else if (type == 'X') xprintf("%llu", (long long)stat->st_atime);
+ else if (type == 'y') date_stat_format((void *)&stat->st_mtime);
+ else if (type == 'Y') xprintf("%llu", (long long)stat->st_mtime);
+ else if (type == 'z') date_stat_format((void *)&stat->st_ctime);
+ else if (type == 'Z') xprintf("%llu", (long long)stat->st_ctime);
+ else xprintf("?");
+}
+
+static void print_statfs(char type) {
+ struct statfs *statfs = (struct statfs *)&TT.stat;
+
+ if (type == 'a') xprintf("%lu", statfs->f_bavail);
+ else if (type == 'b') xprintf("%lu", statfs->f_blocks);
+ else if (type == 'c') xprintf("%lu", statfs->f_files);
+ else if (type == 'd') xprintf("%lu", statfs->f_ffree);
+ else if (type == 'f') xprintf("%lu", statfs->f_bfree);
+ else if (type == 'l') xprintf("%ld", statfs->f_namelen);
+ else if (type == 't') xprintf("%lx", statfs->f_type);
+ else if (type == 'i')
+ xprintf("%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
+ else if (type == 's') xprintf("%d", statfs->f_frsize);
+ else if (type == 'S') xprintf("%d", statfs->f_bsize);
+ else xprintf("?");
+}
+
+void stat_main(void)
+{
+ int flagf = toys.optflags & FLAG_f;
+ char *format = flagf
+ ? " File: \"%n\"\n ID: %i Namelen: %l Type: %t\n"
+ "Block Size: %s Fundamental block size: %S\n"
+ "Blocks: Total: %b\tFree: %f\tAvailable: %a\n"
+ "Inodes: Total: %c\tFree: %d"
+ : " File: %N\n Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n"
+ "Device: %D\t Inode: %i\t Links: %h\n"
+ "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n"
+ "Access: %x\nModify: %y\nChange: %z";
+
+ if (toys.optflags & FLAG_c) format = TT.fmt;
+
+ for (; *toys.optargs; toys.optargs++) {
+ char *f;
+
+ if (flagf && !statfs(*toys.optargs, (void *)&TT.stat));
+ else if (!flagf && !lstat(*toys.optargs, (void *)&TT.stat)) {
+ struct stat *stat = (struct stat*)&TT.stat;
+
+ // check user and group name
+ TT.user_name = getpwuid(stat->st_uid);
+ TT.group_name = getgrgid(stat->st_gid);
+ } else {
+ perror_msg("'%s'", *toys.optargs);
+ continue;
+ }
+
+ for (f = format; *f; f++) {
+ if (*f != '%') putchar(*f);
+ else {
+ if (*++f == 'n') xprintf("%s", *toys.optargs);
+ else if (flagf) print_statfs(*f);
+ else print_stat(*f);
+ }
+ }
+ xputc('\n');
+ }
+}