OrionUserland
Barry Importing existing Orion Userland 19aefaa (2 years, 4 months ago)diff --git a/ls/main.c b/ls/main.c new file mode 100644 index 0000000..27b754c --- /dev/null +++ b/ls/main.c @@ -0,0 +1,320 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <dirent.h> +#include <termios.h> +#include <pwd.h> +#include <grp.h> + +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; +}