#include #include #include #include #include #include #include #include #include #include #include char *progname; #include "arg.h" Winsize termsz; int allFlag = 0; int longFlag = 0; /* Structure for a result */ typedef struct Result Result; struct Result { Result *next, *prev; ino_t ino; enum DirType type; size_t namelen; char name[255]; Stat stat; }; /* Compare results by name */ static int compare_name(Result *a, Result *b) { return (strcmp(a->name, b->name) < 0); } /* Compare results by type */ static int compare_type(Result *a, Result *b) { return (a->type == DT_DIR && b->type != DT_DIR); } /* Sort a list of results */ static Result * sort_results(Result *head, int (*compare)(Result *, Result *)) { Result *curr, *shead = NULL, *slast, *scurr; int i, len = 0; for (curr = head; curr; curr = curr->next) len++; /* Sort */ for (i = 0; i < len; i++) { scurr = head; for (curr = head->next; curr; curr = curr->next) { if (compare(curr, scurr)) scurr = curr; } /* Unlink from old list */ if (scurr == head) head = scurr->next; if (scurr->next) scurr->next->prev = scurr->prev; if (scurr->prev) scurr->prev->next = scurr->next; scurr->prev = scurr->next = NULL; /* Add to sorted list */ if (!shead) { shead = scurr; } else { scurr->prev = slast; slast->next = scurr; } slast = scurr; } return shead; } /* Print normal results */ static void print_normal(Result *head) { Result *curr, *next, *prev; size_t printed = 0; for (curr = head; curr; curr = next) { prev = curr->prev; next = curr->next; int executable = 0; if ((curr->stat.mode & S_IXUSR) || (curr->stat.mode & S_IXGRP) || (curr->stat.mode & S_IXOTH)) executable = 1; if (curr->type == DT_DIR) printf("\033[1;34m%s\033[0m ", curr->name); else if (curr->type == DT_CHR || curr->type == DT_BLK) printf("\033[1;33m%s\033[0m ", curr->name); else if (curr->type == DT_LNK) printf("\033[1;36m%s\033[0m ", curr->name); else if (curr->type == DT_REG && executable) printf("\033[1;32m%s\033[0m ", curr->name); else printf("%s ", curr->name); printed++; /* Remove from list */ if (prev) prev->next = next; if (next) next->prev = prev; if (curr == head) head = next; free(curr); } if (printed) putchar('\n'); } /* Print long results */ static void print_long(Result *head) { Result *curr, *next, *prev; size_t printed = 0; /* Find max column widths */ size_t total = 0; int linkWidth = 0, unameWidth = 0, groupWidth = 0, sizeWidth = 0; for (curr = head; curr; curr = curr->next) { int linkTmp = curr->stat.nlink, linkWidthTmp = 1; while (linkTmp /= 10) linkWidthTmp++; if (linkWidthTmp > linkWidth) linkWidth = linkWidthTmp; Passwd *pwd = getpwuid(curr->stat.uid); if (strlen(pwd->username) > unameWidth) unameWidth = strlen(pwd->username); Group *grp = getgrgid(curr->stat.gid); if (strlen(grp->name) > groupWidth) groupWidth = strlen(grp->name); int sizeTmp = curr->stat.size, sizeWidthTmp = 1; while (sizeTmp /= 10) sizeWidthTmp++; if (sizeWidthTmp > sizeWidth) sizeWidth = sizeWidthTmp; total += (curr->stat.size + (1024 - 1)) / 1024; } /* Print out */ printf("total %d\n", total); for (curr = head; curr; curr = next) { prev = curr->prev; next = curr->next; char perm[] = "----------"; char type[] = "?-dcbfsl"; char uname[33], group[33]; int executable = 0; perm[0] = type[curr->type]; perm[1] = (curr->stat.mode & S_IRUSR) ? 'r' : '-'; perm[2] = (curr->stat.mode & S_IWUSR) ? 'w' : '-'; perm[3] = (curr->stat.mode & S_IXUSR) ? 'x' : '-'; perm[4] = (curr->stat.mode & S_IRGRP) ? 'r' : '-'; perm[5] = (curr->stat.mode & S_IWGRP) ? 'w' : '-'; perm[6] = (curr->stat.mode & S_IXGRP) ? 'x' : '-'; perm[7] = (curr->stat.mode & S_IROTH) ? 'r' : '-'; perm[8] = (curr->stat.mode & S_IWOTH) ? 'w' : '-'; perm[9] = (curr->stat.mode & S_IXOTH) ? 'x' : '-'; Passwd *pwd = getpwuid(curr->stat.uid); Group *grp = getgrgid(curr->stat.gid); if ((curr->stat.mode & S_IXUSR) || (curr->stat.mode & S_IXGRP) || (curr->stat.mode & S_IXOTH)) executable = 1; printf("%s %*d %*s %*s %*d ", perm, linkWidth, curr->stat.nlink, -unameWidth, pwd->username, -groupWidth, grp->name, sizeWidth, curr->stat.size); if (curr->type == DT_DIR) printf("\033[1;34m%s\033[0m\n", curr->name); else if (curr->type == DT_CHR || curr->type == DT_BLK) printf("\033[1;33m%s\033[0m\n", curr->name); else if (curr->type == DT_LNK) printf("\033[1;36m%s\033[0m\n", curr->name); else if (curr->type == DT_REG && executable) printf("\033[1;32m%s\033[0m\n", curr->name); else printf("%s\n", curr->name); printed++; /* Remove from list */ if (prev) prev->next = next; if (next) next->prev = prev; if (curr == head) head = next; free(curr); } } /* List files in a directory */ static void ls(char *name) { int fd, sz, i; char *buf, cwd[1024]; struct stat statbuf; struct dirent *de; Result *head = NULL, *prev = NULL, *next, *curr; size_t len = 0, longest = 0; fd = open(name, O_RDONLY); if (fd < 0) { printf("%s: %s: ", progname, name); perror(NULL); return; } stat(name, &statbuf); if (!S_ISDIR(statbuf.mode)) { close(fd); return; } getcwd(cwd, 1024); chdir(name); /* Get Directory Entries */ buf = malloc(512); sz = getdents(fd, buf, 512); for (de = (void *) buf; de < (struct dirent *) (buf + sz); de = (void *) de + de->namelen + sizeof(struct dirent)) { if (de->name[0] == '.' && !allFlag) continue; curr = malloc(sizeof(Result)); curr->next = NULL; curr->prev = prev; curr->ino = de->ino; curr->type = de->type; curr->namelen = de->namelen; memcpy(curr->name, de->name, de->namelen); curr->name[de->namelen] = '\0'; stat(curr->name, &curr->stat); if (prev) prev->next = curr; else head = curr; prev = curr; len++; if (longest < curr->namelen) longest = curr->namelen; } free(buf); close(fd); head = sort_results(head, compare_name); head = sort_results(head, compare_type); if (longFlag) print_long(head); else print_normal(head); chdir(cwd); } /* Main function */ int main(int argc, char *argv[]) { int i; ioctl(STDOUT_FILENO, TCGWINSZ, &termsz); ARGBEGIN { case 'a': allFlag = 1; break; case 'l': longFlag = 1; break; default: printf("Usage:\n"); } ARGEND; if (argc == 0) { ls("."); return 0; } if (argc == 1) { ls(argv[0]); return 0; } for (i = 0; i < argc; i++) { printf("%s:\n", argv[i]); ls(argv[i]); if (i < argc-1) printf("\n"); } return 0; }