Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

beebox / crossover   deb

Repository URL to install this package:

/ opt / cxoffice / bin / cxsu

#!/usr/bin/perl
# (c) Copyright 2001-2014. CodeWeavers, Inc.
use warnings;
use strict;


# Portable which(1) implementation
sub cxwhich($$;$)
{
    my ($dirs, $app, $noexec)=@_;
    if ($app =~ /^\//)
    {
        return $app if ((-x $app or $noexec) and -f $app);
    }
    elsif ($app =~ /\//)
    {
        require Cwd;
        my $path=Cwd::cwd() . "/$app";
        return $path if ((-x $path or $noexec) and -f $path);
    }
    else
    {
        foreach my $dir (split /:/, $dirs)
        {
            return "$dir/$app" if ($dir ne "" and (-x "$dir/$app" or $noexec) and -f "$dir/$app");
        }
    }
    return undef;
}

# Fast dirname() implementation
sub _cxdirname($)
{
    my ($path)=@_;
    return undef if (!defined $path);
    return "." if ($path !~ s!/+[^/]+/*$!!s);
    return "/" if ($path eq "");
    return $path;
}

# Locate where CrossOver is installed by looking for the directory
# where the cxmenu script is located, unwinding symlinks on the way
sub locate_cx_root(;$)
{
    my ($fallback)=@_;
    my $argv0=cxwhich($ENV{PATH},$0);
    $argv0=$0 if (!defined $argv0);
    if ($argv0 !~ m+^/+)
    {
        require Cwd;
        $argv0=Cwd::cwd() . "/$argv0";
    }
    my $dir=_cxdirname($argv0);
    my $bindir=$dir;
    $bindir =~ s%/lib$%/bin%;
    while (!-x "$bindir/cxmenu" or !-f "$bindir/cxmenu")
    {
        last if (!-l $argv0);
        $argv0=readlink($argv0);
        $argv0="$dir/$argv0" if ($argv0 !~ m+^/+);
        $dir=_cxdirname($argv0);
        $bindir=$dir;
        $bindir =~ s%/lib$%/bin%;
    }
    $bindir =~ s%/(?:\./)+%/%g;
    $bindir =~ s%/\.$%%;
    $ENV{CX_ROOT}=_cxdirname($bindir);
    if ((!-x "$ENV{CX_ROOT}/bin/cxmenu" or !-f "$ENV{CX_ROOT}/bin/cxmenu") and
        $fallback)
    {
        $ENV{CX_ROOT}=$fallback;
    }
    if (!-x "$ENV{CX_ROOT}/bin/cxmenu" or !-f "$ENV{CX_ROOT}/bin/cxmenu")
    {
        my $name0=$0;
        $name0 =~ s+^.*/++;
        print STDERR "$name0:error: could not find CrossOver in '$ENV{CX_ROOT}'\n";
        exit 1;
    }
    return $ENV{CX_ROOT};
}

BEGIN {
    unshift @INC, locate_cx_root() . "/lib/perl";
}
use CXLog;
use CXUtils;


# Process command-line options
my $opt_console;
my $opt_description;
my $opt_wait;
my $opt_ignore_home;
my $opt_parent;
my $opt_verbose;
my $opt_help;
require CXOpts;
my $cxopts=CXOpts->new(["stop_on_non_option"]);
$cxopts->add_options(["console"    => \$opt_console,
                      "description=s"  => \$opt_description,
                      "wait"       => \$opt_wait,
                      "ignore-home"=> \$opt_ignore_home,
                      "parent=s"   => \$opt_parent,
                      "verbose!"   => \$opt_verbose,
                      "?|h|help"   => \$opt_help
                     ]);
my $err=$cxopts->parse();
CXLog::fdopen(2) if ($opt_verbose);

# Validate the command line options
my $usage;
if ($err)
{
    cxerr("$err\n");
    $usage=2;
}
elsif ($opt_help)
{
    $usage=0;
}
elsif (!@ARGV)
{
    cxerr("no command specified\n");
    $usage=2;
}

# Always let the parent know we started, even in case of erroneous usage
my $parent_fifo;
if ($opt_parent and !open($parent_fifo, ">", $opt_parent))
{
    cxerr("unable to open '$opt_parent' for writing: $!\n");
    # Don't overwrite $usage if it is already set
    $usage||=1;
}

# Print usage
if (defined $usage)
{
    my $name0=cxname0();
    if ($usage)
    {
        cxerr("try '$name0 --help' for more information\n");
        exit $usage;
    }
    print "Usage: $name0 [--console] [--description MSG] [--wait] [--verbose] [--help]\n";
    print "            COMMAND\n";

    print "\n";
    print "Runs the specified command as root.\n";

    print "\n";
    print "Options:\n";
    print "  COMMAND     The command to run as root as separate arguments. Explicitly use\n";
    print "              'sh -c' if the command should be run by the shell.\n";
    print "  --console   Indicates that the command to be run needs a console, typically\n";
    print "              because it will prompt the user on the console. It is recommended\n";
    print "              not to pass this option to start a graphical application.\n";
    print "  --description MSG Provides a description of the operation to be performed as\n";
    print "              root and its rationale. Note that this currently only has an\n";
    print "              effect in --console mode.\n";
    print "  --wait      Wait after the command has completed.\n";
    print "  --ignore-home Don't try to preserve \$HOME and other environment variables.\n";
    print "  --verbose   Output more information about what is going on.\n";
    print "  --help, -h  Shows this help message.\n";
    exit 0;
}

if ($> == 0)
{
    # We are already root, so just run the command
    cxexec(@ARGV);
    cxerr("unable to run ", CXUtils::argv2shcmd(@ARGV), ": $!\n");
    exit 1;
}

# Note that we cannot trust the graphical 'su' tools, gksu and kdesudo in
# particular, to provide or leave the console in a usable state, which makes
# them incompatible with the --console option.
my @args;
if (!$opt_console and $ENV{DISPLAY})
{
    # Try to pick the appropriate default for the current desktop environment
    my $de=CXUtils::get_desktop_environment();
    cxlog("desktop environment: $de\n");
    my @su_list;
    push @su_list, "gksu --", "gnomesu -c" if ($de eq "gnome");
    push @su_list, "gksu --" if ($de eq "deepin");
    push @su_list, "kdesudo --", "kdesu --" if ($de eq "kde");
    # And push all known tools as fallbacks. Push xdg-su last because its
    # behavior for 'sh -c' commands is inconsistent between GNOME and KDE.
    push @su_list, "gksu --", "gnomesu -c", "kdesudo --", "kdesu --", "xdg-su -c";

    foreach my $sutool_cmd (@su_list)
    {
        my @sutool=CXUtils::cmdline2argv($sutool_cmd);
        my $sutoolname=shift @sutool;
        cxlog("trying '$sutoolname'\n");
        my $path=cxwhich("$ENV{PATH}:/usr/lib64/kde4/libexec:/usr/lib/kde4/libexec", $sutoolname);
        if (defined $path)
        {
            my $shcmd=CXUtils::argv2shcmd(@ARGV);

            if ($sutoolname eq "gksu")
            {
                # 'gksu --' expects the command as separate arguments, does
                # not run it through sh and passes through stdout and the exit
                # code normally.
                # 'gksu --' is supported since GNOME 2.16, circa ~2006.
                # 'gksu --' gets confused if the first argument contains a
                # space so run the command through 'env' in that case.
                unshift @ARGV, "env" if ($ARGV[0] =~ / /);
                @args=($path, @sutool, @ARGV);
            }
            elsif ($sutoolname eq "gnomesu")
            {
                # 'gnomesu -c' expects the command as a single argument, does
                # not run it through sh and passes through stdout and the exit
                # code normally.
                @args=($path, @sutool, $shcmd);
            }
            elsif ($sutoolname eq "xdg-su")
            {
                # 'xdg-su -c' expects the command as a single argument and,
                # depending on the backend, may or may not run it through sh so
                # we run the commands through 'env'. xdg-su also may or may not
                # pass through stdout. Finally it always preserves zero exit
                # codes, but non-zero ones are usually mapped to another
                # non-zero value.
                @args=($path, @sutool, "env $shcmd");
            }
            else
            {
                # 'kdesu --' expects the command in as separate arguments,
                # won't run a command with a relative path
                # runs it through sh in old version and not in new versions
                # (the same is true for the '-c' variant too except that the
                # latter gets confused if there's an extra 'sh -c'), eats
                # stdout but returns the exit code normally.
                # The old versions of kdesu that ru the command in sh get
                # confused if the first argument contains a space so run the
                # command through env in that case.
                # kdesudo works the same way as kdesu.
                unshift @ARGV, "env" if ($ARGV[0] =~ / /);
                @args=($path, @sutool, @ARGV);
            }
            last;
        }
    }
}

if (!@args)
{
    # Make sure we get a usable console as we are falling back to a console
    # 'su' tool.
    require POSIX;
    if (!POSIX::isatty(0))
    {
        @args=CXUtils::get_terminal_emulator(cxgettext("Enter the root password"));
        if (!@args)
        {
            cxerr("unable to find a suitable terminal emulator\n");
            exit 1;
        }
        # Use 'sh -c' as recommended by get_terminal_emulator().
        # Also the terminal emulator, gnome-terminal for instance, may
        # return before the command terminates so use a fifo to
        # synchronize.
        my $name0=cxname0();
        my $path = $ENV{TMPDIR} || "/tmp";
        $path .= "/$name0-fifo.$$";
        if (cxsystem("mkfifo", "-m", "0600", $path))
        {
            cxerr("unable to create the '$path' fifo\n");
            exit 1;
        }
        my @child_cxsu=($0, "--parent", $path, "--wait");
        push @child_cxsu, "--console" if ($opt_console);
        push @child_cxsu, "--description", $opt_description if ($opt_description);
        push @child_cxsu, @ARGV;
        push @args, "/bin/sh", "-c", CXUtils::argv2shcmd(@child_cxsu);
        my $pid=fork();
        if (!defined $pid)
        {
            cxerr("unable to fork: $!\n");
            unlink $path;
            exit 1;
        }
        if ($pid == 0)
        {
            cxexec(@args);
            cxerr("unable to run '@args': $!\n");
            exit 1;
        }
        my $rc=1;
        eval
        {
            local $SIG{ALRM} = sub { die "timeout" };
            alarm(3);
            if (open(my $fifo, "<", $path))
            {
                alarm(0);
                $rc=<$fifo>;
                $rc=1 if (!defined $rc);
                close($fifo);
            }
            else
            {
                alarm(0);
                cxerr("unable to open '$path' for reading: $!\n");
            }
        };
        if ($@ eq "timeout")
        {
            cxerr("timed out waiting for the child $name0 process to start\n");
            $rc=1;
        }
        elsif ($@)
        {
            cxerr("$@\n");
            $rc=1;
        }
        unlink $path;
        # Sanitize $rc so it is suitable for exit
        exit($rc >> 8) if ($rc >> 8);
        exit($rc);
    }
}

if (!@args)
{
    my $command=CXUtils::argv2shcmd(@ARGV);
    print "$opt_description\n" if ($opt_description);
    print cxgettext("This operation must be run as root:\n");
    print "\n   $command\n\n";

    # Use sudo if available and allowed
    my $sudo_path=cxwhich("$ENV{PATH}","sudo");
    if (defined $sudo_path)
    {
        my $cmd=shquote_string($sudo_path) . " -l |";
        print "Trying with sudo...\n";
        cxlog("Running: $cmd\n");
        if (open(my $fh, $cmd))
        {
Loading ...