~xnox/ubuntu/trusty/gcc-arm-linux-androideabi/dima

« back to all changes in this revision

Viewing changes to android/system/core/toolbox/ls.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2013-07-05 10:12:24 UTC
  • Revision ID: package-import@ubuntu.com-20130705101224-6qo3e8jbz8p31aa1
Tags: upstream-0.20130705.1
ImportĀ upstreamĀ versionĀ 0.20130705.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <stdlib.h>
 
3
#include <string.h>
 
4
#include <sys/types.h>
 
5
#include <dirent.h>
 
6
#include <errno.h>
 
7
 
 
8
#ifdef HAVE_SELINUX
 
9
#include <selinux/selinux.h>
 
10
#endif
 
11
 
 
12
#include <sys/stat.h>
 
13
#include <unistd.h>
 
14
#include <time.h>
 
15
 
 
16
#include <pwd.h>
 
17
#include <grp.h>
 
18
 
 
19
#include <linux/kdev_t.h>
 
20
#include <limits.h>
 
21
 
 
22
#include "dynarray.h"
 
23
 
 
24
// bits for flags argument
 
25
#define LIST_LONG           (1 << 0)
 
26
#define LIST_ALL            (1 << 1)
 
27
#define LIST_RECURSIVE      (1 << 2)
 
28
#define LIST_DIRECTORIES    (1 << 3)
 
29
#define LIST_SIZE           (1 << 4)
 
30
#define LIST_LONG_NUMERIC   (1 << 5)
 
31
#define LIST_CLASSIFY       (1 << 6)
 
32
#define LIST_MACLABEL       (1 << 7)
 
33
 
 
34
// fwd
 
35
static int listpath(const char *name, int flags);
 
36
 
 
37
static char mode2kind(unsigned mode)
 
38
{
 
39
    switch(mode & S_IFMT){
 
40
    case S_IFSOCK: return 's';
 
41
    case S_IFLNK: return 'l';
 
42
    case S_IFREG: return '-';
 
43
    case S_IFDIR: return 'd';
 
44
    case S_IFBLK: return 'b';
 
45
    case S_IFCHR: return 'c';
 
46
    case S_IFIFO: return 'p';
 
47
    default: return '?';
 
48
    }
 
49
}
 
50
 
 
51
static void mode2str(unsigned mode, char *out)
 
52
{
 
53
    *out++ = mode2kind(mode);
 
54
 
 
55
    *out++ = (mode & 0400) ? 'r' : '-';
 
56
    *out++ = (mode & 0200) ? 'w' : '-';
 
57
    if(mode & 04000) {
 
58
        *out++ = (mode & 0100) ? 's' : 'S';
 
59
    } else {
 
60
        *out++ = (mode & 0100) ? 'x' : '-';
 
61
    }
 
62
    *out++ = (mode & 040) ? 'r' : '-';
 
63
    *out++ = (mode & 020) ? 'w' : '-';
 
64
    if(mode & 02000) {
 
65
        *out++ = (mode & 010) ? 's' : 'S';
 
66
    } else {
 
67
        *out++ = (mode & 010) ? 'x' : '-';
 
68
    }
 
69
    *out++ = (mode & 04) ? 'r' : '-';
 
70
    *out++ = (mode & 02) ? 'w' : '-';
 
71
    if(mode & 01000) {
 
72
        *out++ = (mode & 01) ? 't' : 'T';
 
73
    } else {
 
74
        *out++ = (mode & 01) ? 'x' : '-';
 
75
    }
 
76
    *out = 0;
 
77
}
 
78
 
 
79
static void user2str(unsigned uid, char *out)
 
80
{
 
81
    struct passwd *pw = getpwuid(uid);
 
82
    if(pw) {
 
83
        strcpy(out, pw->pw_name);
 
84
    } else {
 
85
        sprintf(out, "%d", uid);
 
86
    }
 
87
}
 
88
 
 
89
static void group2str(unsigned gid, char *out)
 
90
{
 
91
    struct group *gr = getgrgid(gid);
 
92
    if(gr) {
 
93
        strcpy(out, gr->gr_name);
 
94
    } else {
 
95
        sprintf(out, "%d", gid);
 
96
    }
 
97
}
 
98
 
 
99
static int show_total_size(const char *dirname, DIR *d, int flags)
 
