Simple utility to list information about a files. The utility which does the same thing as "ls -la". This is a useful test program. Signed-off-by: Alexey Gladkov <gladkov.alexey at gmail.com> --- usr/utils/Kbuild | 4 +- usr/utils/ls.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 1 deletions(-) create mode 100644 usr/utils/ls.c diff --git a/usr/utils/Kbuild b/usr/utils/Kbuild index 5b6dc28..354a364 100644 --- a/usr/utils/Kbuild +++ b/usr/utils/Kbuild @@ -3,7 +3,7 @@ # progs := chroot dd mkdir mkfifo mknod mount pivot_root umount -progs += true false sleep ln nuke minips cat +progs += true false sleep ln nuke minips cat ls progs += uname halt kill readlink cpio sync dmesg static-y := $(addprefix static/, $(progs)) @@ -36,6 +36,8 @@ static/sleep-y := sleep.o shared/sleep-y := sleep.o static/ln-y := ln.o shared/ln-y := ln.o +static/ls-y := ls.o +shared/ls-y := ls.o static/nuke-y := nuke.o shared/nuke-y := nuke.o static/minips-y := minips.o diff --git a/usr/utils/ls.c b/usr/utils/ls.c new file mode 100644 index 0000000..859142a --- /dev/null +++ b/usr/utils/ls.c @@ -0,0 +1,202 @@ +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/sysmacros.h> + +#define STAT_ISSET(mode, mask) (((mode) & mask) == mask) + +static size_t max_linksiz = 128; +static int max_nlinks = 1; +static int max_size = 1; +static int max_uid = 1; +static int max_gid = 1; +static int max_min = 1; +static int max_maj = 1; + +static void do_preformat(const struct stat *st) +{ + int bytes; + + if ((bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_nlink)) > max_nlinks) + max_nlinks = bytes; + + if ((bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_uid)) > max_uid) + max_uid = bytes; + + if ((bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_gid)) > max_gid) + max_gid = bytes; + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { + if ((bytes = snprintf(NULL, 0, "%u", major(st->st_rdev))) > max_maj) + max_maj = bytes; + + if ((bytes = snprintf(NULL, 0, "%u", minor(st->st_rdev))) > max_min) + max_min = bytes; + + max_size = max_maj + max_min + 1; + } + else { + if ((bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_size)) > max_size) + max_size = bytes; + } + return; +} + +static void do_stat(const struct stat *st, const char *path) +{ + char *fmt, *link_name; + int rc; + + switch (st->st_mode & S_IFMT) { + case S_IFBLK: putchar('b'); break; + case S_IFCHR: putchar('c'); break; + case S_IFDIR: putchar('d'); break; + case S_IFIFO: putchar('p'); break; + case S_IFLNK: putchar('l'); break; + case S_IFSOCK: putchar('s'); break; + case S_IFREG: putchar('-'); break; + default: putchar('?'); break; + } + putchar(STAT_ISSET(st->st_mode, S_IRUSR) ? 'r' : '-'); + putchar(STAT_ISSET(st->st_mode, S_IWUSR) ? 'w' : '-'); + + !STAT_ISSET(st->st_mode, S_ISUID) ? + putchar(STAT_ISSET(st->st_mode, S_IXUSR) ? 'x' : '-') : + putchar('S'); + + putchar(STAT_ISSET(st->st_mode, S_IRGRP) ? 'r' : '-'); + putchar(STAT_ISSET(st->st_mode, S_IWGRP) ? 'w' : '-'); + + !STAT_ISSET(st->st_mode, S_ISGID) ? + putchar(STAT_ISSET(st->st_mode, S_IXGRP) ? 'x' : '-') : + putchar('S'); + + putchar(STAT_ISSET(st->st_mode, S_IROTH) ? 'r' : '-'); + putchar(STAT_ISSET(st->st_mode, S_IWOTH) ? 'w' : '-'); + + !STAT_ISSET(st->st_mode, S_ISVTX) ? + putchar(STAT_ISSET(st->st_mode, S_IXOTH) ? 'x' : '-') : + putchar(S_ISDIR(st->st_mode) ? 't' : 'T'); + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { + rc = asprintf(&fmt," %%%dju %%%dju %%%dju %%%du,%%%du %%s", + max_nlinks, max_uid, max_gid, max_maj, max_min); + if (rc == -1) { + perror("asprintf"); + exit(1); + } + fprintf(stdout, fmt, + (uintmax_t) st->st_nlink, + (uintmax_t) st->st_uid, + (uintmax_t) st->st_gid, + major(st->st_rdev), + minor(st->st_rdev), + path); + } + else { + rc = asprintf(&fmt," %%%dju %%%dju %%%dju %%%dju %%s", + max_nlinks, max_uid, max_gid, max_size); + if (rc == -1) { + perror("asprintf"); + exit(1); + } + fprintf(stdout, fmt, + (uintmax_t) st->st_nlink, + (uintmax_t) st->st_uid, + (uintmax_t) st->st_gid, + (uintmax_t) st->st_size, + path); + } + free(fmt); + + if (S_ISLNK(st->st_mode)) { + if ((link_name = malloc(max_linksiz)) == NULL) { + perror("malloc"); + exit(1); + } + if ((rc = readlink(path, link_name, max_linksiz)) == -1) { + free(link_name); + perror("readlink"); + exit(1); + } + link_name[rc] = '\0'; + fprintf(stdout, " -> %s", link_name); + free(link_name); + } + + putchar('\n'); + return; +} + +static void do_dir(const char *path, int preformat) +{ + DIR *dir; + struct dirent *dent; + struct stat st; + + if (chdir(path) == -1) { + perror(path); + exit(1); + } + + if ((dir = opendir(path)) == NULL) { + perror(path); + exit(1); + } + + while ((dent = readdir(dir)) != NULL) { + if (lstat(dent->d_name, &st)) { + perror(dent->d_name); + exit(1); + } + (preformat) ? + do_preformat(&st) : + do_stat(&st, dent->d_name); + } + + closedir(dir); +} + +int main(int argc, char *argv[]) +{ + int i; + struct stat st; + + if (argc == 1) { + do_dir(".", 1); + do_dir(".", 0); + return 0; + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-' && argv[i][1] == 'h') { + fprintf(stdout, "Usage: ls [-h] [FILE ...]\n"); + return 0; + } + + if (lstat(argv[i], &st)) { + perror(argv[i]); + exit(1); + } + + S_ISDIR(st.st_mode) ? + do_dir(argv[i], 1) : + do_preformat(&st); + } + + for (i = 1; i < argc; i++) { + if (lstat(argv[i], &st)) { + perror(argv[i]); + exit(1); + } + + S_ISDIR(st.st_mode) ? + do_dir(argv[i], 0) : + do_stat(&st, argv[i]); + } + + return 0; +} -- 1.6.3.1