use v6.c; unit class App::RunForPid:ver<0.0.1>:auth; use Term::Choose :choose; sub get-pid { my $proc = run 'xprop', :out; my $output = $proc.out.slurp: :close; for $output.lines -> $line { if $line ~~ m/'_NET_WM_PID'.* \s* '=' \s* $ = [ \d+ ]/ { return $.Int; } } die 'Cannot find pid!'; } sub parse-process-tree(Int $pid) { my @process; my regex name { \w <[\w -]> + } my regex pid { \d+ } my regex proc { '(' ')' } my regex pstree { + % ( '---' || '-+-' ) } my $proc = run 'pstree', '-TlAp', $pid.Str, :out; my $output = $proc.out.slurp: :close; for $output.lines -> $line { if $line ~~ // { @process.append: gather for $ -> $proc { take $proc.Str => $proc.Int } } } @process } sub list-file-descriptors($pid) { my $proc = run 'ls', '-l', "/proc/$pid/fd", :out; my $output = $proc.out.slurp: :close; return gather for $output.lines -> $line { take $line.words[*-1] } } #| Find a pid for a window multi sub MAIN() is export(:main) { my $ppid = get-pid; my @actions = ; say "Found pid from a wm: $ppid"; my @process = parse-process-tree($ppid); my $selection = choose(@process.map({ "{$_.value} ({$_.key})" })) or exit; say "Selected $selection"; my $pid = $selection.words[0]; my $option = choose(@actions) or exit; given $option { when 'gdb' { run 'gdb', '-p', $pid; } when 'fd' { my $fd = choose(list-file-descriptors($pid)) or exit; run 'tail', '-f', "$fd"; } when 'kill' { my $signal = choose(Signal::.keys) or exit; run 'kill', "-{$signal}", $pid; } when 'stdout'|'stderr'|'stdout&stderr' { my $has-stdout = $option.index('stdout').defined; my $has-stderr = $option.index('stderr').defined; my $write = 'write='; if $has-stdout && $has-stderr { $write ~= '1,2'; } elsif $has-stdout { $write ~= '1'; } elsif $has-stderr { $write ~= '2' } my $strace = Proc::Async.new( 'strace', '-e', $write, '-e', 'trace=write', '-e', 'decode-fds=path,socket,dev,pidfd', '-p', $pid ); my @buf; react { whenever $strace.stderr.lines -> $line { given $line { when /write/ { say @buf.join: '' if @buf.elems > 0; @buf = (); } when .index('|').defined { if /$ = [ . ** 16 ] ' |' $$/ { @buf.push: $; } } } # my $in = | 00000 73 74 65 70 20 31 32 33 34 35 36 37 39 30 30 31 step 12345679001 | # $in ~~ / $ = [ . ** 16 ] ' |' $$ /; $/ } whenever $strace.start { say ‘Proc finished: exitcode=’, .exitcode, ‘ signal=’, .signal; done # gracefully jump from the react block } whenever signal(SIGTERM).merge: signal(SIGINT) { once { say ‘Signal received, asking the process to stop’; $strace.kill; # sends SIGHUP, change appropriately whenever signal($_).zip: Promise.in(2).Supply { say ‘Kill it!’; $strace.kill: SIGKILL } } } } } } } #| Execute a command for a child process of $pid multi sub MAIN(Int $pid) is export(:main) { say "Running for $pid"; }