Serenity Operating System
at master 91 lines 3.3 kB view raw
1/* 2 * Copyright (c) 2021, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/DeprecatedString.h> 8#include <LibCore/ArgsParser.h> 9#include <LibCore/System.h> 10#include <LibMain/Main.h> 11#include <bits/posix1_lim.h> 12#include <unistd.h> 13 14ErrorOr<int> serenity_main(Main::Arguments arguments) 15{ 16 TRY(Core::System::pledge("stdio rpath")); 17 bool fail = false; 18 static bool flag_most_posix = false; 19 static bool flag_portability = false; 20 static bool flag_empty_name_and_leading_dash = false; 21 Vector<DeprecatedString> paths; 22 23 Core::ArgsParser args_parser; 24 args_parser.add_option(flag_most_posix, "Check for most POSIX systems", nullptr, 'p'); 25 args_parser.add_option(flag_empty_name_and_leading_dash, "Check for empty names and leading dash", nullptr, 'P'); 26 args_parser.add_option(flag_portability, "Check portability (equivalent to -p and -P)", "portability", '\0'); 27 args_parser.add_positional_argument(paths, "Path to check", "path", Core::ArgsParser::Required::Yes); 28 args_parser.parse(arguments); 29 30 if (flag_portability) { 31 flag_most_posix = true; 32 flag_empty_name_and_leading_dash = true; 33 } 34 35 for (auto& path : paths) { 36 unsigned long path_max = flag_most_posix ? _POSIX_PATH_MAX : pathconf(path.characters(), _PC_PATH_MAX); 37 unsigned long name_max = flag_most_posix ? _POSIX_NAME_MAX : pathconf(path.characters(), _PC_NAME_MAX); 38 39 if (path.length() > path_max) { 40 warnln("Limit {} exceeded by length {} of filename '{}'", path_max, path.length(), path); 41 fail = true; 42 continue; 43 } 44 45 if (flag_most_posix) { 46 // POSIX portable filename character set (a-z A-Z 0-9 . _ -) 47 for (long unsigned i = 0; i < path.length(); ++i) { 48 auto c = path[i]; 49 if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != '/' && c != '.' && c != '-' && c != '_') { 50 warnln("Non-portable character '{}' in filename '{}'", path[i], path); 51 fail = true; 52 continue; 53 } 54 } 55 } else { 56 struct stat st; 57 if (lstat(path.characters(), &st) < 0) { 58 if (errno != ENOENT) { 59 warnln("Directory is not searchable '{}'", path); 60 fail = true; 61 continue; 62 } 63 } 64 } 65 66 if (flag_empty_name_and_leading_dash) { 67 if (path.is_empty()) { 68 warnln("Empty filename"); 69 fail = true; 70 continue; 71 } 72 } 73 74 for (auto& component : path.split('/')) { 75 if (flag_empty_name_and_leading_dash) { 76 if (component.starts_with('-')) { 77 warnln("Leading '-' in a component of filename '{}'", path); 78 fail = true; 79 break; 80 } 81 } 82 if (component.length() > name_max) { 83 warnln("Limit {} exceeded by length {} of filename component '{}'", name_max, component.length(), component.characters()); 84 fail = true; 85 break; 86 } 87 } 88 } 89 90 return fail; 91}