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 # -p <pid> Specify tmux PID.
10 # -s <session> Specify tmux session number.
11 # Notes: The -p and -s flags are only used to identify instances when
12 # viewed in ps output.
17 use POSIX ":sys_wait_h";
19 my $PROG = $FindBin::Script;
21 # Remember args for re-exec.
23 foreach my $arg (@ARGV) {
28 getopts('I:L:R:T:p:s:', \%opts);
30 # Ensure tmux is our parent and find its PID if not already known.
31 our $tmux_pid = &get_tmux_pid($opts{'p'});
33 print STDERR "$PROG: Not a child of tmux!\n";
37 # Find session if possible.
38 our $tmux_session = &get_tmux_session($opts{'s'});
40 # Fix the environment.
41 $ENV{TMUX} =~ s/,\d+,-?\d+$/,$tmux_pid,$tmux_session/;
43 # Ensure there isn't already a helper running for this tmux.
44 my $tmux_helper = &get_tmux_helper;
45 exit 0 if $tmux_helper;
48 # Re-exec ourselves purely so the session and PID are set in the environment.
50 push @args, "-p", $tmux_pid unless defined $opts{'p'};
51 push @args, "-s", $tmux_session unless defined $opts{'s'};
52 exec $0, @args, @execargs if @args;
54 my $kinit = $opts{'I'} || "kinit";
55 my $klist = $opts{'L'} || "klist";
56 my $krenew = $opts{'R'} || "krenew";
57 my $tmux = $opts{'T'} || "tmux";
64 $SIG{INT} = \&cleanup;
65 $SIG{QUIT} = \&cleanup;
66 $SIG{TERM} = \&cleanup;
67 $SIG{USR1} = \&want_credentials;
69 LOOP: while (&ping_tmux) {
71 die "$PROG: Can't fork: $!\n" unless defined $pid;
75 my $exited = waitpid $pid, WNOHANG;
76 goto LOOP if $exited == $pid || $exited < 0;
80 # tmux is dead so kill krenew.
86 exit 1 if &check_credentials;
87 exec $krenew, "-K", "60";
88 print STDERR "$PROG: Can't run krenew: $!\n";
94 # Set from command line?
97 # Set from environment?
99 if ($ENV{TMUX} =~ /,(\d+),[^,]+$/) {
107 # Check it really is our parent.
109 # Check that it's still running.
110 return $pid if kill -0, $pid;
116 # Everything below probably can't happen so should be removed.
117 my $cmd = `/bin/ps -o args= -p $pid`;
118 return $pid if $cmd =~ /\btmux\b/;
122 sub get_tmux_session {
123 # Set from command line?
126 # Set from environment?
128 # The session identifier will be -1 if we were launched from run-shell
129 # because a run-shell command doesn't count as being part of a session.
130 if ($ENV{TMUX} =~ /,(-?\d+)$/) {
138 # Check that a given process was launched from our session.
139 sub check_tmux_session {
142 return undef unless defined $tmux_session;
145 if ($^O eq "linux") {
146 $cmd = "xargs -0 -n 1 < /proc/$pid/environ";
148 elsif ($^O eq "solaris") {
149 $cmd = "pargs -Fe $pid";
152 # Don't know how to check on this OS.
156 return undef unless (open IN, "$cmd | ");
160 next unless /TMUX=.+,(-?\d+)/;
161 # Abort if the running helper doesn't know what session it's for.
162 if ($1 eq $tmux_session || $1 eq "-1") {
172 sub check_kinit_child {
173 foreach my $pid (`/bin/ps -o ppid= -C kinit`) {
174 next unless $pid =~ /^\s*$tmux_pid\s*$/;
175 next if &check_tmux_session($pid);
181 sub get_tmux_helper {
183 if (open IN, "pgrep -x -P $tmux_pid $PROG | ") {
189 return $pid if &check_tmux_session($pid);
197 return kill 0, $tmux_pid;
200 # Try to check existing Kerberos credentials.
201 sub check_credentials {
205 kill USR1, $tmux_helper;
209 # We were signalled by our child which noticed that our credentials expired.
210 sub want_credentials {
211 return sleep 1 if $avoid_race;
213 # Do we already know?
214 system $tmux, "new-window", "-n", "Renew Kerberos credentials", "exec $kinit" unless &check_kinit_child;
223 waitpid $pid, WNOHANG;