100
{
 
101
    struct dirent *de;
 
102
    char tmp[1024];
 
103
    struct stat s;
 
104
    int sum = 0;
 
105
 
 
106
    /* run through the directory and sum up the file block sizes */
 
107
    while ((de = readdir(d)) != 0) {
 
108
        if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
 
109
            continue;
 
110
        if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
 
111
            continue;
 
112
 
 
113
        if (strcmp(dirname, "/") == 0)
 
114
            snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
 
115
        else
 
116
            snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name);
 
117
 
 
118
        if (lstat(tmp, &s) < 0) {
 
119
            fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno));
 
120
            rewinddir(d);
 
121
            return -1;
 
122
        }
 
123
 
 
124
        sum += s.st_blocks / 2;
 
125
    }
 
126
 
 
127
    printf("total %d\n", sum);
 
128
    rewinddir(d);
 
129
    return 0;
 
130
}
 
131
 
 
132
static int listfile_size(const char *path, const char *filename, int flags)
 
133
{
 
134
    struct stat s;
 
135
 
 
136
    if (lstat(path, &s) < 0) {
 
137
        fprintf(stderr, "lstat '%s' failed: %s\n", path, strerror(errno));
 
138
        return -1;
 
139
    }
 
140
 
 
141
    /* blocks are 512 bytes, we want output to be KB */
 
142
    if ((flags & LIST_SIZE) != 0) {
 
143
        printf("%lld ", s.st_blocks / 2);
 
144
    }
 
145
 
 
146
    if ((flags & LIST_CLASSIFY) != 0) {
 
147
        char filetype = mode2kind(s.st_mode);
 
148
        if (filetype != 'l') {
 
149
            printf("%c ", filetype);
 
150
        } else {
 
151
            struct stat link_dest;
 
152
            if (!stat(path, &link_dest)) {
 
153
                printf("l%c ", mode2kind(link_dest.st_mode));
 
154
            } else {
 
155
                fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno));
 
156
                printf("l? ");
 
157
            }
 
158
        }
 
159
    }
 
160
 
 
161
    printf("%s\n", filename);
 
162
 
 
163
    return 0;
 
164
}
 
165
 
 
166
static int listfile_long(const char *path, int flags)
 
167
{
 
168
    struct stat s;
 
169
    char date[32];
 
170
    char mode[16];
 
171
    char user[16];
 
172
    char group[16];
 
173
    const char *name;
 
174
 
 
175
    /* name is anything after the final '/', or the whole path if none*/
 
176
    name = strrchr(path, '/');
 
177
    if(name == 0) {
 
178
        name = path;
 
179
    } else {
 
180
        name++;
 
181
    }
 
182
 
 
183
    if(lstat(path, &s) < 0) {
 
184
        return -1;
 
185
    }
 
186
 
 
187
    mode2str(s.st_mode, mode);
 
188
    if (flags & LIST_LONG_NUMERIC) {
 
189
        sprintf(user, "%ld", s.st_uid);
 
190
        sprintf(group, "%ld", s.st_gid);
 
191
    } else {
 
192
        user2str(s.st_uid, user);
 
193
        group2str(s.st_gid, group);
 
194
    }
 
195
 
 
196
    strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime));
 
197
    date[31] = 0;
 
198
 
 
199
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
 
200
// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
 
201
 
 
202
    switch(s.st_mode & S_IFMT) {
 
203
    case S_IFBLK:
 
204
    case S_IFCHR:
 
205
        printf("%s %-8s %-8s %3d, %3d %s %s\n",
 
206
               mode, user, group,
 
207
               (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev),
 
208
               date, name);
 
209
        break;
 
210
    case S_IFREG:
 
211
        printf("%s %-8s %-8s %8lld %s %s\n",
 
212
               mode, user, group, s.st_size, date, name);
 
213
        break;
 
214
    case S_IFLNK: {
 
215
        char linkto[256];
 
216
        int len;
 
217
 
 
218
        len = readlink(path, linkto, 256);
 
219
        if(len < 0) return -1;
 
220
 
 
221
        if(len > 255) {
 
222
            linkto[252] = '.';
 
223
            linkto[253] = '.';
 
224
            linkto[254] = '.';
 
225
            linkto[255] = 0;
 
226
        } else {
 
227
            linkto[len] = 0;
 
228
        }
 
229
 
 
230
        printf("%s %-8s %-8s          %s %s -> %s\n",
 
231
               mode, user, group, date, name, linkto);
 
232
        break;
 
233
    }
 
234
    default:
 
235
        printf("%s %-8s %-8s          %s %s\n",
 
236
               mode, user, group, date, name);
 
237
 
 
238
    }
 
