1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mosapi.h"
4
5#define BUFSIZE 4096
6
7static const char *type_to_string[] = {
8 [FILE_TYPE_DIRECTORY] = "dir", [FILE_TYPE_REGULAR] = "file", [FILE_TYPE_CHAR_DEVICE] = "char", [FILE_TYPE_BLOCK_DEVICE] = "block",
9 [FILE_TYPE_SYMLINK] = "symlink", [FILE_TYPE_SOCKET] = "socket", [FILE_TYPE_NAMED_PIPE] = "pipe", [FILE_TYPE_UNKNOWN] = "unknown",
10};
11
12int main(int argc, char *argv[])
13{
14 if (argc > 2)
15 {
16 fprintf(stderr, format: "too many arguments\n");
17 fprintf(stderr, format: "usage: %s [path]\n", argv[0]);
18 return 1;
19 }
20
21 // argv[1] may contain the path to list
22 const char *path = argc > 1 ? argv[1] : ".";
23
24 fd_t dirfd = open(path, flags: OPEN_READ | OPEN_DIR);
25 if (dirfd < 0)
26 {
27 fprintf(stderr, format: "failed to open directory '%s'\n", path);
28 return 1;
29 }
30
31 printf(format: "Directory listing of '%s':\n\n", path);
32 printf(format: "%-10s %-15s %-5s %-5s %-15s %-10s %-10s\n", "Inode", "Permission", "UID", "GID", "Size", "Type", "Name");
33
34 char buffer[BUFSIZE];
35 do
36 {
37 size_t sz = syscall_vfs_list_dir(fd: dirfd, buffer, BUFSIZE);
38 if (sz == 0)
39 break;
40
41#define dirent_next(d) ((struct dirent *) ((char *) d + d->d_reclen))
42 for (const struct dirent *dirent = (struct dirent *) buffer; (char *) dirent < buffer + sz; dirent = dirent_next(dirent))
43 {
44 file_stat_t statbuf = { 0 };
45 if (!lstatat(fd: dirfd, path: dirent->d_name, buf: &statbuf))
46 {
47 fprintf(stderr, format: "failed to stat '%s'\n", dirent->d_name);
48 continue;
49 }
50
51 char perm[10] = "---------";
52 file_format_perm(perms: statbuf.perm, buf: perm);
53 char namebuf[256] = { 0 };
54 snprintf(str: namebuf, size: sizeof(namebuf), format: "%s%s", dirent->d_name, dirent->d_type == FILE_TYPE_DIRECTORY ? "/" : "");
55
56 printf(format: "%-10lu %-15s %-5u %-5u %-15zu %-10s %-10s", dirent->d_ino, perm, statbuf.uid, statbuf.gid, statbuf.size, type_to_string[dirent->d_type], namebuf);
57
58 if (dirent->d_type == FILE_TYPE_SYMLINK)
59 {
60 char link[BUFSIZE] = { 0 };
61 size_t sz = syscall_vfs_readlinkat(dirfd, path: dirent->d_name, buf: link, BUFSIZE);
62 bool can_stat = sz > 0 && lstatat(fd: dirfd, path: link, buf: &statbuf);
63 if (can_stat)
64 {
65 link[sz] = '\0';
66 printf(format: " -> %s", link);
67 }
68 else
69 {
70 printf(format: " -> (broken symlink: '%s')", link);
71 }
72 }
73
74 puts(s: "");
75 }
76
77 } while (true);
78
79 syscall_io_close(fd: dirfd);
80
81 return 0;
82}
83