问题
THE NEW QUERY: I am trying to make a unified script that initializes a new Ubuntu install to my liking, it must be run under sudo to install packages, but using gconftool-2 to affect gconf setting relies on the dbus session which is not handled properly by the method of simply changing UID in the script alone. Does someone know how to manage to do this?
OLD QUERY: I am writing a Perl script to be executed on first boot of a new Ubuntu install. This is to ease adding repositories, installing packages, and setting gconf settings. My problem is permissions. To install packages I need the script to be executed as sudo, but then the gconftool-2 call act on the root user and not on my personal user.
回答1:
You can change uids in the middle of the script by altering the uid with POSIX::setuid()
(see perldoc POSIX):
use POSIX 'setuid';
# call cpan to install modules...
POSIX::setuid($newuid);
# ... continue with script
回答2:
You can use sudo again to drop your root privileges like:
sudo -u 'your_username' gfconftool-2
回答3:
After much reading and trial and error it seems that what is missing when you run a script as root is that the DBUS_SESSION_BUS_ADDRESS environment variable is not set. This must be set AND the uid changed to that of the user before the gconf settings can be set. This is my test script that I used to try it out. Run one or the other of the system calls at the end to switch the window button order. Try the script as the user or as root (sudo) to see that it works.
#!/usr/bin/perl
use strict;
use warnings;
use POSIX;
# get the user's name (as opposed to root)
my $user_name = getlogin();
# get the uid of the user by name
my $user_uid = getpwnam($user_name);
print $user_name . ": " . $user_uid . "\n";
my %dbus;
# get the DBUS machine ID
$dbus{'machine_id'} = qx{cat /var/lib/dbus/machine-id};
chomp( $dbus{'machine_id'} );
# read the user's DBUS session file to get variable DBUS_SESSION_BUS_ADDRESS
$dbus{'file'} = "/home/" . $user_name . "/.dbus/session-bus/" . $dbus{'machine_id'} . "-0";
print "checking DBUS file: " . $dbus{'file'} . "\n";
if (-e $dbus{'file'}) {
open(my $fh, '<', $dbus{'file'}) or die "Cannot open $dbus{file}";
while(<$fh>) {
if ( /^DBUS_SESSION_BUS_ADDRESS=(.*)$/ ) {
$dbus{'address'} = $1;
print "Found DBUS address: " . $dbus{'address'} . "\n";
}
}
} else {
print "cannot find DBUS file";
}
# set the uid to the user's uid not root's
POSIX::setuid($user_uid);
# set the DBUS_SESSION_BUS_ADDRESS environment variable
$ENV{'DBUS_SESSION_BUS_ADDRESS'} = $dbus{'address'};
my $command1 = 'gconftool-2 --set "/apps/metacity/general/button_layout" --type string "menu:maximize,minimize,close"';
my $command2 = 'gconftool-2 --set "/apps/metacity/general/button_layout" --type string "menu:minimize,maximize,close"';
system($command1);
## or
#system($command2);
Note: Got some good info here.
来源:https://stackoverflow.com/questions/3875715/how-can-i-run-a-perl-script-as-root-yet-still-affect-user-gconf-settings