#!/usr/local/bin/perl5 -T

$OSH = "/usr/local/bin/osh";

# Just in case we need to clear the IFS for the system call below.
$ENV{'IFS'} = '' if $ENV{'IFS'};
$ENV{'PATH'} = '/bin:/sbin';

# Any flags?
$symlink = 0;
while ($_ = $ARGV[0], /^-/) {
  $symlink = 1 if (/^-s$/);
  shift;
}

if (!(($#ARGV == 0) || ($#ARGV == 1)) || ($ARGV[0] =~ /^-/)) {
  print "Usage:\n\n\tln [-s] file1 [file2]\n";
  exit(1);
}

# Get the file1 and file2 paramaters.
if ($ARGV[0] =~ /(.+)/) {
  $src = $1;
  shift;
}
else { print "Huh?\n"; exit(1); }

if ($#ARGV == 0) {
  if ($ARGV[0] =~ /(.+)/) {
    $dest = $1;
  }
  else { print "Huh?\n"; exit(1); }

  # Check for someone trying to escape things out. It's facist, but better
  # safe than sorry.
  if (($src =~ /["\\'`]/) || ($dest =~ /["\\'`]/)) {
    print "Special characters (ie. \", \\, ', `) are not allowed.\n";
    exit(1);
  }

  # Is file2 a full path? If not, we need to make sure it is before the
  # system call below. (su will cd to/home/user if it can't access the cwd.)
  if ($dest =~ /^[^\/]/) {
    $cwd = `/bin/pwd`;
    chop($cwd);
    $dest = $cwd . "/" . $dest;
  }
}
else {
  $dest = `/bin/pwd`;
  chop($dest);
}

# Is the dest a directory? If so, we need to add the filename in order to
# avoid a "feature" in Perl's symlink call.
if (-d $dest) {
  @tmp = split('/',$src);
  $dest = $dest . '/' . pop(@tmp);
  undef @tmp;
}

# Get the user, which is the owner of the parent process since the
# current process was setuid(0) before spawning off.
#
# Btw, this is how `ps` gets the info for printing as well.
#
# By name.
#$USER=(getpwuid((stat("/proc/". getppid))[4]))[0];
# By UID.
$USER=(getpwuid((stat("/proc/". getppid))[4]))[2];

if ($pid = fork) {
  wait;
  $status = ($? >> 8);
  if ($status == 1) {
    exit(symlink($src, $dest)) if ($symlink == 1);
    exit(link($src, $dest)) if ($symlink == 0);
  } else {
    print "No permission to file $dest.\n";
    exit(1);
  }
} elsif (defined $pid) {

  # Ignore the interrupts just incase.
  $SIG{'INT'} = 'IGNORE';
  $SIG{'QUIT'} = 'IGNORE';

  # Set the previously gotten UID.
  $> = $< = $USER;

  # Call osh test -w to see if they have priveledge to write where they
  # are trying to.
  exit system("$OSH", "test", "-w \"$dest\"") >> 8;
} else {
  die "Can't fork: $!\n";
}
