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