diff --git a/Userland/Utilities/CMakeLists.txt b/Userland/Utilities/CMakeLists.txt index 253b59fcf8..0ebd37fa25 100644 --- a/Userland/Utilities/CMakeLists.txt +++ b/Userland/Utilities/CMakeLists.txt @@ -85,6 +85,7 @@ target_link_libraries(diff LibDiff LibMain) target_link_libraries(dirname LibMain) target_link_libraries(disasm LibX86) target_link_libraries(dmesg LibMain) +target_link_libraries(du LibMain) target_link_libraries(echo LibMain) target_link_libraries(env LibMain) target_link_libraries(expr LibRegex LibMain) diff --git a/Userland/Utilities/du.cpp b/Userland/Utilities/du.cpp index 2840b326b4..995a87d4dc 100644 --- a/Userland/Utilities/du.cpp +++ b/Userland/Utilities/du.cpp @@ -4,8 +4,6 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include #include #include #include @@ -14,8 +12,9 @@ #include #include #include +#include +#include #include -#include #include #include @@ -35,27 +34,24 @@ struct DuOption { Vector excluded_patterns; }; -static int parse_args(int argc, char** argv, Vector& files, DuOption& du_option, int& max_depth); -static int print_space_usage(const String& path, const DuOption& du_option, int max_depth); +static ErrorOr parse_args(Main::Arguments arguments, Vector& files, DuOption& du_option, int& max_depth); +static ErrorOr print_space_usage(const String& path, const DuOption& du_option, int max_depth); -int main(int argc, char** argv) +ErrorOr serenity_main(Main::Arguments arguments) { Vector files; DuOption du_option; int max_depth = INT_MAX; - if (parse_args(argc, argv, files, du_option, max_depth)) - return 1; + TRY(parse_args(arguments, files, du_option, max_depth)); - for (const auto& file : files) { - if (print_space_usage(file, du_option, max_depth)) - return 1; - } + for (const auto& file : files) + TRY(print_space_usage(file, du_option, max_depth)); return 0; } -int parse_args(int argc, char** argv, Vector& files, DuOption& du_option, int& max_depth) +ErrorOr parse_args(Main::Arguments arguments, Vector& files, DuOption& du_option, int& max_depth) { bool summarize = false; const char* pattern = nullptr; @@ -69,12 +65,12 @@ int parse_args(int argc, char** argv, Vector& files, DuOption& du_option "time", 0, "time-type", - [&du_option](const char* s) { - if (!strcmp(s, "mtime") || !strcmp(s, "modification")) + [&du_option](StringView s) { + if (s == "mtime"sv || s == "modification"sv) du_option.time_type = DuOption::TimeType::Modification; - else if (!strcmp(s, "ctime") || !strcmp(s, "status") || !strcmp(s, "use")) + else if (s == "ctime"sv || s == "status"sv || s == "use"sv) du_option.time_type = DuOption::TimeType::Status; - else if (!strcmp(s, "atime") || !strcmp(s, "access")) + else if (s == "atime"sv || s == "access"sv) du_option.time_type = DuOption::TimeType::Access; else return false; @@ -95,7 +91,7 @@ int parse_args(int argc, char** argv, Vector& files, DuOption& du_option args_parser.add_option(pattern, "Exclude files that match pattern", "exclude", 0, "pattern"); args_parser.add_option(exclude_from, "Exclude files that match any pattern in file", "exclude_from", 'X', "file"); args_parser.add_positional_argument(files_to_process, "File to process", "file", Core::ArgsParser::Required::No); - args_parser.parse(argc, argv); + args_parser.parse(arguments); if (summarize) max_depth = 0; @@ -103,9 +99,7 @@ int parse_args(int argc, char** argv, Vector& files, DuOption& du_option if (pattern) du_option.excluded_patterns.append(pattern); if (exclude_from) { - auto file = Core::File::construct(exclude_from); - bool success = file->open(Core::OpenMode::ReadOnly); - VERIFY(success); + auto file = TRY(Core::File::open(exclude_from, Core::OpenMode::ReadOnly)); const auto buff = file->read_all(); if (!buff.is_empty()) { String patterns = String::copy(buff, Chomp); @@ -121,30 +115,23 @@ int parse_args(int argc, char** argv, Vector& files, DuOption& du_option files.append("."); } - return 0; + return {}; } -int print_space_usage(const String& path, const DuOption& du_option, int max_depth) +ErrorOr print_space_usage(const String& path, const DuOption& du_option, int max_depth) { - struct stat path_stat; - if (lstat(path.characters(), &path_stat) < 0) { - perror("lstat"); - return 1; - } - - int ret = 0; - + struct stat path_stat = TRY(Core::System::lstat(path.characters())); if (--max_depth >= 0 && S_ISDIR(path_stat.st_mode)) { auto di = Core::DirIterator(path, Core::DirIterator::SkipParentAndBaseDir); if (di.has_error()) { - warnln("du: cannot read directory '{}': {}", path, di.error_string()); - ret = 1; + outln("du: cannot read directory '{}': {}", path, di.error_string()); + return Error::from_string_literal("An error occurred. See previous error."sv); } + while (di.has_next()) { const auto child_path = di.next_full_path(); if (du_option.all || Core::File::is_directory(child_path)) { - if (print_space_usage(child_path, du_option, max_depth)) - return 1; + TRY(print_space_usage(child_path, du_option, max_depth)); } } } @@ -152,7 +139,7 @@ int print_space_usage(const String& path, const DuOption& du_option, int max_dep const auto basename = LexicalPath::basename(path); for (const auto& pattern : du_option.excluded_patterns) { if (basename.matches(pattern, CaseSensitivity::CaseSensitive)) - return 0; + return {}; } off_t size = path_stat.st_size; @@ -162,7 +149,7 @@ int print_space_usage(const String& path, const DuOption& du_option, int max_dep } if ((du_option.threshold > 0 && size < du_option.threshold) || (du_option.threshold < 0 && size > -du_option.threshold)) - return 0; + return {}; if (du_option.human_readable) { out("{}", human_readable_size(size)); @@ -191,5 +178,5 @@ int print_space_usage(const String& path, const DuOption& du_option, int max_dep outln("\t{}\t{}", formatted_time, path); } - return ret; + return {}; }