31605c8c7e234bc176123170f571e086e05c8232
[profile.git] / opt / bin / ktmux_helper
1 #!/usr/bin/perl
2 #
3 # ktmux_helper: Run krenew in the background for tmux.
4 # Notes: Doesn't handle multiple sessions properly.
5 #
6
7 use FindBin;
8 use POSIX ":sys_wait_h";
9
10 my $PROG = $FindBin::Script;
11
12 # Ensure tmux is our parent and find its PID.
13 our $tmux_pid = &get_tmux_pid;
14 unless ($tmux_pid) {
15   print STDERR "$PROG: Not a child of tmux!\n";
16   exit 100;
17 }
18
19 # Ensure there isn't already a helper running for this tmux.
20 my $tmux_helper = &get_tmux_helper;
21 exit 0 if $tmux_helper;
22 $tmux_helper = $$;
23
24 my $exitasap = 0;
25 my $pid = 0;
26
27 $SIG{INT} = \&cleanup;
28 $SIG{QUIT} = \&cleanup;
29 $SIG{TERM} = \&cleanup;
30 $SIG{USR1} = \&want_credentials;
31
32 LOOP: while (&ping_tmux) {
33   $pid = fork;
34   die "$PROG: Can't fork: $!\n" unless defined $pid;
35
36   if ($pid) {
37     while (&ping_tmux) {
38       my $exited = waitpid $pid, WNOHANG;
39       goto LOOP if $exited == $pid || $exited < 0;
40       sleep 1;
41     }
42
43     # tmux is dead so kill krenew.
44     kill QUIT, $pid;
45     waitpid $pid, 0;
46     exit 0;
47   }
48   else {
49     exit 1 if &check_credentials;
50     exec "krenew", "-K", "60";
51     print "$PROG: Can't run krenew: $!\n";
52     exit 111;
53   }
54 }
55
56 sub get_tmux_pid {
57   my $pid = getppid;
58   my $cmd = `/bin/ps -o args= -p $pid`;
59   return $pid if $cmd =~ /\btmux\b/;
60   return undef;
61 }
62
63 sub check_kinit_child {
64   foreach my $pid (`/bin/ps -o ppid= -C kinit`) {
65     return 1 if $pid =~ /^\s*$tmux_pid\s*$/;
66   }
67   return 0;
68 }
69
70 sub get_tmux_helper {
71   my $pid = undef;
72   if (open IN, "pgrep -x -P $tmux_pid $PROG | ") {
73     while (<IN>) {
74       chomp;
75       s/[^\d]//g;
76       next if $_ == $$;
77       $pid = $_;
78       last;
79     }
80     close IN;
81   }
82   return $pid;
83 }
84
85 sub ping_tmux {
86   return kill 0, $tmux_pid;
87 }
88
89 # Try to check existing Kerberos credentials.
90 sub check_credentials {
91   system "klist", "-s";
92   return 1 if $? < 0;
93   return 0 unless $?;
94   kill USR1, $tmux_helper;
95   return 111;
96 }
97
98 # We were signalled by our child which noticed that our credentials expired.
99 sub want_credentials {
100   # Do we already know?
101   return sleep 1 if &check_kinit_child;
102   system "tmux", "new-window", "-n", "Renew Kerberos credentials", "exec kinit";
103 }
104
105 sub cleanup {
106   unless ($exitasap) {
107     $exitasap = 1;
108     kill $pid;
109     waitpid $pid, WNOHANG;
110     exit 0;
111   }
112 }