FuguVM

App::FuguVM::Remote(3p) Perl Library Manual App::FuguVM::Remote(3p)

App::FuguVM::Remote - the remote side of one running guest

    use App::FuguVM::Remote;
    my $remote = App::FuguVM::Remote->new(
        host => $vm->connect_address,
        port => $ssh_port,
    );
    my $result = $remote->run('uname', '-m');
    $remote->put('lib', '/root/lib', mode => 0644)
        or die "put failed\n";
    $remote->get('/root/report.txt', 'report.txt')
        or die "get failed\n";

The module holds the remote side of one running guest: the Fugu::SSH object, the argument quoting, the local walk, and the publish order. Thus App::FuguVM::CLI keeps thin command bodies, and one module holds the session timeout.

Three constants carry the numbers. "SSH_TIMEOUT" is 3600 seconds: Fugu::SSH bounds the connect and the channel read with one value, and the value must hold a guest build and a large transfer. "MAX_TRANSFER_SIZE" is 64 MiB for one file, because "write_file" and "read_file" each hold a file in memory. "BATCH_PATHS" is 100 paths for each batched remote command, so no command line grows too long.

"new" and "run" die on a missing argument, because each one is a programming error. Every other failure is a return value, and the module reports each reason through "Fugu::Log->default".

    App::FuguVM::Remote->new(host => $host, port => $port)

Build the object. It opens nothing. "host" is the connect address of the guest, and the user is "root". The method dies when the caller gives no host, and it dies when the caller gives no port.

    App::FuguVM::Remote->quote_argv(@argv)

Return one remote command string. A class method. The method wraps each word in single quotes, and it replaces each single quote inside a word with the '\'' form. An empty word becomes ''. The words join with one space. So the remote shell splits the string at the word boundaries only: it expands nothing, and it globs nothing.

    $remote->run(@argv)

Run one argument vector on the guest. The method returns the hash of "Fugu::SSH->run_command": "stdout", "stderr" and "exit_code". It dies on an empty vector. A connect failure reads as exit code 1, with the reason in "stderr".

    $remote->interactive

Open an interactive session. The method returns the exit code of ssh(1).

    $remote->put($local, $remote_path, mode => 0600)

Copy a local file or a local directory to $remote_path in the guest. The destination is never a container: the content of a directory arrives under $remote_path, with no component for the source directory name. "mode" sets the mode of each file that the method writes. Without it each file keeps its local permission bits, masked with 0777, so no setuid bit and no setgid bit arrives. A directory gets the mode that the remote umask allows.

The method walks the source first, and a symbolic link, a device node, a socket, a fifo, and a file above "MAX_TRANSFER_SIZE" each fail the whole call before one byte moves. It creates every remote directory with batched "mkdir -p" calls, writes each file to a temporary name beside its destination, and publishes every temporary file with batched "mv -f" calls. A failure removes every temporary file, so a failed run leaves no partial destination file. A directory copy is not atomic as a whole.

The method returns 1, or "undef".

    $remote->get($remote_path, $local)

Copy one regular guest file to $local on the host. The method reads the whole file, with "MAX_TRANSFER_SIZE" as the cap. It creates the parent directory of $local, and it writes the bytes atomically, mode 0644. So a failure leaves no partial local file. A $local that is an existing directory fails the call.

The method returns 1, or "undef".

Fugu::SSH, Fugu::File, App::FuguVM::CLI, fuguvm(1)

Dick Olsson <hi@senzilla.io>

2026-10-16 OpenBSD