#!/usr/bin/c++script struct PARENT { string name; pid_t ppid = 0; int refered = 0; }; struct NAMEREF{ string name; bool refered; bool operator < (const NAMEREF &n) const { return tie(name,refered) < tie(n.name,n.refered); } }; static void print_child(pid_t pid, map &pids, const string &base_prefix) { PARENT &p = pids[pid]; if (pid != 1) cout << '-'; cout << p.name; if (p.refered == 0){ cout << "\n"; }else{ map> names; for (auto &c:pids|views::filter([pid](auto &m){ return m.second.ppid == pid; })){ names[NAMEREF{c.second.name,c.second.refered>0}].push_back(c.first); } int nbspaces = p.name.size(); if (pid != 1) nbspaces++; string new_prefix = base_prefix + string(nbspaces,' ') + " |";; string prefix{"-+"}; for (auto &c:names){ if (!c.first.refered){ auto nb = c.second.size(); if (nb == 1){ cout << prefix << "-" << c.first.name << "\n";; }else{ cout << format ("{}-{}*[{}]\n",prefix,nb,c.first.name); } prefix = new_prefix; }else{ for (auto pid:c.second){ cout << prefix; print_child (pid,pids,new_prefix); prefix = new_prefix; } } } } } #main progdesc ("pstree like utility"); option verbose ('v',"verbose","More output",false,false); map pids; for (auto &&p:user_processes()){ auto &pp = pids[p.pid]; pp.ppid = p.ppid; pp.name = p.name; pid_t parent_id = p.get_parent(); auto &parent = pids[parent_id]; parent.refered++; for (auto &&t:threads(p.pid)){ auto &tt = pids[t.pid]; tt.ppid = t.get_parent(); tt.name = format("{{{}}}",p.name); // We keep the name of the parent pp.refered++; // cerr << format ("thread pid={} ppid={} tgid={} name={} exe={} vmsize={}\n",t.pid,t.ppid,t.tgid,t.name,t.exe,t.vmsize); } // cerr << format ("pid={} ppid={} tgid={} name={} exe={} vmsize={}\n",p.pid,p.ppid,p.tgid,p.name,p.exe,p.vmsize); } #if 0 for (auto &p:pids){ if (p.second.refered == 0){ // end of a line auto *pt = &p.second; while (true){ cout << pt->name << " "; if (pt->ppid == 0) break; pt = &pids[pt->ppid]; } cout << "\n"; } } #endif string prefix; print_child (1,pids,prefix); return 0;