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