Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 47 additions & 15 deletions scripts/cowork-vm-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,32 @@ const LOG_FILE = path.join(
process.env.HOME || '/tmp',
'.config', 'Claude', 'logs', 'cowork_vm_daemon.log'
);

/**
* Locate virtiofsd binary. Debian installs it to /usr/libexec/virtiofsd which
* is outside PATH, so we check well-known locations after checking PATH.
* @returns {string|null} Absolute path to virtiofsd, or null if not found.
*/
function findVirtiofsd() {
const candidates = [
'/usr/libexec/virtiofsd',
'/usr/lib/qemu/virtiofsd',
];
try {
const result = execFileSync('which', ['virtiofsd'], {
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
if (result) return result;
} catch (_) { /* not in PATH */ }
for (const p of candidates) {
try {
fs.accessSync(p, fs.constants.X_OK);
return p;
} catch (_) { /* not found */ }
}
return null;
}

function formatArgs(args) {
return args.map(a => typeof a === 'string' ? a : JSON.stringify(a))
.join(' ');
Expand Down Expand Up @@ -980,22 +1006,28 @@ class KvmBackend extends BackendBase {
const initrdPath = path.join(VM_BASE_DIR, 'initrd');

// Start virtiofsd for home directory share (if available)
try {
const virtiofsSock = path.join(this.sessionDir, 'virtiofs.sock');
this.virtiofsdProcess = spawnProcess('virtiofsd', [
`--socket-path=${virtiofsSock}`,
'-o', `source=${os.homedir()}`,
'-o', 'cache=auto',
], {
stdio: ['ignore', 'pipe', 'pipe'],
});
this.virtiofsdProcess.on('error', (err) => {
log('KvmBackend: virtiofsd error:', err.message);
const virtiofsdBin = findVirtiofsd();
if (virtiofsdBin) {
try {
const virtiofsSock = path.join(this.sessionDir, 'virtiofs.sock');
this.virtiofsdProcess = spawnProcess(virtiofsdBin, [
`--socket-path=${virtiofsSock}`,
'-o', `source=${os.homedir()}`,
'-o', 'cache=auto',
], {
stdio: ['ignore', 'pipe', 'pipe'],
});
this.virtiofsdProcess.on('error', (err) => {
log('KvmBackend: virtiofsd error:', err.message);
this.virtiofsdProcess = null;
});
log(`KvmBackend: virtiofsd started, socket=${virtiofsSock}`);
} catch (e) {
log(`KvmBackend: virtiofsd not available: ${e.message}`);
this.virtiofsdProcess = null;
});
log(`KvmBackend: virtiofsd started, socket=${virtiofsSock}`);
} catch (e) {
log(`KvmBackend: virtiofsd not available: ${e.message}`);
}
} else {
log('KvmBackend: virtiofsd not found, skipping home directory share');
this.virtiofsdProcess = null;
}

Expand Down
25 changes: 24 additions & 1 deletion scripts/launcher-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -470,12 +470,35 @@ print(len(servers))
_info 'Fix: sudo modprobe vhost_vsock'
fi

# virtiofsd — Debian installs it outside PATH (/usr/libexec or /usr/lib/qemu)
local _virtiofsd_bin=''
if command -v virtiofsd &>/dev/null; then
_virtiofsd_bin=$(command -v virtiofsd)
else
local _vfsd_candidate
for _vfsd_candidate in \
/usr/libexec/virtiofsd \
/usr/lib/qemu/virtiofsd
do
if [[ -x $_vfsd_candidate ]]; then
_virtiofsd_bin="$_vfsd_candidate"
break
fi
done
fi

if [[ -n $_virtiofsd_bin ]]; then
_pass "virtiofsd: found ($_virtiofsd_bin)"
else
_warn 'virtiofsd: not found'
_info "Fix: $(_cowork_pkg_hint "$_distro_id" virtiofsd)"
fi

# Check required tools: label, binary, pkg-hint name
local _tool_label _tool_bin _tool_pkg
for _tool_label in \
'QEMU:qemu-system-x86_64:qemu' \
'socat:socat:socat' \
'virtiofsd:virtiofsd:virtiofsd' \
'bubblewrap:bwrap:bubblewrap'
do
_tool_bin="${_tool_label#*:}"
Expand Down