#!/usr/local/bin/perl5 # -*- mode: perl -*- $rcsid = q$Id: login-magic 1.1 Sat, 19 Jun 1999 19:19:22 +0100 paul $; #use diagnostics; #use strict; #no strict 'vars'; #use Getopt::Long; #use vars qw($rcsid $fh %optctl); # Annoyingly, I can't *quite* use open2 for this because I need indirect object syntax. $fh = 'FHOPEN000'; sub open2closure { no strict 'refs'; my ($dad_rdr, $dad_wtr, $do_when_forked) = @_; my ($kid_rdr, $kid_wtr, $kidpid); $dad_rdr ne '' || die "open2closure: rdr should not be null"; $dad_wtr ne '' || die "open2closure: wtr should not be null"; # force unqualified filehandles into callers' package # local($package) = caller; # $dad_rdr =~ s/^[^']+$/$package'$&/ unless ref $dad_rdr; # $dad_wtr =~ s/^[^']+$/$package'$&/ unless ref $dad_wtr; $kid_rdr = ++$fh; $kid_wtr = ++$fh; pipe($dad_rdr, $kid_wtr) || die "open2closure: pipe 1 failed: $!"; pipe($kid_rdr, $dad_wtr) || die "open2closure: pipe 2 failed: $!"; if (($kidpid = fork) < 0) { die "open2closure: fork failed: $!"; } elsif ($kidpid == 0) { close $dad_rdr; close $dad_wtr; open(STDIN, "<&$kid_rdr"); open(STDOUT, ">&$kid_wtr"); &{$do_when_forked} or die "open2closure: failed after fork"; exit 0; } close $kid_rdr; close $kid_wtr; select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe $kidpid; } #my ($var, $val, %csh_env, @new_path, %path_includes); open2closure(\*READER, \*WRITER, sub { for (keys %ENV) { next if /^HOME$/ || /^LOGNAME$/ || /^USER$/; delete $ENV{$_} }; chdir $ENV{HOME}; $ENV{PATH} = '/bin:/usr/bin'; exec {'/bin/csh'} '-sh'; }); #print WRITER "source .cshrc\n"; #print WRITER "source .login\n"; print WRITER "echo ENV_START\n"; print WRITER "env\n"; print WRITER "echo ENV_END\n"; print WRITER "logout\n"; close WRITER or die "Failed to close write stream to shell, stopped"; while () { chomp; if (/^ENV_START$/ .. /^ENV_END$/) { if (($var, $val) = /^([^=]+)=(.*)$/) { $csh_env{$var} = $val; } } } # These should already be set in the current shell and shouldn't be mucked about. delete $csh_env{USER}; delete $csh_env{LOGNAME}; delete $csh_env{HOME}; delete $csh_env{PWD}; delete $csh_env{TERM}; #print "# Old path: $csh_env{PATH}\n"; @old_path = split(/:/, $csh_env{PATH}); #print "# Split into: \n# ", join("\n# ", @old_path), "\n"; @new_path = (); sub use_path { # my $self = shift; my $pattern = shift; print "# Matching path pattern $pattern\n"; my $code_fragment = q{ foreach (@old_path) { if (!defined $path_includes{$_} && m{PATTERN}o) { $path_includes{$_} = 1; if (-d $_) { print "# Adding to path: $_\n"; push @new_path, $_; } else { print "# Dropping nonexistant directory: $_\n"; } # } else { # print "# Not accepting nonmatch: $_\n"; } } }; $code_fragment =~ s/PATTERN/$pattern/; print "# Code used to match:\n"; my $commented_code_fragment; $commented_code_fragment = $code_fragment; $commented_code_fragment =~ s/^/\# /gmo; print $commented_code_fragment, "\n"; # print "# Old path: ", join(", ", @old_path), "\n"; eval $code_fragment; } #GetOptions("use-path=s" => \@use_path); # KLUDGE because GetOptions is shit in Perl 5.000 foreach (@ARGV) { next if /^--use-path$/; use_path($_); } foreach (sort keys %csh_env) { next if /^PATH$/; print "$_='$csh_env{$_}'\nexport $_\n"; } print "PATH='", join(":", @new_path), "'\nexport PATH\n";