239
    return 0;
 
240
}
 
241
 
 
242
static int listfile_maclabel(const char *path, int flags)
 
243
{
 
244
    struct stat s;
 
245
    char mode[16];
 
246
    char user[16];
 
247
    char group[16];
 
248
    char *maclabel = NULL;
 
249
    const char *name;
 
250
 
 
251
    /* name is anything after the final '/', or the whole path if none*/
 
252
    name = strrchr(path, '/');
 
253
    if(name == 0) {
 
254
        name = path;
 
255
    } else {
 
256
        name++;
 
257
    }
 
258
 
 
259
    if(lstat(path, &s) < 0) {
 
260
        return -1;
 
261
    }
 
262
 
 
263
#ifdef HAVE_SELINUX
 
264
    lgetfilecon(path, &maclabel);
 
265
#else
 
266
    maclabel = strdup("-");
 
267
#endif
 
268
    if (!maclabel) {
 
269
        return -1;
 
270
    }
 
271
 
 
272
    mode2str(s.st_mode, mode);
 
273
    user2str(s.st_uid, user);
 
274
    group2str(s.st_gid, group);
 
275
 
 
276
    switch(s.st_mode & S_IFMT) {
 
277
    case S_IFLNK: {
 
278
        char linkto[256];
 
279
        int len;
 
280
 
 
281
        len = readlink(path, linkto, sizeof(linkto));
 
282
        if(len < 0) return -1;
 
283
 
 
284
        if(len > sizeof(linkto)-1) {
 
285
            linkto[sizeof(linkto)-4] = '.';
 
286
            linkto[sizeof(linkto)-3] = '.';
 
287
            linkto[sizeof(linkto)-2] = '.';
 
288
            linkto[sizeof(linkto)-1] = 0;
 
289
        } else {
 
290
            linkto[len] = 0;
 
291
        }
 
292
 
 
293
        printf("%s %-8s %-8s          %s %s -> %s\n",
 
294
               mode, user, group, maclabel, name, linkto);
 
295
        break;
 
296
    }
 
297
    default:
 
298
        printf("%s %-8s %-8s          %s %s\n",
 
299
               mode, user, group, maclabel, name);
 
300
 
 
301
    }
 
302
 
 
303
    free(maclabel);
 
304
 
 
305
    return 0;
 
306
}
 
307
 
 
308
static int listfile(const char *dirname, const char *filename, int flags)
 
309
{
 
310
    if ((flags & LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL) == 0) {
 
311
        printf("%s\n", filename);
 
312
        return 0;
 
313
    }
 
314
 
 
315
    char tmp[4096];
 
316
    const char* pathname = filename;
 
317
 
 
318
    if (dirname != NULL) {
 
319
        snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename);
 
320
        pathname = tmp;
 
321
    } else {
 
322
        pathname = filename;
 
323
    }
 
324
 
 
325
    if ((flags & LIST_MACLABEL) != 0) {
 
326
        return listfile_maclabel(pathname, flags);
 
327
    } else if ((flags & LIST_LONG) != 0) {
 
328
        return listfile_long(pathname, flags);
 
329
    } else /*((flags & LIST_SIZE) != 0)*/ {
 
330
        return listfile_size(pathname, filename, flags);
 
331
    }
 
332
}
 
333
 
 
334
static int listdir(const char *name, int flags)
 
