/* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2020, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include static ErrorOr stat(StringView file, bool should_follow_links) { auto st = TRY(should_follow_links ? Core::System::stat(file) : Core::System::lstat(file)); outln(" File: {}", file); outln(" Inode: {}", st.st_ino); if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) outln(" Device: {},{}", major(st.st_rdev), minor(st.st_rdev)); else outln(" Size: {}", st.st_size); outln(" Links: {}", st.st_nlink); outln(" Blocks: {}", st.st_blocks); out(" UID: {}", st.st_uid); if (auto* pwd = getpwuid(st.st_uid)) { out(" ({})", pwd->pw_name); } outln(""); out(" GID: {}", st.st_gid); if (auto* grp = getgrgid(st.st_gid)) { out(" ({})", grp->gr_name); } outln(""); out(" Mode: ({:o}/", st.st_mode); if (S_ISDIR(st.st_mode)) out("d"); else if (S_ISLNK(st.st_mode)) out("l"); else if (S_ISBLK(st.st_mode)) out("b"); else if (S_ISCHR(st.st_mode)) out("c"); else if (S_ISFIFO(st.st_mode)) out("f"); else if (S_ISSOCK(st.st_mode)) out("s"); else if (S_ISREG(st.st_mode)) out("-"); else out("?"); out("{:c}{:c}{:c}{:c}{:c}{:c}{:c}{:c}", st.st_mode & S_IRUSR ? 'r' : '-', st.st_mode & S_IWUSR ? 'w' : '-', st.st_mode & S_ISUID ? 's' : (st.st_mode & S_IXUSR ? 'x' : '-'), st.st_mode & S_IRGRP ? 'r' : '-', st.st_mode & S_IWGRP ? 'w' : '-', st.st_mode & S_ISGID ? 's' : (st.st_mode & S_IXGRP ? 'x' : '-'), st.st_mode & S_IROTH ? 'r' : '-', st.st_mode & S_IWOTH ? 'w' : '-'); if (st.st_mode & S_ISVTX) out("t"); else out("{:c}", st.st_mode & S_IXOTH ? 'x' : '-'); outln(")"); auto print_time = [](time_t t) { outln("{}", Core::DateTime::from_timestamp(t).to_string()); }; out("Accessed: "); print_time(st.st_atime); out("Modified: "); print_time(st.st_mtime); out(" Changed: "); print_time(st.st_ctime); return 0; } ErrorOr serenity_main(Main::Arguments arguments) { TRY(Core::System::pledge("stdio rpath", nullptr)); bool should_follow_links = false; Vector files; auto args_parser = Core::ArgsParser(); args_parser.add_option(should_follow_links, "Follow links to files", nullptr, 'L'); args_parser.add_positional_argument(files, "File(s) to stat", "file", Core::ArgsParser::Required::Yes); args_parser.parse(arguments); bool had_error = false; for (auto& file : files) { had_error |= stat(file, should_follow_links).is_error(); } return had_error; }