ls.c revision a8d1afb3e91b043fcd303a40ca4ac9293bbd2781
1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h> 2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h> 3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h> 4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/types.h> 5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <dirent.h> 6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h> 7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/stat.h> 9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h> 10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <time.h> 11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <pwd.h> 13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <grp.h> 14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <linux/kdev_t.h> 16aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner#include <limits.h> 17aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner 18a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner#include "dynarray.h" 19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// bits for flags argument 21b33d3415b6c63f7b22e0863a2ac594feab9171cfAndy McFadden#define LIST_LONG (1 << 0) 22b33d3415b6c63f7b22e0863a2ac594feab9171cfAndy McFadden#define LIST_ALL (1 << 1) 23b33d3415b6c63f7b22e0863a2ac594feab9171cfAndy McFadden#define LIST_RECURSIVE (1 << 2) 24b33d3415b6c63f7b22e0863a2ac594feab9171cfAndy McFadden#define LIST_DIRECTORIES (1 << 3) 25327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden#define LIST_SIZE (1 << 4) 26e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick#define LIST_LONG_NUMERIC (1 << 5) 27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// fwd 29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int listpath(const char *name, int flags); 30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic char mode2kind(unsigned mode) 32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project switch(mode & S_IFMT){ 34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFSOCK: return 's'; 35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFLNK: return 'l'; 36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFREG: return '-'; 37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFDIR: return 'd'; 38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFBLK: return 'b'; 39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFCHR: return 'c'; 40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFIFO: return 'p'; 41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project default: return '?'; 42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void mode2str(unsigned mode, char *out) 46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = mode2kind(mode); 48a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner 49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 0400) ? 'r' : '-'; 50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 0200) ? 'w' : '-'; 51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(mode & 04000) { 52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 0100) ? 's' : 'S'; 53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 0100) ? 'x' : '-'; 55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 040) ? 'r' : '-'; 57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 020) ? 'w' : '-'; 58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(mode & 02000) { 59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 010) ? 's' : 'S'; 60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 010) ? 'x' : '-'; 62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 04) ? 'r' : '-'; 64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 02) ? 'w' : '-'; 65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(mode & 01000) { 66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 01) ? 't' : 'T'; 67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out++ = (mode & 01) ? 'x' : '-'; 69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *out = 0; 71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void user2str(unsigned uid, char *out) 74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project struct passwd *pw = getpwuid(uid); 76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(pw) { 77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project strcpy(out, pw->pw_name); 78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project sprintf(out, "%d", uid); 80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void group2str(unsigned gid, char *out) 84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project struct group *gr = getgrgid(gid); 86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(gr) { 87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project strcpy(out, gr->gr_name); 88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project sprintf(out, "%d", gid); 90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 939feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFaddenstatic int show_total_size(const char *dirname, DIR *d, int flags) 94327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden{ 959feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden struct dirent *de; 969feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden char tmp[1024]; 97327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden struct stat s; 989feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden int sum = 0; 999feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden 1009feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden /* run through the directory and sum up the file block sizes */ 1019feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden while ((de = readdir(d)) != 0) { 1029feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) 1039feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden continue; 1049feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) 1059feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden continue; 1069feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden 1079feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden if (strcmp(dirname, "/") == 0) 1089feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden snprintf(tmp, sizeof(tmp), "/%s", de->d_name); 1099feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden else 1109feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name); 1119feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden 1129feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden if (lstat(tmp, &s) < 0) { 1139feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno)); 1149feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden rewinddir(d); 1159feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden return -1; 1169feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden } 1179feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden 1189feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden sum += s.st_blocks / 2; 1199feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden } 120327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 1219feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden printf("total %d\n", sum); 1229feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden rewinddir(d); 1239feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden return 0; 1249feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden} 1259feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden 1269feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFaddenstatic int listfile_size(const char *path, const char *filename, int flags) 1279feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden{ 1289feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden struct stat s; 1299feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden 1309feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden if (lstat(path, &s) < 0) { 1319feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden fprintf(stderr, "lstat '%s' failed: %s\n", path, strerror(errno)); 132327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden return -1; 1339feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden } 134327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 135327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden /* blocks are 512 bytes, we want output to be KB */ 1369feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden printf("%lld %s\n", s.st_blocks / 2, filename); 137327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden return 0; 138327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden} 139327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 140327e696808910f8e49370079f8d7f4db8cbe3820Andy McFaddenstatic int listfile_long(const char *path, int flags) 141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project struct stat s; 143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char date[32]; 144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char mode[16]; 145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char user[16]; 146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char group[16]; 147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project const char *name; 148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* name is anything after the final '/', or the whole path if none*/ 150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project name = strrchr(path, '/'); 151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(name == 0) { 152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project name = path; 153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project name++; 155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(lstat(path, &s) < 0) { 158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project mode2str(s.st_mode, mode); 162e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick if (flags & LIST_LONG_NUMERIC) { 163e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick sprintf(user, "%ld", s.st_uid); 164e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick sprintf(group, "%ld", s.st_gid); 165e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick } else { 166e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick user2str(s.st_uid, user); 167e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick group2str(s.st_gid, group); 168e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick } 169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime)); 171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project date[31] = 0; 172a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner 173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK) 175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project switch(s.st_mode & S_IFMT) { 177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFBLK: 178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFCHR: 179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project printf("%s %-8s %-8s %3d, %3d %s %s\n", 180a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner mode, user, group, 181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev), 182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project date, name); 183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project break; 184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFREG: 185eb42170e6c8b70f11dca9965785aa04a80290c72Kenny Root printf("%s %-8s %-8s %8lld %s %s\n", 186eb42170e6c8b70f11dca9965785aa04a80290c72Kenny Root mode, user, group, s.st_size, date, name); 187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project break; 188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project case S_IFLNK: { 189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char linkto[256]; 190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int len; 191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project len = readlink(path, linkto, 256); 193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(len < 0) return -1; 194a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner 195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(len > 255) { 196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project linkto[252] = '.'; 197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project linkto[253] = '.'; 198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project linkto[254] = '.'; 199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project linkto[255] = 0; 200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project linkto[len] = 0; 202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 203a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner 204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project printf("%s %-8s %-8s %s %s -> %s\n", 205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project mode, user, group, date, name, linkto); 206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project break; 207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project default: 209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project printf("%s %-8s %-8s %s %s\n", 210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project mode, user, group, date, name); 211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 216327e696808910f8e49370079f8d7f4db8cbe3820Andy McFaddenstatic int listfile(const char *dirname, const char *filename, int flags) 217327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden{ 218327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden if ((flags & (LIST_LONG | LIST_SIZE)) == 0) { 219327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden printf("%s\n", filename); 220327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden return 0; 221327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden } 222327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 223327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden char tmp[4096]; 224327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden const char* pathname = filename; 225327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 226327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden if (dirname != NULL) { 227327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename); 228327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden pathname = tmp; 229327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden } else { 230327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden pathname = filename; 231327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden } 232327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 233327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden if ((flags & LIST_LONG) != 0) { 234327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden return listfile_long(pathname, flags); 235327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden } else /*((flags & LIST_SIZE) != 0)*/ { 2369feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden return listfile_size(pathname, filename, flags); 237327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden } 238327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden} 239327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int listdir(const char *name, int flags) 241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char tmp[4096]; 243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project DIR *d; 244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project struct dirent *de; 245aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_t files = STRLIST_INITIALIZER; 246a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner 247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project d = opendir(name); 248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(d == 0) { 249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project fprintf(stderr, "opendir failed, %s\n", strerror(errno)); 250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 2539feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden if ((flags & LIST_SIZE) != 0) { 2549feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden show_total_size(name, d, flags); 2559feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden } 2569feee025a09ace19b09dbb41d6ba87198c77cdf1Andy McFadden 257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project while((de = readdir(d)) != 0){ 258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; 259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue; 260327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden 261aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_append_dup(&files, de->d_name); 262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 264aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_sort(&files); 265aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner STRLIST_FOREACH(&files, filename, listfile(name, filename, flags)); 266aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_done(&files); 267aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner 268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (flags & LIST_RECURSIVE) { 269aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_t subdirs = STRLIST_INITIALIZER; 270aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner 271dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project rewinddir(d); 272dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 273dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project while ((de = readdir(d)) != 0) { 274dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project struct stat s; 275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int err; 276dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 277dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) 278dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project continue; 279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) 280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project continue; 281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 282327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden if (!strcmp(name, "/")) 283327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden snprintf(tmp, sizeof(tmp), "/%s", de->d_name); 284327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden else 285327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name); 286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * If the name ends in a '/', use stat() so we treat it like a 289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * directory even if it's a symlink. 290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (tmp[strlen(tmp)-1] == '/') 292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project err = stat(tmp, &s); 293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project else 294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project err = lstat(tmp, &s); 295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 296dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (err < 0) { 297dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project perror(tmp); 298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project closedir(d); 299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 300dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 301dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (S_ISDIR(s.st_mode)) { 303aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_append_dup(&subdirs, tmp); 304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 306aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_sort(&subdirs); 307aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner STRLIST_FOREACH(&subdirs, path, { 308aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner printf("\n%s:\n", path); 309aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner listdir(path, flags); 310aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner }); 311aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_done(&subdirs); 312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project closedir(d); 315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int listpath(const char *name, int flags) 319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project struct stat s; 321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int err; 322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* 324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * If the name ends in a '/', use stat() so we treat it like a 325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * directory even if it's a symlink. 326dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 327dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (name[strlen(name)-1] == '/') 328dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project err = stat(name, &s); 329dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project else 330dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project err = lstat(name, &s); 331dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 332dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (err < 0) { 333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project perror(name); 334dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return -1; 335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 337b33d3415b6c63f7b22e0863a2ac594feab9171cfAndy McFadden if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) { 338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (flags & LIST_RECURSIVE) 339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project printf("\n%s:\n", name); 340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return listdir(name, flags); 341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 342327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden /* yeah this calls stat() again*/ 343327e696808910f8e49370079f8d7f4db8cbe3820Andy McFadden return listfile(NULL, name, flags); 344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint ls_main(int argc, char **argv) 348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project{ 349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int flags = 0; 350dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int listed = 0; 351a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner 352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if(argc > 1) { 353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int i; 354dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int err = 0; 355aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_t files = STRLIST_INITIALIZER; 356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (i = 1; i < argc; i++) { 358aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner if (argv[i][0] == '-') { 359aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner /* an option ? */ 360aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner const char *arg = argv[i]+1; 361aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner while (arg[0]) { 362aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner switch (arg[0]) { 363aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner case 'l': flags |= LIST_LONG; break; 364e7fe5bf3ac2c0218bda75da78975d6a18fe7c167Brad Fitzpatrick case 'n': flags |= LIST_LONG | LIST_LONG_NUMERIC; break; 365aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner case 's': flags |= LIST_SIZE; break; 366aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner case 'R': flags |= LIST_RECURSIVE; break; 367aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner case 'd': flags |= LIST_DIRECTORIES; break; 368aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner case 'a': flags |= LIST_ALL; break; 369aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner default: 370aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]); 371aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner exit(1); 372aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner } 373aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner arg++; 374dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 375aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner } else { 376aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner /* not an option ? */ 377aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_append_dup(&files, argv[i]); 378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 379dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 380dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 381aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner if (files.count > 0) { 382aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner STRLIST_FOREACH(&files, path, { 383aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner if (listpath(path, flags) != 0) { 384aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner err = EXIT_FAILURE; 385aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner } 386aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner }); 387aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner strlist_done(&files); 388aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner return err; 389aa2106b008921ed8f33ee14ee70fb1b944f547ecDavid 'Digit' Turner } 390dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 391a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner 392a8d1afb3e91b043fcd303a40ca4ac9293bbd2781David 'Digit' Turner // list working directory if no files or directories were specified 393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return listpath(".", flags); 394dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 395