stat.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2020, Shannon Booth <shannon.ml.booth@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/String.h>
  8. #include <LibCore/ArgsParser.h>
  9. #include <LibCore/DateTime.h>
  10. #include <LibCore/System.h>
  11. #include <LibMain/Main.h>
  12. #include <grp.h>
  13. #include <pwd.h>
  14. #include <sys/sysmacros.h>
  15. #include <time.h>
  16. static ErrorOr<int> stat(StringView file, bool should_follow_links)
  17. {
  18. auto st = TRY(should_follow_links ? Core::System::stat(file) : Core::System::lstat(file));
  19. outln(" File: {}", file);
  20. outln(" Inode: {}", st.st_ino);
  21. if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))
  22. outln(" Device: {},{}", major(st.st_rdev), minor(st.st_rdev));
  23. else
  24. outln(" Size: {}", st.st_size);
  25. outln(" Links: {}", st.st_nlink);
  26. outln(" Blocks: {}", st.st_blocks);
  27. out(" UID: {}", st.st_uid);
  28. if (auto* pwd = getpwuid(st.st_uid)) {
  29. out(" ({})", pwd->pw_name);
  30. }
  31. outln("");
  32. out(" GID: {}", st.st_gid);
  33. if (auto* grp = getgrgid(st.st_gid)) {
  34. out(" ({})", grp->gr_name);
  35. }
  36. outln("");
  37. out(" Mode: ({:o}/", st.st_mode);
  38. if (S_ISDIR(st.st_mode))
  39. out("d");
  40. else if (S_ISLNK(st.st_mode))
  41. out("l");
  42. else if (S_ISBLK(st.st_mode))
  43. out("b");
  44. else if (S_ISCHR(st.st_mode))
  45. out("c");
  46. else if (S_ISFIFO(st.st_mode))
  47. out("f");
  48. else if (S_ISSOCK(st.st_mode))
  49. out("s");
  50. else if (S_ISREG(st.st_mode))
  51. out("-");
  52. else
  53. out("?");
  54. out("{:c}{:c}{:c}{:c}{:c}{:c}{:c}{:c}",
  55. st.st_mode & S_IRUSR ? 'r' : '-',
  56. st.st_mode & S_IWUSR ? 'w' : '-',
  57. st.st_mode & S_ISUID ? 's' : (st.st_mode & S_IXUSR ? 'x' : '-'),
  58. st.st_mode & S_IRGRP ? 'r' : '-',
  59. st.st_mode & S_IWGRP ? 'w' : '-',
  60. st.st_mode & S_ISGID ? 's' : (st.st_mode & S_IXGRP ? 'x' : '-'),
  61. st.st_mode & S_IROTH ? 'r' : '-',
  62. st.st_mode & S_IWOTH ? 'w' : '-');
  63. if (st.st_mode & S_ISVTX)
  64. out("t");
  65. else
  66. out("{:c}", st.st_mode & S_IXOTH ? 'x' : '-');
  67. outln(")");
  68. auto print_time = [](time_t t) {
  69. outln("{}", Core::DateTime::from_timestamp(t).to_string());
  70. };
  71. out("Accessed: ");
  72. print_time(st.st_atime);
  73. out("Modified: ");
  74. print_time(st.st_mtime);
  75. out(" Changed: ");
  76. print_time(st.st_ctime);
  77. return 0;
  78. }
  79. ErrorOr<int> serenity_main(Main::Arguments arguments)
  80. {
  81. TRY(Core::System::pledge("stdio rpath", nullptr));
  82. bool should_follow_links = false;
  83. Vector<StringView> files;
  84. auto args_parser = Core::ArgsParser();
  85. args_parser.add_option(should_follow_links, "Follow links to files", nullptr, 'L');
  86. args_parser.add_positional_argument(files, "File(s) to stat", "file", Core::ArgsParser::Required::Yes);
  87. args_parser.parse(arguments);
  88. bool had_error = false;
  89. for (auto& file : files) {
  90. auto r = stat(file, should_follow_links);
  91. if (r.is_error()) {
  92. had_error = true;
  93. warnln("stat: cannot stat '{}': {}", file, strerror(r.error().code()));
  94. }
  95. }
  96. return had_error;
  97. }