From 40cc4168136c0fbb939dec8ffd7828c013f1c568 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 2 Jun 2013 00:54:55 -0500 Subject: Move stat from pending to other, default y. --- toys/other/stat.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 toys/other/stat.c (limited to 'toys/other/stat.c') 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 + * Copyright 2013 + +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 `%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'); + } +} -- cgit v1.2.3