335
{
 
336
    char tmp[4096];
 
337
    DIR *d;
 
338
    struct dirent *de;
 
339
    strlist_t  files = STRLIST_INITIALIZER;
 
340
 
 
341
    d = opendir(name);
 
342
    if(d == 0) {
 
343
        fprintf(stderr, "opendir failed, %s\n", strerror(errno));
 
344
        return -1;
 
345
    }
 
346
 
 
347
    if ((flags & LIST_SIZE) != 0) {
 
348
        show_total_size(name, d, flags);
 
349
    }
 
350
 
 
351
    while((de = readdir(d)) != 0){
 
352
        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
 
353
        if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue;
 
354
 
 
355
        strlist_append_dup(&files, de->d_name);
 
356
    }
 
357
 
 
358
    strlist_sort(&files);
 
359
    STRLIST_FOREACH(&files, filename, listfile(name, filename, flags));
 
360
    strlist_done(&files);
 
361
 
 
362
    if (flags & LIST_RECURSIVE) {
 
363
        strlist_t subdirs = STRLIST_INITIALIZER;
 
364
 
 
365
        rewinddir(d);
 
366
 
 
367
        while ((de = readdir(d)) != 0) {
 
368
            struct stat s;
 
369
            int err;
 
370
 
 
371
            if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
 
372
                continue;
 
373
            if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0)
 
374
                continue;
 
375
 
 
376
            if (!strcmp(name, "/"))
 
377
                snprintf(tmp, sizeof(tmp), "/%s", de->d_name);
 
378
            else
 
379
                snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name);
 
380
 
 
381
            /*
 
382
             * If the name ends in a '/', use stat() so we treat it like a
 
383
             * directory even if it's a symlink.
 
384
             */
 
385
            if (tmp[strlen(tmp)-1] == '/')
 
386
                err = stat(tmp, &s);
 
387
            else
 
388
                err = lstat(tmp, &s);
 
389
 
 
390
            if (err < 0) {
 
391
                perror(tmp);
 
392
                closedir(d);
 
393
                return -1;
 
394
            }
 
395
 
 
396
            if (S_ISDIR(s.st_mode)) {
 
397
                strlist_append_dup(&subdirs, tmp);
 
398
            }
 
399
        }
 
400
        strlist_sort(&subdirs);
 
401
        STRLIST_FOREACH(&subdirs, path, {
 
402
            printf("\n%s:\n", path);
 
403
            listdir(path, flags);
 
404
        });
 
405
        strlist_done(&subdirs);
 
406
    }
 
407
 
 
408
    closedir(d);
 
409
    return 0;
 
410
}
 
411
 
 
412
static int listpath(const char *name, int flags)
 
413
{
 
414
    struct stat s;
 
415
    int err;
 
416
 
 
417
    /*
 
418
     * If the name ends in a '/', use stat() so we treat it like a
 
419
     * directory even if it's a symlink.
 
420
     */
 
421
    if (name[strlen(name)-1] == '/')
 
422
        err = stat(name, &s);
 
423
    else
 
424
        err = lstat(name, &s);
 
425
 
 
426
    if (err < 0) {
 
427
        perror(name);
 
428
        return -1;
 
429
    }
 
430
 
 
431
    if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) {
 
432
        if (flags & LIST_RECURSIVE)
 
433
            printf("\n%s:\n", name);
 
434
        return listdir(name, flags);
 
435
    } else {
 
436
        /* yeah this calls stat() again*/
 
437
        return listfile(NULL, name, flags);
 
438
    }
 
439
}
 
440
 
 
441
int ls_main(int argc, char **argv)
 
442
{
 
443
    int flags = 0;
 
444
    int listed = 0;
 
445
 
 
446
    if(argc > 1) {
 
447
        int i;
 
448
        int err = 0;
 
449
        strlist_t  files = STRLIST_INITIALIZER;
 
450
 
 
451
        for (i = 1; i < argc; i++) {
 
452
            if (argv[i][0] == '-') {
 
453
                /* an option ? */
 
454
                const char *arg = argv[i]+1;
 
455
                while (arg[0]) {
 
456
                    switch (arg[0]) {
 
457
                    case 'l': flags |= LIST_LONG; break;
 
458
                    case 'n': flags |= LIST_LONG | LIST_LONG_NUMERIC; break;
 
459
                    case 's': flags |= LIST_SIZE; break;
 
460
                    case 'R': flags |= LIST_RECURSIVE; break;
 
461
                    case 'd': flags |= LIST_DIRECTORIES; break;
 
462
                    case 'Z': flags |= LIST_MACLABEL; break;
 
463
                    case 'a': flags |= LIST_ALL; break;
 
464
                    case 'F': flags |= LIST_CLASSIFY; break;
 
465
                    default:
 
466
                        fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
 
467
                        exit(1);
 
468
                    }
 
469
                    arg++;
 
470
                }
 
471
            } else {
 
472
                /* not an option ? */
 
473
                strlist_append_dup(&files, argv[i]);
 
474
            }
 
475
        }
 
476
 
 
477
        if (files.count > 0) {
 
478
            STRLIST_FOREACH(&files, path, {
 
479
                if (listpath(path, flags) != 0) {
 
480
                    err = EXIT_FAILURE;
 
481
                }
 
482
            });
 
483
            strlist_done(&files);
 
484
            return err;
 
485
        }
 
486
    }
 
487
 
 
488
    // list working directory if no files or directories were specified
 
489
    return listpath(".", flags);
 
490
}