Mercurial > hg > toybox
comparison toys/pending/stat.c @ 916:b92cb3cc9696
Stat cleanup.
lib: rename format_mode() to mode_to_string() (echoing string_to_mode), make it
take a normal char * argument.
stat: collapse big switch/case statements that only have one line each
into if/else staircase (much fewer lines of code). Remove return type
(other stat implementations print ? for unknown escapes, so do that here).
Inline do_stat() and do_statfs(). Set default string in normal local
variable "format". Remove unnecessary struct d. Restructure stat logic to
"if (flagf && !statfs()) else if (!flagf && !stat()) else perror_msg();"
Teach %N to add -> symlink. Judicious use of putchar() instead of xputc to
let FILE * do its job collating output.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sun, 02 Jun 2013 00:24:24 -0500 |
parents | 91d15ead5602 |
children | b2697351ce6d |
comparison
equal
deleted
inserted
replaced
915:463a7b796e61 | 916:b92cb3cc9696 |
---|---|
42 struct stat st; | 42 struct stat st; |
43 struct statfs sf; | 43 struct statfs sf; |
44 } stat; | 44 } stat; |
45 struct passwd *user_name; | 45 struct passwd *user_name; |
46 struct group *group_name; | 46 struct group *group_name; |
47 char *ftname, access_str[11]; | 47 char *ftname; |
48 ) | 48 ) |
49 | 49 |
50 | 50 |
51 // Note: the atime, mtime, and ctime fields in struct stat are the start | 51 // Note: the atime, mtime, and ctime fields in struct stat are the start |
52 // of embedded struct timespec, but posix won't let them use that | 52 // of embedded struct timespec, but posix won't let them use that |
57 strftime(toybuf, sizeof(toybuf), "%Y-%m-%d %H:%M:%S", | 57 strftime(toybuf, sizeof(toybuf), "%Y-%m-%d %H:%M:%S", |
58 localtime(&(ts->tv_sec))); | 58 localtime(&(ts->tv_sec))); |
59 xprintf("%s.%09d", toybuf, ts->tv_nsec); | 59 xprintf("%s.%09d", toybuf, ts->tv_nsec); |
60 } | 60 } |
61 | 61 |
62 static int print_stat(char type) | 62 static void print_stat(char type) |
63 { | 63 { |
64 struct stat *stat = (struct stat *)&TT.stat; | 64 struct stat *stat = (struct stat *)&TT.stat; |
65 | 65 |
66 switch (type) { | 66 if (type == 'a') xprintf("%04lo", stat->st_mode & ~S_IFMT); |
67 case 'a': | 67 else if (type == 'A') { |
68 xprintf("%04lo", stat->st_mode & ~S_IFMT); | 68 char str[11]; |
69 break; | |
70 case 'A': | |
71 xprintf("%s", TT.access_str); | |
72 break; | |
73 | 69 |
74 case 'b': | 70 mode_to_string(stat->st_mode, str); |
75 xprintf("%llu", stat->st_blocks); | 71 xprintf("%s", str); |
76 break; | 72 } else if (type == 'b') xprintf("%llu", stat->st_blocks); |
77 | 73 else if (type == 'B') xprintf("%lu", stat->st_blksize); |
78 case 'B': | 74 else if (type == 'd') xprintf("%ldd", stat->st_dev); |
79 xprintf("%lu", stat->st_blksize); | 75 else if (type == 'D') xprintf("%llxh", stat->st_dev); |
80 break; | 76 else if (type == 'f') xprintf("%lx", stat->st_mode); |
81 case 'd': | 77 else if (type == 'F') xprintf("%s", TT.ftname); |
82 xprintf("%ldd", stat->st_dev); | 78 else if (type == 'g') xprintf("%lu", stat->st_gid); |
83 break; | 79 else if (type == 'G') xprintf("%8s", TT.user_name->pw_name); |
84 case 'D': | 80 else if (type == 'h') xprintf("%lu", stat->st_nlink); |
85 xprintf("%llxh", stat->st_dev); | 81 else if (type == 'i') xprintf("%llu", stat->st_ino); |
86 break; | 82 else if (type == 'N') { |
87 case 'f': | 83 xprintf("`%s'", *toys.optargs); |
88 xprintf("%lx", stat->st_mode); | 84 if (S_ISLNK(stat->st_mode)) |
89 break; | 85 if (0<readlink(*toys.optargs, toybuf, sizeof(toybuf))) |
90 case 'F': | 86 xprintf(" -> `%s'", toybuf); |
91 xprintf("%s", TT.ftname); | 87 } else if (type == 'o') xprintf("%lu", stat->st_blksize); |
92 break; | 88 else if (type == 's') xprintf("%llu", stat->st_size); |
93 case 'g': | 89 else if (type == 'u') xprintf("%lu", stat->st_uid); |
94 xprintf("%lu", stat->st_gid); | 90 else if (type == 'U') xprintf("%8s", TT.user_name->pw_name); |
95 break; | 91 else if (type == 'x') date_stat_format((void *)&stat->st_atime); |
96 case 'G': | 92 else if (type == 'X') xprintf("%llu", (long long)stat->st_atime); |
97 xprintf("%8s", TT.user_name->pw_name); | 93 else if (type == 'y') date_stat_format((void *)&stat->st_mtime); |
98 break; | 94 else if (type == 'Y') xprintf("%llu", (long long)stat->st_mtime); |
99 case 'h': | 95 else if (type == 'z') date_stat_format((void *)&stat->st_ctime); |
100 xprintf("%lu", stat->st_nlink); | 96 else if (type == 'Z') xprintf("%llu", (long long)stat->st_ctime); |
101 break; | 97 else xprintf("?"); |
102 case 'i': | |
103 xprintf("%llu", stat->st_ino); | |
104 break; | |
105 case 'N': | |
106 xprintf("`%s'", *toys.optargs); | |
107 break; | |
108 case 'o': | |
109 xprintf("%lu", stat->st_blksize); | |
110 break; | |
111 case 's': | |
112 xprintf("%llu", stat->st_size); | |
113 break; | |
114 case 'u': | |
115 xprintf("%lu", stat->st_uid); | |
116 break; | |
117 case 'U': | |
118 xprintf("%8s", TT.user_name->pw_name); | |
119 break; | |
120 | |
121 case 'x': | |
122 date_stat_format((void *)&stat->st_atime); | |
123 break; | |
124 case 'X': | |
125 xprintf("%llu", (long long)stat->st_atime); | |
126 break; | |
127 case 'y': | |
128 date_stat_format((void *)&stat->st_mtime); | |
129 break; | |
130 case 'Y': | |
131 xprintf("%llu", (long long)stat->st_mtime); | |
132 break; | |
133 case 'z': | |
134 date_stat_format((void *)&stat->st_ctime); | |
135 break; | |
136 case 'Z': | |
137 xprintf("%llu", (long long)stat->st_ctime); | |
138 break; | |
139 | |
140 default: | |
141 return 1; | |
142 } | |
143 return 0; | |
144 } | 98 } |
145 | 99 |
146 static int print_statfs(char type) { | 100 static void print_statfs(char type) { |
147 struct statfs *statfs = (struct statfs *)&TT.stat; | 101 struct statfs *statfs = (struct statfs *)&TT.stat; |
148 | 102 |
149 switch (type) { | 103 if (type == 'a') xprintf("%lu", statfs->f_bavail); |
150 case 'a': | 104 else if (type == 'b') xprintf("%lu", statfs->f_blocks); |
151 xprintf("%lu", statfs->f_bavail); | 105 else if (type == 'c') xprintf("%lu", statfs->f_files); |
152 break; | 106 else if (type == 'd') xprintf("%lu", statfs->f_ffree); |
153 case 'b': | 107 else if (type == 'f') xprintf("%lu", statfs->f_bfree); |
154 xprintf("%lu", statfs->f_blocks); | 108 else if (type == 'l') xprintf("%ld", statfs->f_namelen); |
155 break; | 109 else if (type == 't') xprintf("%lx", statfs->f_type); |
156 case 'c': | 110 else if (type == 'i') |
157 xprintf("%lu", statfs->f_files); | 111 xprintf("%x%x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]); |
158 break; | 112 else if (type == 's') xprintf("%d", statfs->f_frsize); |
159 case 'd': | 113 else if (type == 'S') xprintf("%d", statfs->f_bsize); |
160 xprintf("%lu", statfs->f_ffree); | 114 else xprintf("?"); |
161 break; | |
162 case 'f': | |
163 xprintf("%lu", statfs->f_bfree); | |
164 break; | |
165 case 'i': | |
166 xprintf("%x%x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]); | |
167 break; | |
168 case 'l': | |
169 xprintf("%ld", statfs->f_namelen); | |
170 break; | |
171 case 's': | |
172 xprintf("%d", statfs->f_frsize); | |
173 break; | |
174 case 'S': | |
175 xprintf("%d", statfs->f_bsize); | |
176 break; | |
177 case 't': | |
178 xprintf("%lx", statfs->f_type); | |
179 break; | |
180 default: | |
181 return 1; | |
182 } | |
183 return 0; | |
184 } | |
185 | |
186 static int do_stat(char *path) | |
187 { | |
188 struct stat *statf = (struct stat*)&TT.stat; | |
189 char *types = "character device\0directory\0block device\0" \ | |
190 "regular file\0symbolic link\0socket\0FIFO (named pipe)"; | |
191 int i, filetype; | |
192 | |
193 if (stat(path, statf) < 0) return 1; | |
194 | |
195 filetype = statf->st_mode & S_IFMT; | |
196 TT.ftname = types; | |
197 for (i = 1; filetype != (i*8192) && i < 7; i++) | |
198 TT.ftname += strlen(TT.ftname)+1; | |
199 if (!statf->st_size && filetype == S_IFREG) | |
200 TT.ftname = "regular empty file"; | |
201 | |
202 // check user and group name | |
203 TT.user_name = getpwuid(statf->st_uid); | |
204 TT.group_name = getgrgid(statf->st_gid); | |
205 // function to get access in human readable format | |
206 format_mode(&TT.access_str, statf->st_mode); | |
207 | |
208 return 0; | |
209 } | |
210 | |
211 static int do_statfs(char *path) | |
212 { | |
213 return statfs(path, (void *)&TT.stat) < 0; | |
214 } | 115 } |
215 | 116 |
216 void stat_main(void) | 117 void stat_main(void) |
217 { | 118 { |
218 struct { | 119 int flagf = toys.optflags & FLAG_f; |
219 char *fmt; | 120 char *format = flagf |
220 int (*do_it)(char*); | 121 ? " File: \"%n\"\n ID: %i Namelen: %l Type: %t\n" |
221 int (*print_it)(char); | 122 "Block Size: %s Fundamental block size: %S\n" |
222 } d, ds[2] = { | 123 "Blocks: Total: %b\tFree: %f\tAvailable: %a\n" |
223 {" File: %N\n" | 124 "Inodes: Total: %c\tFree: %d" |
224 " Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n" | 125 : " File: %N\n Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n" |
225 "Device: %D\t Inode: %i\t Links: %h\n" | 126 "Device: %D\t Inode: %i\t Links: %h\n" |
226 "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n" | 127 "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n" |
227 "Access: %x\nModify: %y\nChange: %z", | 128 "Access: %x\nModify: %y\nChange: %z"; |
228 do_stat, print_stat}, | |
229 {" File: \"%n\"\n" | |
230 " ID: %i Namelen: %l Type: %t\n" | |
231 "Block Size: %s Fundamental block size: %S\n" | |
232 "Blocks: Total: %b\tFree: %f\tAvailable: %a\n" | |
233 "Inodes: Total: %c\tFree: %d", | |
234 do_statfs, print_statfs} | |
235 }; | |
236 | 129 |
237 d = ds[toys.optflags & FLAG_f]; | 130 if (toys.optflags & FLAG_c) format = TT.fmt; |
238 if (toys.optflags & FLAG_c) d.fmt = TT.fmt; | |
239 | 131 |
240 for (; *toys.optargs; toys.optargs++) { | 132 for (; *toys.optargs; toys.optargs++) { |
241 char *format = d.fmt; | 133 char *f; |
242 if (d.do_it(*toys.optargs)) { | 134 |
135 if (flagf && !statfs(*toys.optargs, (void *)&TT.stat)); | |
136 else if (!flagf && !lstat(*toys.optargs, (void *)&TT.stat)) { | |
137 struct stat *stat = (struct stat*)&TT.stat; | |
138 char *types = "character device\0directory\0block device\0" \ | |
139 "regular file\0symbolic link\0socket\0FIFO (named pipe)"; | |
140 int i, filetype; | |
141 | |
142 filetype = stat->st_mode & S_IFMT; | |
143 TT.ftname = types; | |
144 for (i = 1; filetype != (i*8192) && i < 7; i++) | |
145 TT.ftname += strlen(TT.ftname)+1; | |
146 if (!stat->st_size && filetype == S_IFREG) | |
147 TT.ftname = "regular empty file"; | |
148 | |
149 // check user and group name | |
150 TT.user_name = getpwuid(stat->st_uid); | |
151 TT.group_name = getgrgid(stat->st_gid); | |
152 } else { | |
243 perror_msg("'%s'", *toys.optargs); | 153 perror_msg("'%s'", *toys.optargs); |
244 continue; | 154 continue; |
245 } | 155 } |
246 for (; *format; format++) { | 156 |
247 if (*format != '%') { | 157 for (f = format; *f; f++) { |
248 xputc(*format); | 158 if (*f != '%') putchar(*f); |
249 continue; | 159 else { |
160 if (*++f == 'n') xprintf("%s", *toys.optargs); | |
161 else if (flagf) print_statfs(*f); | |
162 else print_stat(*f); | |
250 } | 163 } |
251 format++; | |
252 if (*format == 'n') xprintf("%s", *toys.optargs); | |
253 else if (d.print_it(*format)) xputc(*format); | |
254 } | 164 } |
255 xputc('\n'); | 165 xputc('\n'); |
256 } | 166 } |
257 } | 167 } |