#include #include #include #include #include #include #include #include "status.h" #include "status.m" #include #include #include #include #include class PSTREE_PROC: public ARRAY_OBJ{ friend class PSTREE_PROCS; pid_t pid; pid_t ppid; uid_t uid; char *exe; // Path of the program char *name; // Logical name of the progra, (if it is a script for example) PSTREE_PROC *parent; PSTREE_PROC *first_child; PSTREE_PROC *next; public: int x0,y0,x1,y1; /*~PROTOBEG~ PSTREE_PROC */ public: PSTREE_PROC (pid_t _pid); const char *getexepath (void); const char *getname (void); PSTREE_PROC *getparent (void)const; pid_t getpid (void)const; pid_t getppid (void); uid_t getuid (void); private: void loadinfo (void); public: void menu (void); void print (int x, int &y, DIALOG *dia, int &maxx); void show (void); void showpkg (void); ~PSTREE_PROC (void); /*~PROTOEND~ PSTREE_PROC */ }; PUBLIC PSTREE_PROC::PSTREE_PROC (pid_t _pid) { pid = _pid; ppid = (pid_t)-1; uid = (uid_t)-1; exe = NULL; name = NULL; parent = NULL; first_child = NULL; next = NULL; } PUBLIC PSTREE_PROC::~PSTREE_PROC() { free (exe); } PRIVATE void PSTREE_PROC::loadinfo() { char path[PATH_MAX]; sprintf (path,"/proc/%u/status",pid); FILE *fin = fopen (path,"r"); if (fin != NULL){ char buf[200]; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ if (strncmp(buf,"Uid:",4)==0){ uid = atoi(str_skip(buf+4)); }else if (strncmp(buf,"PPid:",5)==0){ ppid = atoi(str_skip(buf+5)); }else if (strncmp(buf,"Name:",5)==0){ strip_end (buf); name = strdup(str_skip(buf+5)); } } fclose (fin); }else{ fprintf (stderr,"Can't read %s (%s)\n",path,strerror(errno)); } } /* Return the user ID associated with this socket */ PUBLIC uid_t PSTREE_PROC::getuid() { if (uid == (uid_t)-1){ loadinfo(); } return uid; } /* Return the process ID of this process parent */ PUBLIC pid_t PSTREE_PROC::getppid() { if (ppid == (pid_t)-1){ loadinfo(); } return ppid; } PUBLIC pid_t PSTREE_PROC::getpid() const { return pid; } /* Return the path of the program. */ PUBLIC const char *PSTREE_PROC::getexepath() { if (exe == NULL){ char path[PATH_MAX]; sprintf (path,"/proc/%u/exe",pid); char buf[PATH_MAX]; int len = readlink (path,buf,sizeof(buf)-1); if (len > 0){ buf[len] = '\0'; exe = strdup(buf); }else{ exe = strdup(""); } } return exe; } /* Return the logical name of the process */ PUBLIC const char *PSTREE_PROC::getname() { if (name == NULL) loadinfo(); return name; } /* Return the parent of this process. It may return NULL. Note that this call is only useful after the tree is solved. It may also return NULL because the parent died while we were parsing /proc. Not likely, but possible. */ PUBLIC PSTREE_PROC *PSTREE_PROC::getparent() const { return parent; } /* Show information about the process */ PUBLIC void PSTREE_PROC::show() { DIALOG dia; dia.settype (DIATYPE_POPUP); dia.newf_info (MSG_U(F_NAME,"Process name"),name); char pidstr[20]; sprintf (pidstr,"%d",pid); dia.newf_info (MSG_U(F_PID,"Process ID (pid)"),pidstr); int nof = 0; dia.edit ("","",help_nil,nof,MENUBUT_CANCEL); } /* Show information about the package owning that process */ PUBLIC void PSTREE_PROC::showpkg() { PACKAGE_API *pkg_api = package_api_init ("status"); if (pkg_api != NULL){ PACKAGE_VERSION ver; SSTRING pkg; const char *binpath = getexepath(); if (pkg_api->path2pkg (pkg_api,binpath,pkg,ver) == -1){ xconf_error (MSG_U(E_NOPACKAGE ,"There is no package associated with program %s.\n" "It may have been installed without the package manager") ,binpath); }else{ pkg_api->showinfo (pkg_api,pkg.get()); } package_api_end (pkg_api); }else{ xconf_error (MSG_U(E_NOPKGMOD ,"No package management service available\n" "(module managerpm for one)")); } } /* Popup menu to operate on the process */ PUBLIC void PSTREE_PROC::menu() { DIALOG_MENUPOPUP dia; dia.new_menuitem (MSG_U(M_SHOW,"Show"),MSG_U(M_INFO,"process info")); dia.new_menuitem (MSG_R(M_SHOW),MSG_U(M_PKG,"package info")); dia.newf_title ("-","-"); dia.new_menuitem (MSG_U(M_TERM,"Terminate"),MSG_U(M_PROCESS,"the process")); dia.new_menuitem (MSG_U(M_KILL,"Kill"),MSG_R(M_PROCESS)); dia.newf_title (MSG_U(M_SIGNAL,"Signal"),1,MSG_R(M_SIGNAL),MSG_R(M_PROCESS)); int opt_signal = dia.getnb(); for (int i=1; i<32; i++){ static const char *tbsig[]={ MSG_U(I_SIGHANGUP,"hangup HUP"), MSG_U(I_SIGINT,"interrupt INT"), MSG_U(I_SIGQUIT,"quit QUIT"), MSG_U(I_SIGILL,"illegal instruction ILL"), MSG_U(I_SIGTRAP,"trap TRAP"), MSG_U(I_SIGABRT,"abort ABRT"), MSG_U(I_SIGBUS,"bus error BUS"), MSG_U(I_SIGFPE,"floating point exception FPE"), MSG_U(I_SIGKILL,"kill KILL"), MSG_U(I_SIGUSR1,"user defined USR1"), MSG_U(I_SIGSEGV,"segmentation fault SEGV"), MSG_U(I_SIGUSR2,"user defined USR2"), MSG_U(I_SIGPIPE,"pipe error PIPE"), MSG_U(I_SIGALRM,"alarm ALRM"), MSG_U(I_SIGTERM,"terminate TERM"), MSG_U(I_SIGSTKFLT,"stack fault STKFLT"), MSG_U(I_SIGCHLD,"child process death CHLD"), MSG_U(I_SIGCONT,"continue CONT"), MSG_U(I_SIGSTOP,"stop STOP"), MSG_U(I_SIGTSTP,"TSTP"), MSG_U(I_SIGTTIN,"TTIN"), MSG_U(I_SIGTTOU,"TTOU"), MSG_U(I_SIGURG,"urgent URG"), MSG_U(I_SIGXCPU,"XCPU"), MSG_U(I_SIGXFSZ,"XFSZ"), MSG_U(I_SIGVTALRM,"VTALRM"), MSG_U(I_SIGPROG,"PROF"), MSG_U(I_SIGWINCH,"window size changed WINCH"), MSG_U(I_SIGIO,"input/output failure IO"), MSG_U(I_SIGPWR,"power failue PWR"), MSG_U(I_SIGUNUSED,"UNUSED"), }; dia.new_menuitem("",tbsig[i-1]); } int nof = 0; if (dia.editmenu ("",nof)==MENU_OK){ if (perm_rootaccess (MSG_U(P_CTRLPROCESS,"control processes"))){ if (nof == 0){ show(); }else if (nof == 1){ showpkg(); }else if (nof == 3){ kill (getpid(),SIGTERM); }else if (nof == 4){ kill (getpid(),SIGKILL); }else if (nof > opt_signal){ kill (getpid(),nof-opt_signal+1); } } } } class PSTREE_PROCS: public ARRAY{ bool solved; /*~PROTOBEG~ PSTREE_PROCS */ public: PSTREE_PROCS (void); PSTREE_PROC *getitem (int no)const; int load (void); void print (DIALOG *dia, int &maxx, int &maxy); void solve (void); /*~PROTOEND~ PSTREE_PROCS */ }; PUBLIC PSTREE_PROCS::PSTREE_PROCS() { solved = false; } PUBLIC PSTREE_PROC *PSTREE_PROCS::getitem(int no) const { return (PSTREE_PROC*)ARRAY::getitem(no); } /* Scan /proc to load the list of active process */ PUBLIC int PSTREE_PROCS::load() { PSTREE_PROCS *p; solved = false; glocal.p = this; remove_all(); ("/proc"); return false; if (isdigit(basename[0])){ glocal.p->add (new PSTREE_PROC(atoi(basename))); } return getnb(); } #if 0 /* Help function to sort process so a pstree like disposition is easily done */ static int cmp_pstree (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2) { PSTREE_PROC *p1 = (PSTREE_PROC*)o1; PSTREE_PROC *p2 = (PSTREE_PROC*)o2; int ret = 0; pid_t pid1 = p1->getpid(); pid_t ppid1 = p1->getppid(); pid_t pid2 = p2->getpid(); pid_t ppid2 = p2->getppid(); if (pid1 == ppid2){ ret = -1; }else if (ppid1 == pid2){ ret = 1; }else{ ret = strcmp(p1->getexepath(),p2->getexepath()); } return ret; } #endif PUBLIC void PSTREE_PROCS::solve() { int n = getnb(); for (int i=0; igetppid(); for (int j=0; jgetpid()){ p->parent = pp; p->next = pp->first_child; pp->first_child = p; break; } } } solved = true; } static int cmp_name (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2) { PSTREE_PROC *p1 = (PSTREE_PROC*)o1; PSTREE_PROC *p2 = (PSTREE_PROC*)o2; return strcmp(p1->getname(),p2->getname()); } PUBLIC void PSTREE_PROC::print ( int x, int &y, DIALOG *dia, int &maxx) { const int stepx = 10; const int stepy = 15; const int stepy_2 = stepy/2; //fprintf (stderr,"%*s%s[%d]\n",level*4,"",getname(),getpid()); if (dia != NULL){ dia->gui_passthrough (P_Drawline,"%d %d %d %d",x,y+stepy_2,x+stepx,y+stepy_2); } x0 = x + stepx + 5; y0 = y; x1 = x0 + strlen(getname()) * 10; y1 = y + stepy; if (dia != NULL){ dia->gui_passthrough (P_Drawtext,"%d %d %s",x0,y,getname()); } PSTREE_PROCS tbb; tbb.neverdelete(); PSTREE_PROC *pt = first_child; while (pt != NULL){ // fprintf (stderr,"Add[%d] %d %d :%s:\n",nbadd++,pt->getppid(),pt->getpid(),pt->getname()); tbb.add (pt); pt = pt->next; } tbb.sort(cmp_name); x += stepx + strlen(getname())*10; if (x > maxx) maxx = x; int starty = y; for (int i=0; iprint (x,y,dia,maxx); } if (dia != NULL && tbb.getnb() > 0){ int y_2 = starty + stepy_2; dia->gui_passthrough (P_Drawline,"%d %d %d %d",x-5,y_2 ,x,y_2); if (tbb.getnb() > 1){ dia->gui_passthrough (P_Drawline,"%d %d %d %d",x,y_2 ,x,y+stepy_2); } } } PUBLIC void PSTREE_PROCS::print(DIALOG *dia, int &maxx, int &maxy) { maxx = 0; maxy = 0; if (!solved) solve(); for (int i=0; igetpid()==1){ p->print (5,maxy,dia,maxx); maxy += 15; break; } } } void pstree_edit() { PSTREE_PROCS procs; DIALOG dia; PRIVATE_MESSAGE input; procs.load(); int maxx,maxy; procs.print(NULL,maxx,maxy); dia.gui_passthrough(P_Form,"tree $doch=%d docw=%d vtrigger=300 htrigger=400",maxx,maxy); dia.new_inputgrid (0,0,1,1,maxx,maxy,input); const char *penwhite = guiid_setpen ("white",0,GPEN_STYLE_SOLID); const char *brushwhite = guiid_setbrush ("white"); const char *dcwhite = guiid_setdc (NULL,penwhite,brushwhite); dia.gui_passthrough (P_Clear,"$dc=%s\n",dcwhite); procs.print(&dia,maxx,maxy); dia.gui_end(); int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_PROCESSES ,"Process tree") ,"",help_nil,nof,MENUBUT_CANCEL); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_MESSAGE){ if (dialog_testmessage(input)){ UISTATE st; diajava_lastmousestate (st); for (int i=0; i= p->x0 && st.y >= p->y0 && st.x < p->x1 && st.y < p->y1){ // fprintf (stderr,"Click %s\n",p->getname()); p->menu(); break; } } } } } }