pstree.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // DT PS Tree
  2. //
  3. // Douglas Thrift
  4. //
  5. // $Id$
  6. #include <climits>
  7. #include <cstdio>
  8. #include <iostream>
  9. #include <map>
  10. #include <set>
  11. #include <sstream>
  12. #include <string>
  13. #include <err.h>
  14. #include <fcntl.h>
  15. #include <kvm.h>
  16. #include <paths.h>
  17. #include <pwd.h>
  18. #include <sys/param.h>
  19. #include <sys/sysctl.h>
  20. #include <sys/user.h>
  21. #include "foreach.hpp"
  22. class Proc;
  23. typedef std::map<pid_t, Proc *> PidMap;
  24. typedef std::multimap<std::string, Proc *> NameMap;
  25. enum Sort { Pid, Name };
  26. class Proc
  27. {
  28. kvm_t *kd_;
  29. kinfo_proc *proc_;
  30. Proc *parent_;
  31. PidMap childrenByPid_;
  32. NameMap childrenByName_;
  33. bool highlight_;
  34. public:
  35. Proc() {}
  36. Proc(kvm_t *kd, kinfo_proc *proc) : kd_(kd), proc_(proc) {}
  37. inline std::string name() const { return proc_->ki_comm; }
  38. inline pid_t parent() const { return proc_->ki_ppid; }
  39. inline pid_t pid() const { return proc_->ki_pid; }
  40. void child(Proc *proc)
  41. {
  42. proc->parent_ = this;
  43. childrenByPid_[proc->pid()] = proc;
  44. childrenByName_.insert(NameMap::value_type(proc->name(), proc));
  45. }
  46. void highlight()
  47. {
  48. highlight_ = true;
  49. if (parent_)
  50. parent_->highlight();
  51. }
  52. inline bool root() const { return !parent_; }
  53. void printByPid(const std::string &indent = "") const
  54. {
  55. std::cout << indent << print(indent.size()) << std::endl;
  56. _foreach (const PidMap, child, childrenByPid_)
  57. child->second->printByPid(indent + " ");
  58. }
  59. void printByName(const std::string &indent = "") const
  60. {
  61. std::cout << indent << print(indent.size()) << std::endl;
  62. _foreach (const NameMap, child, childrenByName_)
  63. child->second->printByName(indent + " ");
  64. }
  65. private:
  66. std::string print(std::string::size_type indent) const
  67. {
  68. std::ostringstream print;
  69. if (highlight_)
  70. print << "\033[1m";
  71. print << name();
  72. bool _pid(true), _args(true);
  73. bool change(true && parent_ && uid() != parent_->uid());
  74. bool parens((_pid || change) && !_args);
  75. if (parens)
  76. print << '(';
  77. if (_pid)
  78. {
  79. if (!parens)
  80. print << ',';
  81. print << pid();
  82. }
  83. if (change)
  84. {
  85. if (!parens || _pid)
  86. print << ',';
  87. print << user();
  88. }
  89. if (parens)
  90. print << ')';
  91. if (highlight_)
  92. print << "\033[22m";
  93. if (_args)
  94. print << args(indent + print.str().size());
  95. return print.str();
  96. }
  97. inline bool children() const { return childrenByPid_.size(); }
  98. inline uid_t uid() const { return proc_->ki_ruid; }
  99. std::string user() const
  100. {
  101. passwd *user(getpwuid(uid()));
  102. return user->pw_name;
  103. }
  104. std::string args(std::string::size_type indent) const
  105. {
  106. char **argv(kvm_getargv(kd_, proc_, 0));
  107. std::ostringstream args;
  108. if (argv && *argv)
  109. for (++argv; *argv; ++argv)
  110. {
  111. if (true && (indent += 1 + std::strlen(*argv)) > 75)
  112. {
  113. args << " ...";
  114. break;
  115. }
  116. args << ' ' << *argv;
  117. }
  118. return args.str();
  119. }
  120. };
  121. typedef kinfo_proc *InfoProc;
  122. int main(int argc, char *argv[])
  123. {
  124. char error[_POSIX2_LINE_MAX];
  125. kvm_t *kd(kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, error));
  126. if (!kd)
  127. errx(1, "%s", error);
  128. int count;
  129. InfoProc procs(kvm_getprocs(kd, KERN_PROC_PROC, 0, &count));
  130. if (!procs)
  131. errx(1, "%s", kvm_geterr(kd));
  132. PidMap pids;
  133. _forall (InfoProc, proc, procs, procs + count)
  134. pids[proc->ki_pid] = new Proc(kd, proc);
  135. Sort sort(Name);
  136. _foreach (PidMap, pid, pids)
  137. {
  138. Proc *proc(pid->second);
  139. PidMap::iterator parent(pids.find(proc->parent()));
  140. if (parent != pids.end())
  141. parent->second->child(proc);
  142. }
  143. if (true)
  144. {
  145. pid_t hpid(0);
  146. PidMap::iterator pid(pids.find(hpid ? hpid : getpid()));
  147. if (pid != pids.end())
  148. pid->second->highlight();
  149. }
  150. NameMap names;
  151. _foreach (PidMap, pid, pids)
  152. {
  153. Proc *proc(pid->second);
  154. if (proc->root())
  155. switch (sort)
  156. {
  157. case Pid:
  158. proc->printByPid();
  159. break;
  160. case Name:
  161. names.insert(NameMap::value_type(proc->name(), proc));
  162. }
  163. }
  164. switch (sort)
  165. {
  166. case Name:
  167. _foreach (NameMap, name, names)
  168. name->second->printByName();
  169. default:
  170. break;
  171. }
  172. return 0;
  173. }