ls.c (6170B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <dirent.h> 3 #include <grp.h> 4 #include <pwd.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <time.h> 10 #include <unistd.h> 11 12 #include "util.h" 13 14 typedef struct { 15 char *name; 16 mode_t mode, tmode; 17 nlink_t nlink; 18 uid_t uid; 19 gid_t gid; 20 off_t size; 21 time_t t; 22 ino_t ino; 23 } Entry; 24 25 static int entcmp(const void *, const void *); 26 static void ls(Entry *); 27 static void lsdir(const char *); 28 static void mkent(Entry *, char *, int, int); 29 static void output(Entry *); 30 31 static int aflag = 0; 32 static int cflag = 0; 33 static int dflag = 0; 34 static int Fflag = 0; 35 static int Hflag = 0; 36 static int hflag = 0; 37 static int iflag = 0; 38 static int Lflag = 0; 39 static int lflag = 0; 40 static int rflag = 0; 41 static int tflag = 0; 42 static int Uflag = 0; 43 static int first = 1; 44 static int many; 45 46 static void 47 usage(void) 48 { 49 eprintf("usage: %s [-1acdFHhiLlrtU] [file ...]\n", argv0); 50 } 51 52 int 53 main(int argc, char *argv[]) 54 { 55 int i; 56 Entry *ents; 57 58 ARGBEGIN { 59 case '1': 60 /* ignore */ 61 break; 62 case 'a': 63 aflag = 1; 64 break; 65 case 'c': 66 cflag = 1; 67 break; 68 case 'd': 69 dflag = 1; 70 break; 71 case 'F': 72 Fflag = 1; 73 break; 74 case 'H': 75 Hflag = 1; 76 break; 77 case 'h': 78 hflag = 1; 79 break; 80 case 'i': 81 iflag = 1; 82 break; 83 case 'L': 84 Lflag = 1; 85 break; 86 case 'l': 87 lflag = 1; 88 break; 89 case 'r': 90 rflag = 1; 91 break; 92 case 't': 93 tflag = 1; 94 break; 95 case 'U': 96 Uflag = 1; 97 break; 98 default: 99 usage(); 100 } ARGEND; 101 102 many = (argc > 1); 103 if (argc == 0) 104 *--argv = ".", argc++; 105 106 ents = emalloc(argc * sizeof(*ents)); 107 108 for (i = 0; i < argc; i++) 109 mkent(&ents[i], argv[i], 1, Hflag || Lflag); 110 qsort(ents, argc, sizeof *ents, entcmp); 111 for (i = 0; i < argc; i++) 112 ls(&ents[rflag ? argc-i-1 : i]); 113 114 return 0; 115 } 116 117 static int 118 entcmp(const void *va, const void *vb) 119 { 120 const Entry *a = va, *b = vb; 121 122 if (tflag) 123 return b->t - a->t; 124 else 125 return strcmp(a->name, b->name); 126 } 127 128 static void 129 ls(Entry *ent) 130 { 131 if ((S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag) { 132 lsdir(ent->name); 133 } else { 134 output(ent); 135 } 136 } 137 138 static void 139 lsdir(const char *path) 140 { 141 char *cwd, *p; 142 long i, n = 0; 143 struct dirent *d; 144 DIR *dp; 145 Entry ent, *ents = NULL; 146 size_t sz; 147 148 cwd = agetcwd(); 149 if (!(dp = opendir(path))) 150 eprintf("opendir %s:", path); 151 if (chdir(path) < 0) 152 eprintf("chdir %s:", path); 153 154 if (many) { 155 if (!first) 156 putchar('\n'); 157 printf("%s:\n", path); 158 first = 0; 159 } 160 161 while ((d = readdir(dp))) { 162 if (d->d_name[0] == '.' && !aflag) 163 continue; 164 if (Uflag){ 165 mkent(&ent, d->d_name, Fflag || lflag || iflag, Lflag); 166 output(&ent); 167 } else { 168 ents = erealloc(ents, ++n * sizeof *ents); 169 p = emalloc((sz = strlen(d->d_name)+1)); 170 memcpy(p, d->d_name, sz); 171 mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag, Lflag); 172 } 173 } 174 closedir(dp); 175 if (!Uflag){ 176 qsort(ents, n, sizeof *ents, entcmp); 177 for (i = 0; i < n; i++) { 178 output(&ents[rflag ? n-i-1 : i]); 179 free(ents[rflag ? n-i-1 : i].name); 180 } 181 } 182 if (chdir(cwd) < 0) 183 eprintf("chdir %s:", cwd); 184 free(ents); 185 free(cwd); 186 } 187 188 static void 189 mkent(Entry *ent, char *path, int dostat, int follow) 190 { 191 struct stat st; 192 193 ent->name = path; 194 if (!dostat) 195 return; 196 if ((follow ? stat : lstat)(path, &st) < 0) 197 eprintf("%s %s:", follow ? "stat" : "lstat", path); 198 ent->mode = st.st_mode; 199 ent->nlink = st.st_nlink; 200 ent->uid = st.st_uid; 201 ent->gid = st.st_gid; 202 ent->size = st.st_size; 203 ent->t = cflag ? st.st_ctime : st.st_mtime; 204 ent->ino = st.st_ino; 205 if (S_ISLNK(ent->mode)) 206 ent->tmode = stat(path, &st) == 0 ? st.st_mode : 0; 207 } 208 209 static char * 210 indicator(mode_t mode) 211 { 212 if (!Fflag) 213 return ""; 214 215 if (S_ISLNK(mode)) 216 return "@"; 217 else if (S_ISDIR(mode)) 218 return "/"; 219 else if (S_ISFIFO(mode)) 220 return "|"; 221 else if (S_ISSOCK(mode)) 222 return "="; 223 else if (mode & S_IXUSR || 224 mode & S_IXGRP || 225 mode & S_IXOTH) 226 return "*"; 227 else 228 return ""; 229 } 230 231 static void 232 output(Entry *ent) 233 { 234 char buf[BUFSIZ], *fmt; 235 char mode[] = "----------"; 236 ssize_t len; 237 struct group *gr; 238 struct passwd *pw; 239 char pwname[_SC_LOGIN_NAME_MAX]; 240 char grname[_SC_LOGIN_NAME_MAX]; 241 242 if (iflag) 243 printf("%lu ", (unsigned long)ent->ino); 244 if (!lflag) { 245 printf("%s%s\n", ent->name, indicator(ent->mode)); 246 return; 247 } 248 if (S_ISREG(ent->mode)) 249 mode[0] = '-'; 250 else if (S_ISBLK(ent->mode)) 251 mode[0] = 'b'; 252 else if (S_ISCHR(ent->mode)) 253 mode[0] = 'c'; 254 else if (S_ISDIR(ent->mode)) 255 mode[0] = 'd'; 256 else if (S_ISFIFO(ent->mode)) 257 mode[0] = 'p'; 258 else if (S_ISLNK(ent->mode)) 259 mode[0] = 'l'; 260 else if (S_ISSOCK(ent->mode)) 261 mode[0] = 's'; 262 else 263 mode[0] = '?'; 264 265 if (ent->mode & S_IRUSR) mode[1] = 'r'; 266 if (ent->mode & S_IWUSR) mode[2] = 'w'; 267 if (ent->mode & S_IXUSR) mode[3] = 'x'; 268 if (ent->mode & S_IRGRP) mode[4] = 'r'; 269 if (ent->mode & S_IWGRP) mode[5] = 'w'; 270 if (ent->mode & S_IXGRP) mode[6] = 'x'; 271 if (ent->mode & S_IROTH) mode[7] = 'r'; 272 if (ent->mode & S_IWOTH) mode[8] = 'w'; 273 if (ent->mode & S_IXOTH) mode[9] = 'x'; 274 275 if (ent->mode & S_ISUID) mode[3] = (mode[3] == 'x') ? 's' : 'S'; 276 if (ent->mode & S_ISGID) mode[6] = (mode[6] == 'x') ? 's' : 'S'; 277 if (ent->mode & S_ISVTX) mode[9] = (mode[9] == 'x') ? 't' : 'T'; 278 279 pw = getpwuid(ent->uid); 280 if (pw) 281 snprintf(pwname, sizeof(pwname), "%s", pw->pw_name); 282 else 283 snprintf(pwname, sizeof(pwname), "%d", ent->uid); 284 285 gr = getgrgid(ent->gid); 286 if (gr) 287 snprintf(grname, sizeof(grname), "%s", gr->gr_name); 288 else 289 snprintf(grname, sizeof(grname), "%d", ent->gid); 290 291 if (time(NULL) > ent->t + (180*24*60*60)) /* 6 months ago? */ 292 fmt = "%b %d %Y"; 293 else 294 fmt = "%b %d %H:%M"; 295 296 strftime(buf, sizeof buf, fmt, localtime(&ent->t)); 297 printf("%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname); 298 if (hflag) 299 printf("%10s ", humansize((unsigned long)ent->size)); 300 else 301 printf("%10lu ", (unsigned long)ent->size); 302 printf("%s %s%s", buf, ent->name, indicator(ent->mode)); 303 if (S_ISLNK(ent->mode)) { 304 if ((len = readlink(ent->name, buf, sizeof buf - 1)) < 0) 305 eprintf("readlink %s:", ent->name); 306 buf[len] = '\0'; 307 printf(" -> %s%s", buf, indicator(ent->tmode)); 308 } 309 putchar('\n'); 310 }