make getpeername() return the original socket address which before it was intercepted
[hband-tools.git] / user-tools / jobsel
blob10a01e7d1d845c3f8b3b1f8f07ab4cd9b035841d
1 #!/usr/bin/env perl
2 ###################
4 no if ($] >= 5.018), 'warnings' => 'experimental::smartmatch';
5 $me=$0;
6 $0="jobsel";
7 #sub helpy { $pos = tell DATA; print STDERR <DATA>; seek DATA,$pos,0 }
8 sub helpy { system("pod2text", $me, "/dev/stderr") }
9 exit helpy if $ARGV[0] eq '--help';
10 use Term::ReadKey;
11 ReadMode 4;
12 sub bye { print STDOUT "export JOBSEL_DISPLAY_MODE=$dispmode"; exit ReadMode 0 }
13 sub getkey { while(not defined ($k = ReadKey(-1))){} return $k }
14 $SIG{INT}=$SIG{STOP}=$SIG{STOP}=$SIG{TSTP}=$SIG{QUIT}='bye';
15 $dispmode = $ENV{JOBSEL_DISPLAY_MODE};
16 $dispmode = "x" unless $dispmode ~~ ["c", "x", "l"];
17 $dispmode = "l" unless $ARGV[1];
19 while(1){
20 @o=@x=();
21 for(split/[\r\n]+/,$ARGV[0]){
22 ($j,$p)=/(\d+)\]\S?\s+(\d+)/;
23 if ( open(P,"/proc/$p/stat") and ($c,$s)=(<P>=~/\s\((.+?)\)\s+(\S+)/) ) {
24 close P;
25 push @o,[$j,$c,$p,$s]; # job number, command, pid, state
27 s/(\S+\s+){3}//;
28 push @x,sprintf "[%d] %5d %s %s",$j,$p,$s,$_;
31 bye unless @o;
33 $in=$#o if $in>$#o;
34 $pos = tell STDERR;
36 print STDERR "\033[s";
37 if($dispmode =~ /[xc]/)
39 print STDERR "\033[1;1H";
40 if($dispmode eq "x") {
41 for(0..$#o) {
42 printf STDERR "%s%s\033[m\n",($_==$in?"\033[44;1;36m":"\033[1;36m"),$x[$_];
45 else {
46 print STDERR "\033[1;36mjobs: ";
47 for(0..$#o) {
48 printf STDERR "%s[%%%s %s(%s) %s]\033[m ",($_==$in?"\033[44;1;36m":"\033[1;36m"),@{$o[$_]};
52 else {
53 print STDERR "\033[6n"; { local $/="R"; ($rn) = (<STDIN>=~/\[(\d+);/); }
54 printf STDERR "\033[%d;1H", $rn-1;
55 for(0..$#o) {
56 printf STDERR "%s[%%%s %s(%s) %s]\033[m ",($_==$in?"\033[1;36m":"\033[36m"),@{$o[$_]};
59 print STDERR "\033[u";
61 $k=getkey;
62 if($k eq chr(27)) {
63 $k=getkey;
64 if($k eq '[') {
65 $k=getkey;
66 if($k =~ /[DA]/) { # arrow left/up
67 $in-- if $in > 0
69 elsif($k =~ /[CB]/) { # arrow right/down
70 $in++ if $in < $#o
72 elsif($k =~ /[H5]/) { # home/pg up
73 $in=0
75 elsif($k =~ /[F6]/) { # end/pg down
76 $in=$#o
78 elsif($k eq chr(27)) { bye }
80 elsif($k eq chr(27)) { bye }
82 elsif($k =~ /[ts ]/i) {
83 kill ${$o[$in]}[3] eq 'T' ? 18 : 20, ${$o[$in]}[2]; # CONT,TSTP
85 elsif($k =~ /k/i) {
86 kill 9, ${$o[$in]}[2]; # KILL
88 elsif($k =~ /u/i) {
89 kill 1, ${$o[$in]}[2]; # HUP
91 elsif($k =~ /i/i) {
92 kill 2, ${$o[$in]}[2]; # INT
94 elsif($k =~ /d/i) {
95 undef$/;
96 print STDERR "Commandline:\t";
97 open A,"/proc/".${$o[$in]}[2]."/cmdline";
98 print STDERR join(" ",split/\x0/,<A>)."\n";
99 close A;
100 print STDERR "Directory:\t";
101 print STDERR readlink "/proc/".${$o[$in]}[2]."/cwd","\n";
102 $/="\n";
103 open A,"/proc/".${$o[$in]}[2]."/status";
104 /^(ppid|uid|gid):/i and print STDERR $_ while<A>;
105 close A;
107 elsif($k =~ /[xcl]/i) {
108 $dispmode=lc $k;
110 elsif($k =~ /[?h]/i) {
111 helpy;
113 elsif($k =~ /[\r\n]/) {
114 ReadMode 0;
115 print STDOUT "export JOBSEL_DISPLAY_MODE=$dispmode; fg ".$o[$in][0];
116 exit 0;
118 elsif($k =~ /q/i) { bye }
120 # clear screen region
121 if($dispmode =~ /[xc]/) {
122 print STDERR "\033[s\033[1;1H";
123 if($dispmode eq "x") {
124 print STDERR " " x $ARGV[1], "\n" for @x
126 elsif($dispmode eq "c") {
127 print STDERR " " x (-$pos+tell STDERR)
129 print STDERR "\033[u";
133 __END__
135 =pod
137 =head1 NAME
139 jobsel
141 =head1 SYNOPSIS
143 jobsel <B<joblist>> [B<COLUMNS>]
145 =head1 DESCRIPTION
147 Improved job control frontend for bash. B<joblist> is a C<jobs -l> output from which B<jobsel> builds a menu.
148 B<COLUMNS> is an optional parameter, if omitted B<jobsel> calls tput(1) to obtain number of columns on the terminal.
150 =head1 KEYS
152 Left,Right Select item
153 Enter Switch to job in forground
154 U Hangup selected process SIGHUP
155 I Interrupt process SIGINT
156 S,T,Space Suspend, Resume job SIGCONT,SIGTSTP
157 K Kill process SIGKILL
158 D Process details
159 X,C,L Expanded, collapsed, in-line display mode
160 Q Dismiss menu
162 =head1 EXAMPLE
164 eval $(jobsel "$(jobs -l)" $COLUMNS)
166 =head1 HINTS
168 =head2 Use as an alias
170 alias j='eval $(jobsel "$(jobs -l)" $COLUMNS)'
172 =head2 Bind a function key for it
174 bind -x '"\204"':"eval \$(jobsel \"\$(jobs -l)\" \$COLUMNS)"
175 bind '"\ej"':"\"\204\"" # ESC-J
177 Where 204 is an arbitrary free keyscan code
179 =cut