dtpstree.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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 <popt.h>
  18. #include <pwd.h>
  19. #include <sys/param.h>
  20. #include <sys/sysctl.h>
  21. #include <sys/user.h>
  22. #include "foreach.hpp"
  23. class Proc;
  24. typedef std::map<pid_t, Proc *> PidMap;
  25. typedef std::multimap<std::string, Proc *> NameMap;
  26. enum Sort { Pid, Name };
  27. class Proc
  28. {
  29. kvm_t *kd_;
  30. kinfo_proc *proc_;
  31. Proc *parent_;
  32. PidMap childrenByPid_;
  33. NameMap childrenByName_;
  34. bool highlight_;
  35. public:
  36. Proc() {}
  37. Proc(kvm_t *kd, kinfo_proc *proc) : kd_(kd), proc_(proc) {}
  38. inline std::string name() const { return proc_->ki_comm; }
  39. inline pid_t parent() const { return proc_->ki_ppid; }
  40. inline pid_t pid() const { return proc_->ki_pid; }
  41. void child(Proc *proc)
  42. {
  43. proc->parent_ = this;
  44. childrenByPid_[proc->pid()] = proc;
  45. childrenByName_.insert(NameMap::value_type(proc->name(), proc));
  46. }
  47. void highlight()
  48. {
  49. highlight_ = true;
  50. if (parent_)
  51. parent_->highlight();
  52. }
  53. inline bool root() const { return !parent_; }
  54. void printByPid(const std::string &indent = "") const
  55. {
  56. std::cout << indent << print(indent.size()) << std::endl;
  57. _foreach (const PidMap, child, childrenByPid_)
  58. child->second->printByPid(indent + " ");
  59. }
  60. void printByName(const std::string &indent = "") const
  61. {
  62. std::cout << indent << print(indent.size()) << std::endl;
  63. _foreach (const NameMap, child, childrenByName_)
  64. child->second->printByName(indent + " ");
  65. }
  66. private:
  67. std::string print(std::string::size_type indent) const
  68. {
  69. std::ostringstream print;
  70. if (highlight_)
  71. print << "\033[1m";
  72. print << name();
  73. bool _pid(true), _args(true);
  74. bool change(true && parent_ && uid() != parent_->uid());
  75. bool parens((_pid || change) && !_args);
  76. if (parens)
  77. print << '(';
  78. if (_pid)
  79. {
  80. if (!parens)
  81. print << ',';
  82. print << pid();
  83. }
  84. if (change)
  85. {
  86. if (!parens || _pid)
  87. print << ',';
  88. print << user();
  89. }
  90. if (parens)
  91. print << ')';
  92. if (highlight_)
  93. print << "\033[22m";
  94. if (_args)
  95. print << args(indent + print.str().size());
  96. return print.str();
  97. }
  98. inline bool children() const { return childrenByPid_.size(); }
  99. inline uid_t uid() const { return proc_->ki_ruid; }
  100. std::string user() const
  101. {
  102. passwd *user(getpwuid(uid()));
  103. return user->pw_name;
  104. }
  105. std::string args(std::string::size_type indent) const
  106. {
  107. char **argv(kvm_getargv(kd_, proc_, 0));
  108. std::ostringstream args;
  109. if (argv && *argv)
  110. for (++argv; *argv; ++argv)
  111. {
  112. if (true && (indent += 1 + std::strlen(*argv)) > 75)
  113. {
  114. args << " ...";
  115. break;
  116. }
  117. args << ' ' << *argv;
  118. }
  119. return args.str();
  120. }
  121. };
  122. typedef kinfo_proc *InfoProc;
  123. int main(int argc, char *argv[])
  124. {
  125. poptOption options[] = {
  126. { "arguments", 'a', POPT_ARG_NONE, NULL, 0, "show command line arguments", NULL },
  127. { "ascii", 'A', POPT_ARG_NONE, NULL, 0, "use ASCII line drawing characters", NULL },
  128. { "compact", 'c', POPT_ARG_NONE, NULL, 0, "don't compact identical subtrees", NULL },
  129. { "highlight-all", 'h', POPT_ARG_NONE, NULL, 0, "highlight current process and its ancestors", NULL },
  130. { "highlight-pid", 'H', POPT_ARG_INT, NULL, 0, "highlight this process and its ancestors", "PID" },
  131. { "vt100", 'G', POPT_ARG_NONE, NULL, 0, "use VT100 line drawing characters", NULL },
  132. { "long", 'l', POPT_ARG_NONE, NULL, 0, "don't truncate long lines", NULL },
  133. { "numeric-sort", 'n', POPT_ARG_NONE, NULL, 0, "sort output by PID", NULL },
  134. { "show-pids", 'p', POPT_ARG_NONE, NULL, 0, "show PIDs; implies -c", NULL },
  135. { "uid-changes", 'u', POPT_ARG_NONE, NULL, 0, "show uid transitions", NULL },
  136. { "unicode", 'U', POPT_ARG_NONE, NULL, 0, "use Unicode line drawing characters", NULL },
  137. { "version", 'V', POPT_ARG_NONE, NULL, 0, "display version information", NULL },
  138. POPT_AUTOHELP
  139. POPT_TABLEEND
  140. };
  141. poptContext context(poptGetContext(NULL, argc, const_cast<const char **>(argv), options, 0));
  142. poptSetOtherOptionHelp(context, "[OPTION...] [PID|USER]");
  143. std::cout << poptGetNextOpt(context) << std::endl;
  144. poptFreeContext(context);
  145. return 0;
  146. char error[_POSIX2_LINE_MAX];
  147. kvm_t *kd(kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, error));
  148. if (!kd)
  149. errx(1, "%s", error);
  150. int count;
  151. InfoProc procs(kvm_getprocs(kd, KERN_PROC_PROC, 0, &count));
  152. if (!procs)
  153. errx(1, "%s", kvm_geterr(kd));
  154. PidMap pids;
  155. _forall (InfoProc, proc, procs, procs + count)
  156. if (proc->ki_ppid != 0 || proc->ki_pid == 1)
  157. pids[proc->ki_pid] = new Proc(kd, proc);
  158. Sort sort(Name);
  159. _foreach (PidMap, pid, pids)
  160. {
  161. Proc *proc(pid->second);
  162. PidMap::iterator parent(pids.find(proc->parent()));
  163. if (parent != pids.end())
  164. parent->second->child(proc);
  165. }
  166. if (true)
  167. {
  168. pid_t hpid(0);
  169. PidMap::iterator pid(pids.find(hpid ? hpid : getpid()));
  170. if (pid != pids.end())
  171. pid->second->highlight();
  172. }
  173. NameMap names;
  174. _foreach (PidMap, pid, pids)
  175. {
  176. Proc *proc(pid->second);
  177. if (proc->root())
  178. switch (sort)
  179. {
  180. case Pid:
  181. proc->printByPid();
  182. break;
  183. case Name:
  184. names.insert(NameMap::value_type(proc->name(), proc));
  185. }
  186. }
  187. switch (sort)
  188. {
  189. case Name:
  190. _foreach (NameMap, name, names)
  191. name->second->printByName();
  192. default:
  193. break;
  194. }
  195. return 0;
  196. }