ps.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/QuickSort.h>
  7. #include <LibCore/ArgsParser.h>
  8. #include <LibCore/ProcessStatisticsReader.h>
  9. #include <stdio.h>
  10. #include <unistd.h>
  11. int main(int argc, char** argv)
  12. {
  13. if (pledge("stdio rpath tty", nullptr) < 0) {
  14. perror("pledge");
  15. return 1;
  16. }
  17. String this_tty = ttyname(STDIN_FILENO);
  18. if (pledge("stdio rpath", nullptr) < 0) {
  19. perror("pledge");
  20. return 1;
  21. }
  22. if (unveil("/proc/all", "r") < 0) {
  23. perror("unveil");
  24. return 1;
  25. }
  26. if (unveil("/etc/passwd", "r") < 0) {
  27. perror("unveil");
  28. return 1;
  29. }
  30. unveil(nullptr, nullptr);
  31. enum class Alignment {
  32. Left,
  33. Right,
  34. };
  35. struct Column {
  36. String title;
  37. Alignment alignment { Alignment::Left };
  38. int width { 0 };
  39. String buffer;
  40. };
  41. bool every_process_flag = false;
  42. bool full_format_flag = false;
  43. Core::ArgsParser args_parser;
  44. args_parser.add_option(every_process_flag, "Show every process", nullptr, 'e');
  45. args_parser.add_option(full_format_flag, "Full format", nullptr, 'f');
  46. args_parser.parse(argc, argv);
  47. Vector<Column> columns;
  48. int uid_column = -1;
  49. int pid_column = -1;
  50. int ppid_column = -1;
  51. int state_column = -1;
  52. int tty_column = -1;
  53. int cmd_column = -1;
  54. auto add_column = [&](auto title, auto alignment) {
  55. columns.append({ title, alignment, 0, {} });
  56. return columns.size() - 1;
  57. };
  58. if (full_format_flag) {
  59. uid_column = add_column("UID", Alignment::Left);
  60. pid_column = add_column("PID", Alignment::Right);
  61. ppid_column = add_column("PPID", Alignment::Right);
  62. state_column = add_column("STATE", Alignment::Left);
  63. tty_column = add_column("TTY", Alignment::Left);
  64. cmd_column = add_column("CMD", Alignment::Left);
  65. } else {
  66. pid_column = add_column("PID", Alignment::Right);
  67. tty_column = add_column("TTY", Alignment::Left);
  68. cmd_column = add_column("CMD", Alignment::Left);
  69. }
  70. auto all_processes = Core::ProcessStatisticsReader::get_all();
  71. if (!all_processes.has_value())
  72. return 1;
  73. auto& processes = all_processes.value().processes;
  74. quick_sort(processes, [](auto& a, auto& b) { return a.pid < b.pid; });
  75. Vector<Vector<String>> rows;
  76. rows.ensure_capacity(1 + processes.size());
  77. Vector<String> header;
  78. header.ensure_capacity(columns.size());
  79. for (auto& column : columns)
  80. header.append(column.title);
  81. rows.append(move(header));
  82. for (auto const& process : processes) {
  83. auto tty = process.tty;
  84. if (!every_process_flag && tty != this_tty)
  85. continue;
  86. if (tty.starts_with("/dev/"))
  87. tty = tty.characters() + 5;
  88. else
  89. tty = "n/a";
  90. auto* state = process.threads.is_empty() ? "Zombie" : process.threads.first().state.characters();
  91. Vector<String> row;
  92. row.resize(columns.size());
  93. if (uid_column != -1)
  94. row[uid_column] = process.username;
  95. if (pid_column != -1)
  96. row[pid_column] = String::number(process.pid);
  97. if (ppid_column != -1)
  98. row[ppid_column] = String::number(process.ppid);
  99. if (tty_column != -1)
  100. row[tty_column] = tty;
  101. if (state_column != -1)
  102. row[state_column] = state;
  103. if (cmd_column != -1)
  104. row[cmd_column] = process.name;
  105. rows.append(move(row));
  106. }
  107. for (size_t i = 0; i < columns.size(); i++) {
  108. auto& column = columns[i];
  109. for (auto& row : rows)
  110. column.width = max(column.width, static_cast<int>(row[i].length()));
  111. }
  112. for (auto& row : rows) {
  113. for (size_t i = 0; i < columns.size(); i++) {
  114. auto& column = columns[i];
  115. auto& cell_text = row[i];
  116. if (!column.width) {
  117. out("{}", cell_text);
  118. continue;
  119. }
  120. if (column.alignment == Alignment::Right)
  121. out("{1:>{0}} ", column.width, cell_text);
  122. else
  123. out("{1:{0}} ", column.width, cell_text);
  124. if (i != columns.size() - 1)
  125. out(" ");
  126. }
  127. outln();
  128. }
  129. return 0;
  130. }