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 }