├── .gitignore ├── .travis.yml ├── Cask ├── README.md ├── helm-proc.el └── travis-ci.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /.cask/ 2 | *.elc 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: emacs-lisp 2 | 3 | before_install: 4 | - sudo mkdir /usr/local/evm 5 | - sudo chown travis:travis /usr/local/evm 6 | 7 | - curl -fsSkL https://raw.github.com/rejeep/evm/master/go | bash 8 | - export PATH="/home/travis/.evm/bin:$PATH" 9 | - evm install $EVM_EMACS --use 10 | 11 | - curl -fsSkL https://raw.github.com/cask/cask/master/go | python 12 | - export PATH="/home/travis/.cask/bin:$PATH" 13 | - cask 14 | 15 | env: 16 | - EVM_EMACS=emacs-24.5-bin 17 | 18 | script: 19 | - ./travis-ci.sh 20 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source melpa) 2 | 3 | (depends-on "helm") 4 | (files "helm-proc.el") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | helm-proc 2 | ========= 3 | 4 | Helm source and actions to manage processes. 5 | 6 | Some example actions: 7 | 8 | * Send TERM/KILL to process 9 | * Polite KILL: Send TERM, wait and then KILL 10 | * Open /proc dir for process 11 | * Attach strace 12 | -------------------------------------------------------------------------------- /helm-proc.el: -------------------------------------------------------------------------------- 1 | ;;; helm-proc.el --- Helm interface for managing system processes 2 | 3 | ;; Copyright (C) 2014 Markus Hauck 4 | 5 | ;; Author: Markus Hauck 6 | ;; Maintainer: Markus Hauck 7 | ;; Keywords: helm 8 | ;; Version: 0.0.4 9 | ;; Package-requires: ((helm "1.6.0") (cl-lib "0.5")) 10 | 11 | ;; This program is free software; you can redistribute it and/or modify 12 | ;; it under the terms of the GNU General Public License as published by 13 | ;; the Free Software Foundation, either version 3 of the License, or 14 | ;; (at your option) any later version. 15 | ;; 16 | ;; This program is distributed in the hope that it will be useful, 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | ;; GNU General Public License for more details. 20 | ;; 21 | ;; You should have received a copy of the GNU General Public License 22 | ;; along with this program. If not, see . 23 | 24 | ;;; Commentary: 25 | ;; 26 | ;; This package provides a helm source `helm-source-proc' and a 27 | ;; configured helm `helm-proc'. It is meant to be used to manage 28 | ;; emacs-external unix processes. 29 | ;; 30 | ;; With `helm-proc' a helm session is launched and you can perform 31 | ;; various helm actions on processes like sending signals, changing to 32 | ;; the corresponding /proc dir, attach strace... 33 | ;; 34 | ;; Example: 35 | ;; 36 | ;; Call `helm-proc' and: 37 | ;; type 'firefox' 38 | ;; => lists all processes named firefox or with firefox in args 39 | ;; press RET to send TERM signal 40 | ;; or 41 | ;; press TAB for list of possible actions 42 | 43 | ;;; Code: 44 | (require 'helm) 45 | (require 'helm-utils) 46 | (require 'helm-help) 47 | (require 'proced) 48 | (require 'cl-lib) 49 | (require 'thingatpt) 50 | (require 'gdb-mi) 51 | 52 | (defgroup helm-proc nil 53 | "Manage system processes with helm." 54 | :group 'helm) 55 | 56 | (defcustom helm-proc-polite-delay 10 57 | "Number of seconds to wait when politely killing a process." 58 | :type 'number 59 | :group 'helm-proc) 60 | 61 | (defcustom helm-proc-retrieve-pid-function 'helm-proc-system-pgrep 62 | "Function to retrieve a list of pids matching a pattern given as argument." 63 | :group 'helm-proc 64 | :type '(choice 65 | (function-item :tag "pgrep" :value helm-proc-system-pgrep) 66 | (function :tag "Custom function"))) 67 | 68 | (defcustom helm-proc-strace-buffer-name "*helm-proc-strace*" 69 | "Used as the buffer name for the output of strace when used by helm-proc." 70 | :type 'string 71 | :group 'helm-proc) 72 | 73 | (defcustom helm-proc-strace-process-name "helm-proc-strace" 74 | "Used as the name for the strace process started by helm-proc." 75 | :type 'string 76 | :group 'helm-proc) 77 | 78 | (defcustom helm-proc-lsof-buffer-name "*helm-proc-lsof*" 79 | "Name of the buffer used for the output of lsof used by helm-proc." 80 | :type 'string 81 | :group 'helm-proc) 82 | 83 | (defcustom helm-proc-lsof-process-name "helm-proc-lsof" 84 | "Process name when executing lsof from helm-proc." 85 | :type 'string 86 | :group 'helm-proc) 87 | 88 | (defcustom helm-proc-strace-executable "strace" 89 | "Name of the strace executable." 90 | :type 'string 91 | :group 'helm-proc 92 | :type '(choice 93 | (string :tag "strace" :value "strace") 94 | (string :tag "ltrace" :value "ltrace") 95 | (string :tag "Custom executable"))) 96 | 97 | (defcustom helm-proc-strace-seconds 10 98 | "Number of seconds to collect strace data before process is killed." 99 | :type 'number 100 | :group 'helm-proc) 101 | 102 | (defcustom helm-proc-formatting-function 'helm-proc-format-candidate-for-display 103 | "Function used to display candidates. 104 | 105 | It takes one argument, the pid and returns (DISPLAY . pid) where 106 | DISPLAY can be any string." 107 | :group 'helm-proc 108 | :type '(choice 109 | (function-item :tag "builtin-multiline" :value helm-proc-format-candidate-for-display) 110 | (function :tag "Custom function"))) 111 | 112 | (defun helm-proc-candidates () 113 | "Generate the candidate list for the current `helm-pattern'. 114 | Then format elements for display in helm." 115 | (cl-loop for candidate in (helm-proc-search helm-pattern) 116 | when (assoc-default 'comm (cdar (proced-process-attributes `(,candidate)))) 117 | collect (funcall helm-proc-formatting-function candidate))) 118 | 119 | (defun helm-proc-system-pgrep (pattern) 120 | "Use external pgrep command to retrieve list of pids matching PATTERN." 121 | (let ((to-number (string-to-number pattern))) 122 | (append nil 123 | (if (not (equal 0 to-number)) `(,to-number) nil) 124 | (cl-loop for result in (split-string 125 | (shell-command-to-string 126 | (format "pgrep -f %s" pattern)) "\n") 127 | unless (string= "" result) 128 | collect (string-to-number result))))) 129 | 130 | (defun helm-proc-search (pattern) 131 | "Call `helm-proc-retrieve-pid-function' with PATTERN. 132 | Return a list of pids as result." 133 | (funcall helm-proc-retrieve-pid-function pattern)) 134 | 135 | (defun helm-proc--resident-set-size (pid) 136 | "Determine the resident set size of a process given by PID." 137 | (with-temp-buffer 138 | (insert-file-contents-literally (format "/proc/%s/status" pid)) 139 | (goto-char (point-min)) 140 | (search-forward "VmRSS:" nil t) 141 | (forward-word) 142 | (file-size-human-readable 143 | (* (string-to-number (word-at-point)) 1024) 144 | 'iec))) 145 | 146 | (defun helm-proc-format-candidate-for-display (pid) 147 | "Format PID for display in helm." 148 | (if (not pid) nil 149 | (let* ((attr-alist 150 | (cdar (proced-process-attributes `(,pid)))) 151 | (command (assoc-default 'comm attr-alist)) 152 | (args (assoc-default 'args attr-alist)) 153 | (time (proced-format-time (assoc-default 'time attr-alist))) 154 | (state (assoc-default 'state attr-alist)) 155 | (nice (assoc-default 'nice attr-alist)) 156 | (user (assoc-default 'user attr-alist)) 157 | (mem (helm-proc--resident-set-size pid)) 158 | (display (format 159 | "%s %s\nTime: %s | State: %s | Nice: %s | User: %s | Mem: %s\nArgs: %s" 160 | pid 161 | command 162 | time 163 | state 164 | nice 165 | user 166 | mem 167 | args))) 168 | (cons display pid)))) 169 | 170 | (defun helm-proc-action-copy-pid (pid) 171 | "Copy PID." 172 | (kill-new (format "%s" pid))) 173 | 174 | (defun helm-proc-action-term (pid) 175 | "Send TERM to PID." 176 | (signal-process pid 'TERM)) 177 | 178 | (defun helm-proc-action-kill (pid) 179 | "Send KILL to PID." 180 | (signal-process pid 'KILL)) 181 | 182 | (defun helm-proc-action-stop (pid) 183 | "Send STOP to PID to stop the process." 184 | (signal-process pid 'STOP)) 185 | 186 | (defun helm-proc-action-continue (pid) 187 | "Send CONT to PID to continue the process if stopped." 188 | (signal-process pid 'CONT)) 189 | 190 | (defun helm-proc-process-alive-p (pid) 191 | "If process with PID is alive return t else nil." 192 | (file-readable-p (format "/proc/%s/" pid))) 193 | 194 | (defun helm-proc-action-polite-kill (pid) 195 | "Send TERM to PID, wait for `helm-proc-polite-delay' seconds, then send KILL." 196 | (helm-proc-action-term pid) 197 | (run-with-timer helm-proc-polite-delay nil 198 | (lambda (pid) 199 | (unless (not (helm-proc-process-alive-p pid)) 200 | (helm-proc-action-kill pid) 201 | (message (format "Sent KILL to %s" pid)) 202 | (if helm-alive-p (helm-update)))) 203 | pid)) 204 | 205 | (defun helm-proc-action-find-dir (pid) 206 | "Open the /proc dir for PID." 207 | (find-file (format "/proc/%s/" pid))) 208 | 209 | (defun helm-proc-action-timed-strace (pid) 210 | "Attach strace to PID, collect output `helm-proc-strace-seconds'." 211 | (if (get-buffer helm-proc-strace-buffer-name) 212 | (kill-buffer helm-proc-strace-buffer-name)) 213 | (and (start-process-shell-command 214 | helm-proc-strace-process-name 215 | helm-proc-strace-buffer-name 216 | (concat "echo " (shell-quote-argument (read-passwd "Sudo Password: ")) 217 | (format " | sudo -S strace -p %s" pid))) 218 | (switch-to-buffer helm-proc-strace-buffer-name) 219 | (run-with-timer helm-proc-strace-seconds nil 220 | (lambda () 221 | (kill-process 222 | (get-process helm-proc-strace-process-name)))))) 223 | 224 | (defun helm-proc-action-lsof (pid) 225 | "List all files opened by process with PID." 226 | (if (get-buffer helm-proc-lsof-buffer-name) 227 | (kill-buffer helm-proc-lsof-buffer-name)) 228 | (start-process-shell-command 229 | helm-proc-lsof-process-name 230 | helm-proc-lsof-buffer-name 231 | (format "lsof -p %s" pid)) 232 | (switch-to-buffer helm-proc-lsof-buffer-name) 233 | (setq buffer-read-only t)) 234 | 235 | (defun helm-proc-action-gdb (pid) 236 | "Attach gdb to PID." 237 | (add-to-list 238 | 'gud-gdb-history 239 | (format 240 | "gdb -i=mi %s %s" 241 | (file-truename 242 | (format "/proc/%s/exe" pid)) 243 | pid)) 244 | (call-interactively 'gdb)) 245 | 246 | (defun helm-proc-run-kill () 247 | "Execute kill action from `helm-source-proc'." 248 | (interactive) 249 | (with-helm-alive-p 250 | (helm-exit-and-execute-action 'helm-proc-action-kill))) 251 | 252 | (defun helm-proc-run-polite () 253 | "Execute polite kill action from `helm-source-proc'." 254 | (interactive) 255 | (with-helm-alive-p 256 | (helm-exit-and-execute-action 'helm-proc-action-polite-kill))) 257 | 258 | (defun helm-proc-run-stop () 259 | "Execute stop action from `helm-source-proc'." 260 | (interactive) 261 | (with-helm-alive-p 262 | (helm-exit-and-execute-action 'helm-proc-action-stop))) 263 | 264 | (defun helm-proc-run-continue () 265 | "Execute continue action from `helm-source-proc'." 266 | (interactive) 267 | (with-helm-alive-p 268 | (helm-exit-and-execute-action 'helm-proc-action-continue))) 269 | 270 | (defun helm-proc-run-term () 271 | "Execute term action from `helm-source-proc'." 272 | (interactive) 273 | (with-helm-alive-p 274 | (helm-exit-and-execute-action 'helm-proc-action-term))) 275 | 276 | (defun helm-proc-action-polite-kill-and-update (candidate) 277 | "Run `helm-proc-action-polite-kill' on CANDIDATE and call `helm-update'." 278 | (helm-proc-action-polite-kill candidate) 279 | (helm-update)) 280 | 281 | (defvar helm-proc-map 282 | (let ((map (make-sparse-keymap))) 283 | (set-keymap-parent map helm-map) 284 | (define-key map (kbd "C-c t") 'helm-proc-run-term) 285 | (define-key map (kbd "C-c k") 'helm-proc-run-kill) 286 | (define-key map (kbd "C-c p") 'helm-proc-run-polite) 287 | (define-key map (kbd "C-c s") 'helm-proc-run-stop) 288 | (define-key map (kbd "C-c c") 'helm-proc-run-continue) 289 | (define-key map (kbd "C-c ?") 'helm-proc-help) 290 | map)) 291 | 292 | (defvar helm-proc-help-message 293 | "== Helm proc ==\ 294 | \nSpecific commands for Helm proc: 295 | \\\ 296 | \\[helm-proc-help]\t\tShow this help. 297 | \\[helm-proc-run-term]\t\tSend the TERM signal. 298 | \\[helm-proc-run-kill]\t\tSend the KILL signal. 299 | \\[helm-proc-run-polite]\t\tSend TERM to PID, wait for `helm-proc-polite-delay' seconds, then send KILL. 300 | \\[helm-proc-run-stop]\t\tSend the STOP signal. 301 | \\[helm-proc-run-continue]\t\tSend the CONT signal. 302 | \n== Helm Map == 303 | \\{helm-map}") 304 | 305 | (defun helm-proc-help () 306 | "Display help for `helm-proc'." 307 | (interactive) 308 | (let ((helm-help-message helm-proc-help-message)) 309 | (helm-help))) 310 | 311 | (defvar helm-proc-mode-line-string '("Ps" "\ 312 | \\\ 313 | \\[helm-proc-help]:Help|\ 314 | \\[helm-proc-run-term]:TERM \ 315 | \\[helm-proc-run-polite]:Polite KILL|\ 316 | \\[helm-proc-run-kill]:KILL|\ 317 | \\[helm-proc-run-stop]:STOP|\ 318 | \\[helm-proc-run-continue]:CONT") 319 | "Help string displayed in mode-line in `helm-proc'.") 320 | 321 | (defvar helm-source-proc 322 | `((name . "Processes") 323 | (volatile) 324 | (requires-pattern . 2) 325 | (multiline) 326 | (match . ((lambda (x) t))) 327 | (action . (("Send TERM (C-c t)" . helm-proc-action-term) 328 | ("Copy the pid" . helm-proc-action-copy-pid) 329 | ("Polite KILL (TERM -> KILL) (C-c p)" . helm-proc-action-polite-kill) 330 | ("Just KILL (C-c k)" . helm-proc-action-kill) 331 | ("Stop process (C-c s)" . helm-proc-action-stop) 332 | ("Continue if stopped (C-c c)" . helm-proc-action-continue) 333 | ("Open corresponding /proc dir" . helm-proc-action-find-dir) 334 | ("Call strace to attach with time limit" . helm-proc-action-timed-strace) 335 | ("List opened files (lsof)" . helm-proc-action-lsof) 336 | ("Attach gdb to process" . helm-proc-action-gdb))) 337 | (keymap . ,helm-proc-map) 338 | (persistent-action . helm-proc-action-polite-kill-and-update) 339 | (persistent-help . "Politely kill process") 340 | (candidates . helm-proc-candidates) 341 | (mode-line . helm-proc-mode-line-string))) 342 | 343 | ;;;###autoload 344 | (defun helm-proc () 345 | "Preconfigured helm for processes." 346 | (interactive) 347 | (helm :sources '(helm-source-proc))) 348 | 349 | (provide 'helm-proc) 350 | ;;; helm-proc.el ends here 351 | -------------------------------------------------------------------------------- /travis-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PATH="$HOME/.cask/bin:$PATH" 4 | RESULT="$(cask exec cask build 2>&1)" 5 | 6 | echo "$RESULT" 7 | 8 | ! echo "$RESULT" | grep -i -e warning -e error 9 | --------------------------------------------------------------------------------