Search code examples
javascriptgnome-shell-extensions

GLib run command with root privileges


I'm writing a very simple gnome extension for personal use (in javascript).

To run console commands I use GLib.spawn_command_line_sync("command");

GNOME Shell version 3.36.2

WHAT I NEED

I need to run only one command but with root privileges, how can I make something like GLib.spawn_command_line_sync("sudo command"); work?

I would like to use the default Authentication Required gnome dialog for password input.

WHAT I KNOW

I read a lot the source code and I found the definition of the dialog but I don't understand how to use it because can't really find a single usage example.

I have no idea how to connect those two things together (the dialog and GLib).


Solution

  • Firstly, avoid using GLib.spawn_command_line_sync() in extensions. This function will execute synchronously in the same thread as animations and user interactions, blocking until it completes.

    If you don't need to output or exit status from the command, use GLib.spawn_command_line_async(). If you do need the output or exit status, use Gio.Subprocess with communicate_utf8_async().

    To execute privileged commands as a user, the easiest way probably to use pkexec, which will use the dialog you want (you can test this running it in a terminal):

    // With GLib (no output or success notification)
    let cmd = 'apt-get update';
    
    try {
        GLib.spawn_command_line_async('pkexec ' + cmd);
    } catch (e) {
        logError(e);
    }
    
    // With GSubprocess (output and success notification)
    let args = ['apt-get', 'update'];
    
    function privelegedExec(args) {
        try {
            let proc = Gio.Subprocess.new(
                ['pkexec'].concat(args),
                Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE
            );
    
            proc.communicate_utf8_async(null, null, (proc, res) => {
                try {
                    let [, stdout, stderr] = proc.communicate_utf8_finish(res);
    
                    // Failure
                    if (!proc.get_successful())
                        throw new Error(stderr);
    
                    // Success
                    log(stdout);
                } catch (e) {
                    logError(e);
                }
            });
        } catch (e) {
            logError(e);
        }
    }