// Program to find all process trees with /usr/lib/systemd/systemd --user as // the root process. // // Prints kill -9 commands ordered from the bottom of the tree up to the // systemd --user command. #include #include #include #include #include #include #include #include #include #include #include // Make a multiset of these guys to hold the process tree struct pidtree { unsigned long parent_pid; unsigned long child_pid; }; // Compare multiset elements first on parent then on child (actually // if I include the child in the key, I guess I don't really need a // multiset, but what the heck...) // struct pidcomp { bool operator() (const struct pidtree & a, const struct pidtree & b) const { if (a.parent_pid < b.parent_pid) { return true; } else if (a.parent_pid == b.parent_pid) { return a.child_pid < b.child_pid; } return false; } }; typedef std::multiset treetype; treetype tree; // Recursively descend the process tree, printing kill -9 commands // on the way back up. // void print_tree(unsigned long parent) { struct pidtree p; p.parent_pid = parent; p.child_pid = 0; std::pair start; start = tree.equal_range(p); treetype::iterator it; for (it = start.first; it!=tree.end(); ++it) { struct pidtree elt = *it; if (elt.parent_pid == parent) { print_tree(elt.child_pid); } else { break; } } std::cout << "kill -9 " << parent << std::endl; } int main(int argc, char ** argv) { std::vector daemons; // Read the /proc directory to find all the systemd user daemons struct dirent * dirp; DIR * procdir = opendir("/proc"); if (procdir == NULL) { const char * msg = std::strerror(errno); std::cerr << "Unable to read /proc : " << msg << std::endl; exit(2); } while ((dirp = readdir(procdir)) != NULL) { char * endp; unsigned long int onepid = strtoul(dirp->d_name, &endp, 10); if (*endp == '\0') { // OK, this is an all digit directory and therefore a pid // and not one of the other zillion things under /proc // Read each process' status file to find the parent pid // and build the process tree. std::string statname("/proc/"); statname.append(dirp->d_name); statname.append("/status"); { std::ifstream sf(statname.c_str()); if (sf.is_open()) { std::string buf; unsigned long int oneparent = 0; while (getline(sf, buf)) { const char * bufp = buf.c_str(); if (strncmp(bufp, "PPid:", 5) == 0) { oneparent = strtoul(bufp+5, NULL, 10); break; } } struct pidtree p; p.parent_pid = oneparent; p.child_pid = onepid; tree.insert(p); } else { const char * msg = std::strerror(errno); std::cerr << "Unable to open " << statname << " for reading : " << msg << std::endl; } } // Check each process to see if it is one of the systemd // user daemons and record the pid in the daemons array if it // matches std::string cmdname("/proc/"); cmdname.append(dirp->d_name); cmdname.append("/cmdline"); { std::ifstream cf(cmdname.c_str()); std::string arg; std::string systemd("/usr/lib/systemd/systemd"); std::string user("--user"); bool arg1issystemd = false; bool arg2isuser = false; char c; int argnum = 0; while ((cf.get(c)) && (argnum <= 2)) { if (c == '\0') { ++argnum; switch(argnum) { case 1: if (arg == systemd) { arg1issystemd = true; } else { argnum = 99; } break; case 2: if (arg == user) { arg2isuser = true; } else { argnum = 99; } } arg.clear(); } else { if (argnum == 2) { argnum = 99; } arg.append(1, (char)c); } } if ((argnum == 2) && arg1issystemd && arg2isuser) { daemons.push_back(onepid); } } } } // Go through the daemons array and print the commands to kill all // user daemons and processes running under them for (int i = 0; i < daemons.size(); ++i) { print_tree(daemons[i]); } }