diff options
author | Elliott Hughes | 2015-05-15 18:54:35 -0500 |
---|---|---|
committer | Elliott Hughes | 2015-05-15 18:54:35 -0500 |
commit | 9c94aa9982c562585c08c5f95569695ccc64f846 (patch) | |
tree | fd7e61c59ccedda1923ed0c795b18bc495b92020 /toolbox | |
parent | 4e0008123d0828e8b8ab31c81ebdbc5dc3656e88 (diff) | |
download | platform-system-core-9c94aa9982c562585c08c5f95569695ccc64f846.tar.gz platform-system-core-9c94aa9982c562585c08c5f95569695ccc64f846.tar.xz platform-system-core-9c94aa9982c562585c08c5f95569695ccc64f846.zip |
Switch to toybox ls.
Bug: http://b/21171466
Change-Id: I3fa09db7ca43d337cbda60f10269e7607544982b
Diffstat (limited to 'toolbox')
-rw-r--r-- | toolbox/Android.mk | 1 | ||||
-rw-r--r-- | toolbox/ls.c | 588 |
2 files changed, 0 insertions, 589 deletions
diff --git a/toolbox/Android.mk b/toolbox/Android.mk index ad99a3997..5a58d191b 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk | |||
@@ -45,7 +45,6 @@ OUR_TOOLS := \ | |||
45 | ioctl \ | 45 | ioctl \ |
46 | ionice \ | 46 | ionice \ |
47 | log \ | 47 | log \ |
48 | ls \ | ||
49 | lsof \ | 48 | lsof \ |
50 | mount \ | 49 | mount \ |
51 | nandread \ | 50 | nandread \ |
diff --git a/toolbox/ls.c b/toolbox/ls.c deleted file mode 100644 index 9a89dd462..000000000 --- a/toolbox/ls.c +++ /dev/null | |||
@@ -1,588 +0,0 @@ | |||
1 | #include <dirent.h> | ||
2 | #include <errno.h> | ||
3 | #include <grp.h> | ||
4 | #include <limits.h> | ||
5 | #include <pwd.h> | ||
6 | #include <stddef.h> | ||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <string.h> | ||
10 | #include <sys/stat.h> | ||
11 | #include <sys/sysmacros.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <time.h> | ||
14 | #include <unistd.h> | ||
15 | |||
16 | #include <selinux/selinux.h> | ||
17 | |||
18 | // simple dynamic array of strings. | ||
19 | typedef struct { | ||
20 | int count; | ||
21 | int capacity; | ||
22 | void** items; | ||
23 | } strlist_t; | ||
24 | |||
25 | #define STRLIST_INITIALIZER { 0, 0, NULL } | ||
26 | |||
27 | /* Used to iterate over a strlist_t | ||
28 | * _list :: pointer to strlist_t object | ||
29 | * _item :: name of local variable name defined within the loop with | ||
30 | * type 'char*' | ||
31 | * _stmnt :: C statement executed in each iteration | ||
32 | * | ||
33 | * This macro is only intended for simple uses. Do not add or remove items | ||
34 | * to/from the list during iteration. | ||
35 | */ | ||
36 | #define STRLIST_FOREACH(_list,_item,_stmnt) \ | ||
37 | do { \ | ||
38 | int _nn_##__LINE__ = 0; \ | ||
39 | for (;_nn_##__LINE__ < (_list)->count; ++ _nn_##__LINE__) { \ | ||
40 | char* _item = (char*)(_list)->items[_nn_##__LINE__]; \ | ||
41 | _stmnt; \ | ||
42 | } \ | ||
43 | } while (0) | ||
44 | |||
45 | static void dynarray_reserve_more( strlist_t *a, int count ) { | ||
46 | int old_cap = a->capacity; | ||
47 | int new_cap = old_cap; | ||
48 | const int max_cap = INT_MAX/sizeof(void*); | ||
49 | void** new_items; | ||
50 | int new_count = a->count + count; | ||
51 | |||
52 | if (count <= 0) | ||
53 | return; | ||
54 | |||
55 | if (count > max_cap - a->count) | ||
56 | abort(); | ||
57 | |||
58 | new_count = a->count + count; | ||
59 | |||
60 | while (new_cap < new_count) { | ||
61 | old_cap = new_cap; | ||
62 | new_cap += (new_cap >> 2) + 4; | ||
63 | if (new_cap < old_cap || new_cap > max_cap) { | ||
64 | new_cap = max_cap; | ||
65 | } | ||
66 | } | ||
67 | new_items = realloc(a->items, new_cap*sizeof(void*)); | ||
68 | if (new_items == NULL) | ||
69 | abort(); | ||
70 | |||
71 | a->items = new_items; | ||
72 | a->capacity = new_cap; | ||
73 | } | ||
74 | |||
75 | void strlist_init( strlist_t *list ) { | ||
76 | list->count = list->capacity = 0; | ||
77 | list->items = NULL; | ||
78 | } | ||
79 | |||
80 | // append a new string made of the first 'slen' characters from 'str' | ||
81 | // followed by a trailing zero. | ||
82 | void strlist_append_b( strlist_t *list, const void* str, size_t slen ) { | ||
83 | char *copy = malloc(slen+1); | ||
84 | memcpy(copy, str, slen); | ||
85 | copy[slen] = '\0'; | ||
86 | if (list->count >= list->capacity) | ||
87 | dynarray_reserve_more(list, 1); | ||
88 | list->items[list->count++] = copy; | ||
89 | } | ||
90 | |||
91 | // append the copy of a given input string to a strlist_t. | ||
92 | void strlist_append_dup( strlist_t *list, const char *str) { | ||
93 | strlist_append_b(list, str, strlen(str)); | ||
94 | } | ||
95 | |||
96 | // note: strlist_done will free all the strings owned by the list. | ||
97 | void strlist_done( strlist_t *list ) { | ||
98 | STRLIST_FOREACH(list, string, free(string)); | ||
99 | free(list->items); | ||
100 | list->items = NULL; | ||
101 | list->count = list->capacity = 0; | ||
102 | } | ||
103 | |||
104 | static int strlist_compare_strings(const void* a, const void* b) { | ||
105 | const char *sa = *(const char **)a; | ||
106 | const char *sb = *(const char **)b; | ||
107 | return strcmp(sa, sb); | ||
108 | } | ||
109 | |||
110 | /* sort the strings in a given list (using strcmp) */ | ||
111 | void strlist_sort( strlist_t *list ) { | ||
112 | if (list->count > 0) { | ||
113 | qsort(list->items, (size_t)list->count, sizeof(void*), strlist_compare_strings); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | |||
118 | // bits for flags argument | ||
119 | #define LIST_LONG (1 << 0) | ||
120 | #define LIST_ALL (1 << 1) | ||
121 | #define LIST_RECURSIVE (1 << 2) | ||
122 | #define LIST_DIRECTORIES (1 << 3) | ||
123 | #define LIST_SIZE (1 << 4) | ||
124 | #define LIST_LONG_NUMERIC (1 << 5) | ||
125 | #define LIST_CLASSIFY (1 << 6) | ||
126 | #define LIST_MACLABEL (1 << 7) | ||
127 | #define LIST_INODE (1 << 8) | ||
128 | |||
129 | // fwd | ||
130 | static int listpath(const char *name, int flags); | ||
131 | |||
132 | static char mode2kind(mode_t mode) | ||
133 | { | ||
134 | switch(mode & S_IFMT){ | ||
135 | case S_IFSOCK: return 's'; | ||
136 | case S_IFLNK: return 'l'; | ||
137 | case S_IFREG: return '-'; | ||
138 | case S_IFDIR: return 'd'; | ||
139 | case S_IFBLK: return 'b'; | ||
140 | case S_IFCHR: return 'c'; | ||
141 | case S_IFIFO: return 'p'; | ||
142 | default: return '?'; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | void strmode(mode_t mode, char *out) | ||
147 | { | ||
148 | *out++ = mode2kind(mode); | ||
149 | |||
150 | *out++ = (mode & 0400) ? 'r' : '-'; | ||
151 | *out++ = (mode & 0200) ? 'w' : '-'; | ||
152 | if(mode & 04000) { | ||
153 | *out++ = (mode & 0100) ? 's' : 'S'; | ||
154 | } else { | ||
155 | *out++ = (mode & 0100) ? 'x' : '-'; | ||
156 | } | ||
157 | *out++ = (mode & 040) ? 'r' : '-'; | ||
158 | *out++ = (mode & 020) ? 'w' : '-'; | ||
159 | if(mode & 02000) { | ||
160 | *out++ = (mode & 010) ? 's' : 'S'; | ||
161 | } else { | ||
162 | *out++ = (mode & 010) ? 'x' : '-'; | ||
163 | } | ||
164 | *out++ = (mode & 04) ? 'r' : '-'; | ||
165 | *out++ = (mode & 02) ? 'w' : '-'; | ||
166 | if(mode & 01000) { | ||
167 | *out++ = (mode & 01) ? 't' : 'T'; | ||
168 | } else { | ||
169 | *out++ = (mode & 01) ? 'x' : '-'; | ||
170 | } | ||
171 | *out = 0; | ||
172 | } | ||
173 | |||
174 | static void user2str(uid_t uid, char *out, size_t out_size) | ||
175 | { | ||
176 | struct passwd *pw = getpwuid(uid); | ||
177 | if(pw) { | ||
178 | strlcpy(out, pw->pw_name, out_size); | ||
179 | } else { | ||
180 | snprintf(out, out_size, "%d", uid); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static void group2str(gid_t gid, char *out, size_t out_size) | ||
185 | { | ||
186 | struct group *gr = getgrgid(gid); | ||
187 | if(gr) { | ||
188 | strlcpy(out, gr->gr_name, out_size); | ||
189 | } else { | ||
190 | snprintf(out, out_size, "%d", gid); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static int show_total_size(const char *dirname, DIR *d, int flags) | ||
195 | { | ||
196 | struct dirent *de; | ||
197 | char tmp[1024]; | ||
198 | struct stat s; | ||
199 | int sum = 0; | ||
200 | |||
201 | /* run through the directory and sum up the file block sizes */ | ||
202 | while ((de = readdir(d)) != 0) { | ||
203 | if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) | ||
204 | continue; | ||
205 | if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) | ||
206 | continue; | ||
207 | |||
208 | if (strcmp(dirname, "/") == 0) | ||
209 | snprintf(tmp, sizeof(tmp), "/%s", de->d_name); | ||
210 | else | ||
211 | snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name); | ||
212 | |||
213 | if (lstat(tmp, &s) < 0) { | ||
214 | fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno)); | ||
215 | rewinddir(d); | ||
216 | return -1; | ||
217 | } | ||
218 | |||
219 | sum += s.st_blocks / 2; | ||
220 | } | ||
221 | |||
222 | printf("total %d\n", sum); | ||
223 | rewinddir(d); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int listfile_size(const char *path, const char *filename, struct stat *s, | ||
228 | int flags) | ||
229 | { | ||
230 | if(!s || !path) { | ||
231 | return -1; | ||
232 | } | ||
233 | |||
234 | /* blocks are 512 bytes, we want output to be KB */ | ||
235 | if ((flags & LIST_SIZE) != 0) { | ||
236 | printf("%lld ", (long long)s->st_blocks / 2); | ||
237 | } | ||
238 | |||
239 | if ((flags & LIST_CLASSIFY) != 0) { | ||
240 | char filetype = mode2kind(s->st_mode); | ||
241 | if (filetype != 'l') { | ||
242 | printf("%c ", filetype); | ||
243 | } else { | ||
244 | struct stat link_dest; | ||
245 | if (!stat(path, &link_dest)) { | ||
246 | printf("l%c ", mode2kind(link_dest.st_mode)); | ||
247 | } else { | ||
248 | fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno)); | ||
249 | printf("l? "); | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | printf("%s\n", filename); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int listfile_long(const char *path, struct stat *s, int flags) | ||
260 | { | ||
261 | char date[32]; | ||
262 | char mode[16]; | ||
263 | char user[32]; | ||
264 | char group[32]; | ||
265 | const char *name; | ||
266 | |||
267 | if(!s || !path) { | ||
268 | return -1; | ||
269 | } | ||
270 | |||
271 | /* name is anything after the final '/', or the whole path if none*/ | ||
272 | name = strrchr(path, '/'); | ||
273 | if(name == 0) { | ||
274 | name = path; | ||
275 | } else { | ||
276 | name++; | ||
277 | } | ||
278 | |||
279 | strmode(s->st_mode, mode); | ||
280 | if (flags & LIST_LONG_NUMERIC) { | ||
281 | snprintf(user, sizeof(user), "%u", s->st_uid); | ||
282 | snprintf(group, sizeof(group), "%u", s->st_gid); | ||
283 | } else { | ||
284 | user2str(s->st_uid, user, sizeof(user)); | ||
285 | group2str(s->st_gid, group, sizeof(group)); | ||
286 | } | ||
287 | |||
288 | strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime)); | ||
289 | date[31] = 0; | ||
290 | |||
291 | // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 | ||
292 | // MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK) | ||
293 | |||
294 | switch(s->st_mode & S_IFMT) { | ||
295 | case S_IFBLK: | ||
296 | case S_IFCHR: | ||
297 | printf("%s %-8s %-8s %3d, %3d %s %s\n", | ||
298 | mode, user, group, | ||
299 | major(s->st_rdev), minor(s->st_rdev), | ||
300 | date, name); | ||
301 | break; | ||
302 | case S_IFREG: | ||
303 | printf("%s %-8s %-8s %8lld %s %s\n", | ||
304 | mode, user, group, (long long)s->st_size, date, name); | ||
305 | break; | ||
306 | case S_IFLNK: { | ||
307 | char linkto[256]; | ||
308 | ssize_t len; | ||
309 | |||
310 | len = readlink(path, linkto, 256); | ||
311 | if(len < 0) return -1; | ||
312 | |||
313 | if(len > 255) { | ||
314 | linkto[252] = '.'; | ||
315 | linkto[253] = '.'; | ||
316 | linkto[254] = '.'; | ||
317 | linkto[255] = 0; | ||
318 | } else { | ||
319 | linkto[len] = 0; | ||
320 | } | ||
321 | |||
322 | printf("%s %-8s %-8s %s %s -> %s\n", | ||
323 | mode, user, group, date, name, linkto); | ||
324 | break; | ||
325 | } | ||
326 | default: | ||
327 | printf("%s %-8s %-8s %s %s\n", | ||
328 | mode, user, group, date, name); | ||
329 | |||
330 | } | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int listfile_maclabel(const char *path, struct stat *s) | ||
335 | { | ||
336 | char mode[16]; | ||
337 | char user[32]; | ||
338 | char group[32]; | ||
339 | char *maclabel = NULL; | ||
340 | const char *name; | ||
341 | |||
342 | if(!s || !path) { | ||
343 | return -1; | ||
344 | } | ||
345 | |||
346 | /* name is anything after the final '/', or the whole path if none*/ | ||
347 | name = strrchr(path, '/'); | ||
348 | if(name == 0) { | ||
349 | name = path; | ||
350 | } else { | ||
351 | name++; | ||
352 | } | ||
353 | |||
354 | lgetfilecon(path, &maclabel); | ||
355 | if (!maclabel) { | ||
356 | return -1; | ||
357 | } | ||
358 | |||
359 | strmode(s->st_mode, mode); | ||
360 | user2str(s->st_uid, user, sizeof(user)); | ||
361 | group2str(s->st_gid, group, sizeof(group)); | ||
362 | |||
363 | switch(s->st_mode & S_IFMT) { | ||
364 | case S_IFLNK: { | ||
365 | char linkto[256]; | ||
366 | ssize_t len; | ||
367 | |||
368 | len = readlink(path, linkto, sizeof(linkto)); | ||
369 | if(len < 0) return -1; | ||
370 | |||
371 | if((size_t)len > sizeof(linkto)-1) { | ||
372 | linkto[sizeof(linkto)-4] = '.'; | ||
373 | linkto[sizeof(linkto)-3] = '.'; | ||
374 | linkto[sizeof(linkto)-2] = '.'; | ||
375 | linkto[sizeof(linkto)-1] = 0; | ||
376 | } else { | ||
377 | linkto[len] = 0; | ||
378 | } | ||
379 | |||
380 | printf("%s %-8s %-8s %s %s -> %s\n", | ||
381 | mode, user, group, maclabel, name, linkto); | ||
382 | break; | ||
383 | } | ||
384 | default: | ||
385 | printf("%s %-8s %-8s %s %s\n", | ||
386 | mode, user, group, maclabel, name); | ||
387 | |||
388 | } | ||
389 | |||
390 | free(maclabel); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static int listfile(const char *dirname, const char *filename, int flags) | ||
396 | { | ||
397 | struct stat s; | ||
398 | |||
399 | if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL | LIST_INODE)) == 0) { | ||
400 | printf("%s\n", filename); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | char tmp[4096]; | ||
405 | const char* pathname = filename; | ||
406 | |||
407 | if (dirname != NULL) { | ||
408 | snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename); | ||
409 | pathname = tmp; | ||
410 | } else { | ||
411 | pathname = filename; | ||
412 | } | ||
413 | |||
414 | if(lstat(pathname, &s) < 0) { | ||
415 | fprintf(stderr, "lstat '%s' failed: %s\n", pathname, strerror(errno)); | ||
416 | return -1; | ||
417 | } | ||
418 | |||
419 | if(flags & LIST_INODE) { | ||
420 | printf("%8llu ", (unsigned long long)s.st_ino); | ||
421 | } | ||
422 | |||
423 | if ((flags & LIST_MACLABEL) != 0) { | ||
424 | return listfile_maclabel(pathname, &s); | ||
425 | } else if ((flags & LIST_LONG) != 0) { | ||
426 | return listfile_long(pathname, &s, flags); | ||
427 | } else /*((flags & LIST_SIZE) != 0)*/ { | ||
428 | return listfile_size(pathname, filename, &s, flags); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static int listdir(const char *name, int flags) | ||
433 | { | ||
434 | char tmp[4096]; | ||
435 | DIR *d; | ||
436 | struct dirent *de; | ||
437 | strlist_t files = STRLIST_INITIALIZER; | ||
438 | |||
439 | d = opendir(name); | ||
440 | if(d == 0) { | ||
441 | fprintf(stderr, "opendir failed, %s\n", strerror(errno)); | ||
442 | return -1; | ||
443 | } | ||
444 | |||
445 | if ((flags & LIST_SIZE) != 0) { | ||
446 | show_total_size(name, d, flags); | ||
447 | } | ||
448 | |||
449 | while((de = readdir(d)) != 0){ | ||
450 | if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; | ||
451 | if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue; | ||
452 | |||
453 | strlist_append_dup(&files, de->d_name); | ||
454 | } | ||
455 | |||
456 | strlist_sort(&files); | ||
457 | STRLIST_FOREACH(&files, filename, listfile(name, filename, flags)); | ||
458 | strlist_done(&files); | ||
459 | |||
460 | if (flags & LIST_RECURSIVE) { | ||
461 | strlist_t subdirs = STRLIST_INITIALIZER; | ||
462 | |||
463 | rewinddir(d); | ||
464 | |||
465 | while ((de = readdir(d)) != 0) { | ||
466 | struct stat s; | ||
467 | int err; | ||
468 | |||
469 | if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) | ||
470 | continue; | ||
471 | if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) | ||
472 | continue; | ||
473 | |||
474 | if (!strcmp(name, "/")) | ||
475 | snprintf(tmp, sizeof(tmp), "/%s", de->d_name); | ||
476 | else | ||
477 | snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name); | ||
478 | |||
479 | /* | ||
480 | * If the name ends in a '/', use stat() so we treat it like a | ||
481 | * directory even if it's a symlink. | ||
482 | */ | ||
483 | if (tmp[strlen(tmp)-1] == '/') | ||
484 | err = stat(tmp, &s); | ||
485 | else | ||
486 | err = lstat(tmp, &s); | ||
487 | |||
488 | if (err < 0) { | ||
489 | perror(tmp); | ||
490 | closedir(d); | ||
491 | return -1; | ||
492 | } | ||
493 | |||
494 | if (S_ISDIR(s.st_mode)) { | ||
495 | strlist_append_dup(&subdirs, tmp); | ||
496 | } | ||
497 | } | ||
498 | strlist_sort(&subdirs); | ||
499 | STRLIST_FOREACH(&subdirs, path, { | ||
500 | printf("\n%s:\n", path); | ||
501 | listdir(path, flags); | ||
502 | }); | ||
503 | strlist_done(&subdirs); | ||
504 | } | ||
505 | |||
506 | closedir(d); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static int listpath(const char *name, int flags) | ||
511 | { | ||
512 | struct stat s; | ||
513 | int err; | ||
514 | |||
515 | /* | ||
516 | * If the name ends in a '/', use stat() so we treat it like a | ||
517 | * directory even if it's a symlink. | ||
518 | */ | ||
519 | if (name[strlen(name)-1] == '/') | ||
520 | err = stat(name, &s); | ||
521 | else | ||
522 | err = lstat(name, &s); | ||
523 | |||
524 | if (err < 0) { | ||
525 | perror(name); | ||
526 | return -1; | ||
527 | } | ||
528 | |||
529 | if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) { | ||
530 | if (flags & LIST_RECURSIVE) | ||
531 | printf("\n%s:\n", name); | ||
532 | return listdir(name, flags); | ||
533 | } else { | ||
534 | /* yeah this calls stat() again*/ | ||
535 | return listfile(NULL, name, flags); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | int ls_main(int argc, char **argv) | ||
540 | { | ||
541 | int flags = 0; | ||
542 | |||
543 | if(argc > 1) { | ||
544 | int i; | ||
545 | int err = 0; | ||
546 | strlist_t files = STRLIST_INITIALIZER; | ||
547 | |||
548 | for (i = 1; i < argc; i++) { | ||
549 | if (argv[i][0] == '-') { | ||
550 | /* an option ? */ | ||
551 | const char *arg = argv[i]+1; | ||
552 | while (arg[0]) { | ||
553 | switch (arg[0]) { | ||
554 | case 'l': flags |= LIST_LONG; break; | ||
555 | case 'n': flags |= LIST_LONG | LIST_LONG_NUMERIC; break; | ||
556 | case 's': flags |= LIST_SIZE; break; | ||
557 | case 'R': flags |= LIST_RECURSIVE; break; | ||
558 | case 'd': flags |= LIST_DIRECTORIES; break; | ||
559 | case 'Z': flags |= LIST_MACLABEL; break; | ||
560 | case 'a': flags |= LIST_ALL; break; | ||
561 | case 'F': flags |= LIST_CLASSIFY; break; | ||
562 | case 'i': flags |= LIST_INODE; break; | ||
563 | default: | ||
564 | fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]); | ||
565 | exit(1); | ||
566 | } | ||
567 | arg++; | ||
568 | } | ||
569 | } else { | ||
570 | /* not an option ? */ | ||
571 | strlist_append_dup(&files, argv[i]); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | if (files.count > 0) { | ||
576 | STRLIST_FOREACH(&files, path, { | ||
577 | if (listpath(path, flags) != 0) { | ||
578 | err = EXIT_FAILURE; | ||
579 | } | ||
580 | }); | ||
581 | strlist_done(&files); | ||
582 | return err; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | // list working directory if no files or directories were specified | ||
587 | return listpath(".", flags); | ||
588 | } | ||