mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-23 20:26:09 +03:00
passwd uses new FlatpakHostCommand
This commit is contained in:
@ -19,6 +19,10 @@ pub fn isFlatpak() bool {
|
||||
/// This makes it easy for the command to behave synchronously similar to
|
||||
/// std.process.ChildProcess.
|
||||
///
|
||||
/// There are lots of chances for low-hanging improvements here (automatic
|
||||
/// pipes, /dev/null, etc.) but this was purpose built for my needs so
|
||||
/// it doesn't have all of those.
|
||||
///
|
||||
/// Requires GIO, GLib to be available and linked.
|
||||
pub const FlatpakHostCommand = struct {
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -78,16 +82,13 @@ pub const FlatpakHostCommand = struct {
|
||||
},
|
||||
};
|
||||
|
||||
/// Execute the command and wait for it to finish. This will automatically
|
||||
/// read all the data from the provided stdout/stderr fds and return them
|
||||
/// in the result.
|
||||
///
|
||||
/// This runs the exec in a dedicated thread with a dedicated GLib
|
||||
/// event loop so that it can run synchronously.
|
||||
pub fn exec(self: *FlatpakHostCommand, alloc: Allocator) !void {
|
||||
const thread = try std.Thread.spawn(.{}, threadMain, .{ self, alloc });
|
||||
thread.join();
|
||||
}
|
||||
/// Errors that are possible from us.
|
||||
pub const Error = error{
|
||||
FlatpakMustBeStarted,
|
||||
FlatpakSpawnFail,
|
||||
FlatpakSetupFail,
|
||||
FlatpakRPCFail,
|
||||
};
|
||||
|
||||
/// Spawn the command. This will start the host command. On return,
|
||||
/// the pid will be available. This must only be called with the
|
||||
@ -105,7 +106,7 @@ pub const FlatpakHostCommand = struct {
|
||||
|
||||
return switch (self.state) {
|
||||
.init => unreachable,
|
||||
.err => error.FlatpakSpawnFail,
|
||||
.err => Error.FlatpakSpawnFail,
|
||||
.started => |v| v.pid,
|
||||
.exited => |v| v.pid,
|
||||
};
|
||||
@ -119,8 +120,8 @@ pub const FlatpakHostCommand = struct {
|
||||
|
||||
while (true) {
|
||||
switch (self.state) {
|
||||
.init => return error.FlatpakCommandNotStarted,
|
||||
.err => return error.FlatpakSpawnFail,
|
||||
.init => return Error.FlatpakMustBeStarted,
|
||||
.err => return Error.FlatpakSpawnFail,
|
||||
.started => {},
|
||||
.exited => |v| {
|
||||
self.state = .{ .init = {} };
|
||||
@ -187,15 +188,15 @@ pub const FlatpakHostCommand = struct {
|
||||
defer c.g_object_unref(fd_list);
|
||||
if (c.g_unix_fd_list_append(fd_list, self.stdin, &err) < 0) {
|
||||
log.warn("error adding fd: {s}", .{err.*.message});
|
||||
return error.FlatpakFdFailed;
|
||||
return Error.FlatpakSetupFail;
|
||||
}
|
||||
if (c.g_unix_fd_list_append(fd_list, self.stdout, &err) < 0) {
|
||||
log.warn("error adding fd: {s}", .{err.*.message});
|
||||
return error.FlatpakFdFailed;
|
||||
return Error.FlatpakSetupFail;
|
||||
}
|
||||
if (c.g_unix_fd_list_append(fd_list, self.stderr, &err) < 0) {
|
||||
log.warn("error adding fd: {s}", .{err.*.message});
|
||||
return error.FlatpakFdFailed;
|
||||
return Error.FlatpakSetupFail;
|
||||
}
|
||||
|
||||
// Build our arguments for the file descriptors.
|
||||
@ -279,7 +280,7 @@ pub const FlatpakHostCommand = struct {
|
||||
&err,
|
||||
) orelse {
|
||||
log.warn("Flatpak.HostCommand failed: {s}", .{err.*.message});
|
||||
return error.FlatpakHostCommandFailed;
|
||||
return Error.FlatpakRPCFail;
|
||||
};
|
||||
defer c.g_variant_unref(reply);
|
||||
|
||||
@ -335,6 +336,7 @@ pub const FlatpakHostCommand = struct {
|
||||
.status = std.math.cast(u8, exit_status) orelse 255,
|
||||
},
|
||||
});
|
||||
log.debug("HostCommand exited pid={} status={}", .{ pid, exit_status });
|
||||
|
||||
// We're done now, so we can unsubscribe
|
||||
c.g_dbus_connection_signal_unsubscribe(bus.?, state.subscription);
|
||||
|
@ -49,13 +49,12 @@ pub fn get(alloc: Allocator) !Entry {
|
||||
// If we're in flatpak then our entry is always empty so we grab it
|
||||
// by shelling out to the host. note that we do HAVE an entry in the
|
||||
// sandbox but only the username is correct.
|
||||
//
|
||||
// Note: we wrap our getent call in a /bin/sh login shell because
|
||||
// some operating systems (NixOS tested) don't set the PATH for various
|
||||
// utilities properly until we get a login shell.
|
||||
if (internal_os.isFlatpak()) {
|
||||
log.info("flatpak detected, will use host-spawn to get our entry", .{});
|
||||
|
||||
// Note: we wrap our getent call in a /bin/sh login shell because
|
||||
// some operating systems (NixOS tested) don't set the PATH for various
|
||||
// utilities properly until we get a login shell.
|
||||
const Pty = @import("Pty.zig");
|
||||
var pty = try Pty.open(.{});
|
||||
defer pty.deinit();
|
||||
@ -76,31 +75,43 @@ pub fn get(alloc: Allocator) !Entry {
|
||||
};
|
||||
_ = try cmd.spawn(alloc);
|
||||
_ = try cmd.wait();
|
||||
if (true) @panic("END");
|
||||
|
||||
const exec = try std.ChildProcess.exec(.{
|
||||
.allocator = alloc,
|
||||
.argv = &[_][]const u8{
|
||||
"/app/bin/host-spawn",
|
||||
"-pty",
|
||||
"/bin/sh",
|
||||
"-l",
|
||||
"-c",
|
||||
try std.fmt.allocPrint(
|
||||
alloc,
|
||||
"getent passwd {s}",
|
||||
.{std.mem.sliceTo(pw.pw_name, 0)},
|
||||
),
|
||||
},
|
||||
});
|
||||
if (exec.term == .Exited) {
|
||||
// Once started, we can close the child side. We do this after
|
||||
// wait right now but that is fine too. This lets us read the
|
||||
// parent and detect EOF.
|
||||
_ = std.os.close(pty.slave);
|
||||
|
||||
// Read all of our output
|
||||
const output = output: {
|
||||
var output: std.ArrayListUnmanaged(u8) = .{};
|
||||
while (true) {
|
||||
const n = std.os.read(pty.master, &buf) catch |err| {
|
||||
switch (err) {
|
||||
// EIO is triggered at the end since we closed our
|
||||
// child side. This is just EOF for this. I'm not sure
|
||||
// if I'm doing this wrong.
|
||||
error.InputOutput => break,
|
||||
else => return err,
|
||||
}
|
||||
};
|
||||
|
||||
try output.appendSlice(alloc, buf[0..n]);
|
||||
|
||||
// Max total size is buf.len. We can do better here by trimming
|
||||
// the front and continuing reading but we choose to just exit.
|
||||
if (output.items.len > buf.len) break;
|
||||
}
|
||||
|
||||
break :output try output.toOwnedSlice(alloc);
|
||||
};
|
||||
log.warn("DONE output={s}", .{output});
|
||||
|
||||
// Shell and home are the last two entries
|
||||
var it = std.mem.splitBackwards(u8, std.mem.trimRight(u8, exec.stdout, " \r\n"), ":");
|
||||
var it = std.mem.splitBackwards(u8, std.mem.trimRight(u8, output, " \r\n"), ":");
|
||||
result.shell = it.next() orelse null;
|
||||
result.home = it.next() orelse null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (pw.pw_shell) |ptr| {
|
||||
const source = std.mem.sliceTo(ptr, 0);
|
||||
|
Reference in New Issue
Block a user