Skip to content

Commit

Permalink
Bugfixes, improve Zig implementation mount, remove runId
Browse files Browse the repository at this point in the history
 * Fixed crash when helpers.FileExists encounters unknown error
 * Removed ai.runId in aisap-go to simplify codebase. This was
   originally to make the mount point inside the sandbox look like a
   normal AppImage, but I don't think it justifies the extra LoC
 * Removed some useless comments in aisap-go
 * Begin adding code for new profile API (which will use more proper
   values instead of strings)
 * Use zig ar instead of system ar since we have it
 * For aisap-zig, now mount by daemonizing fuse and using a thread, so
   code can continue after the AppImage is mounted
 * Add function to generate temporary mount dir in aisap-zig
 * Use known-folders for temporary mount dir location
  • Loading branch information
mgord9518 committed Jul 30, 2023
1 parent 08226a5 commit bc6ec57
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 50 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "zig/bubblewrap"]
path = zig/bubblewrap
url = https://github.com/mgord9518/bubblewrap
[submodule "zig/known-folders"]
path = zig/known-folders
url = https://github.com/ziglibs/known-folders
15 changes: 6 additions & 9 deletions appimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,29 @@ type AppImage struct {
Desktop *ini.File // INI of internal desktop entry
Perms *permissions.AppImagePerms // Permissions
Path string // Location of AppImage
dataDir string // The AppImage's `~` directory
dataDir string // The AppImage's `HOME` directory
rootDir string // Can be used to give the AppImage fake system files
tempDir string // The AppImage's `/tmp` directory
mountDir string // The location the AppImage is mounted at
md5 string // MD5 of AppImage's URI
runId string // Random string associated with this specific run instance
Name string // AppImage name from the desktop entry
Version string // Version of the AppImage
UpdateInfo string // Update information
Version string
UpdateInfo string
Offset int // Offset of SquashFS image
imageType int // Type of AppImage (1=ISO 9660 ELF, 2=squashfs ELF, -2=shImg shell)
architecture []string // List of CPU architectures supported by the bundle
reader *squashfs.Reader
file *os.File

// These will both be removed when the Zig-implemented C bindings
// become usable
CurrentArg int // Should only ever be used for the C bindings
WrapArgsList []string // Should only ever be used for the C bindings
}

// Current version of aisap
const (
Version = "0.8.1-alpha"
Version = "0.9.0-alpha"
)

// Create a new AppImage object from a path
Expand Down Expand Up @@ -212,10 +213,6 @@ func (ai *AppImage) MountDir() string {
return ai.mountDir
}

func (ai *AppImage) RunId() string {
return ai.runId
}

// Set the directory the sandbox pulls system files from
func (ai *AppImage) SetRootDir(d string) {
ai.rootDir = d
Expand Down
6 changes: 3 additions & 3 deletions cmd/aisap/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/mgord9518/aisap/cmd/aisap

go 1.19
go 1.18

replace github.com/mgord9518/aisap => ../../

Expand All @@ -13,7 +13,7 @@ replace github.com/mgord9518/aisap/spooky => ../../spooky
replace github.com/mgord9518/aisap/helpers => ../../helpers

require (
github.com/gookit/color v1.5.3
github.com/gookit/color v1.5.4
github.com/mgord9518/aisap v0.0.0-00010101000000-000000000000
github.com/mgord9518/aisap/helpers v0.0.0-20230110044537-c0113f9e4b7c
github.com/mgord9518/aisap/permissions v0.0.0-20230110044537-c0113f9e4b7c
Expand All @@ -34,5 +34,5 @@ require (
github.com/therootcompany/xz v1.0.1 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/sys v0.10.0 // indirect
)
9 changes: 7 additions & 2 deletions helpers/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,20 @@ func RandString(seed int, length int) string {
func DirExists(path string) bool {
info, err := os.Stat(path)

if os.IsNotExist(err) { return false }
if err != nil {
return false
}

return info.IsDir()
}

// Returns true if any kind of file (including dirs) exists at `path`
func FileExists(path string) bool {
_, err := os.Stat(path)

if os.IsNotExist(err) { return false }
if err != nil {
return false
}

return true
}
Expand Down
21 changes: 7 additions & 14 deletions mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ package aisap
import (
"bufio"
"bytes"
"path"
"path/filepath"
"os"
"os/exec"
"strconv"
"strings"
"errors"
"fmt"

helpers "github.com/mgord9518/aisap/helpers"
xdg "github.com/adrg/xdg"
Expand Down Expand Up @@ -58,23 +57,17 @@ func (ai *AppImage) Mount(dest ...string) error {
return nil
}

pfx := path.Base(ai.Path)
if len(pfx) > 6 {
pfx = pfx[0:6]
}

// Generate a seed based on the AppImage URI MD5sum. This shouldn't cause
// any issues as AppImages will have a different path given a different
// version
seed, err := strconv.ParseInt(ai.md5[0:15], 16, 64)
ai.runId = pfx + helpers.RandString(int(seed), 6)
var err error

ai.tempDir, err = helpers.MakeTemp(filepath.Join(xdg.RuntimeDir, "aisap"), ai.runId)
ai.tempDir, err = helpers.MakeTemp(xdg.RuntimeDir + "/aisap/tmp", ai.md5)
if err != nil { return err }

ai.mountDir, err = helpers.MakeTemp(ai.tempDir, ".mount_" + ai.runId)
ai.mountDir, err = helpers.MakeTemp(xdg.RuntimeDir + "/aisap/mount", ai.md5)
if err != nil { return err }

fmt.Println(ai.mountDir)
fmt.Println(ai.tempDir)

// Only mount if no previous instances (launched of the same version) are
// already mounted there. This is to reuse their libraries, save on RAM and
// to spam the mount list as little as possible
Expand Down
25 changes: 25 additions & 0 deletions permissions/perms.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,36 @@ var (
InvalidSocket = errors.New("socket invalid")
)

type File struct {
Source string
Dest string
Writable bool
}

type Socket int

const (
x11 = Socket(0)
alsa
audio
pulseaudio
wayland
dbus
cgroup
network
pid
pipewire
session
user
uts
)

type AppImagePerms struct {
Level int `json:"level"` // How much access to system files
Files []string `json:"filesystem"` // Grant permission to access files
Devices []string `json:"devices"` // Access device files (eg: dri, input)
Sockets []string `json:"sockets"` // Use sockets (eg: x11, pulseaudio, network)
// TODO: rename to PersistentHome or something
NoDataDir bool `json:"no_data_dir"` // Whether or not a data dir should be created (only
// use if the AppImage saves ZERO data eg: 100% online or a game without
// save files)
Expand Down
13 changes: 3 additions & 10 deletions resources/build_libaisap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,11 @@ rm ../libaisap-x86_64.h
echo "Building Zig functions for libaisap"
cd ../zig
zig build -Doptimize=ReleaseSafe
#zig build-lib \
# lib/c_api.zig -lc \
# -I .. \
# -I squashfuse-zig/squashfuse \
# -fcompiler-rt \
# -fPIE \
# -target x86_64-linux

# Extract both, then combine them into a single lib
ar -x ../libaisap-x86_64.a
ar -x zig-out/lib/libaisap.a
ar -qfc ../libaisap-x86_64.a *.o
zig ar -x ../libaisap-x86_64.a
zig ar -x zig-out/lib/libaisap.a
zig ar -qc ../libaisap-x86_64.a *.o

# Clean up
rm *.o
6 changes: 4 additions & 2 deletions wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (ai *AppImage) mainWrapArgs() []string {
cmdArgs := []string{
"--setenv", "TMPDIR", "/tmp",
"--setenv", "HOME", xdg.Home,
"--setenv", "APPDIR", "/tmp/.mount_"+ai.runId,
"--setenv", "APPDIR", "/tmp/.mount_"+ai.md5,
"--setenv", "APPIMAGE", filepath.Join("/app", path.Base(ai.Path)),
"--setenv", "ARGV0", filepath.Join(path.Base(ai.Path)),
"--setenv", "XDG_DESKTOP_DIR", filepath.Join(xdg.Home, "Desktop"),
Expand Down Expand Up @@ -185,7 +185,7 @@ func (ai *AppImage) mainWrapArgs() []string {
cmdArgs = append(cmdArgs, parseFiles(ai)...)
cmdArgs = append(cmdArgs, parseSockets(ai)...)
cmdArgs = append(cmdArgs, parseDevices(ai)...)
cmdArgs = append(cmdArgs, "--", "/tmp/.mount_"+ai.runId+"/AppRun")
cmdArgs = append(cmdArgs, "--", "/tmp/.mount_"+ai.md5+"/AppRun")

if ai.Perms.NoDataDir {
cmdArgs = append([]string{
Expand All @@ -199,6 +199,7 @@ func (ai *AppImage) mainWrapArgs() []string {

cmdArgs = append([]string{
"--bind", ai.tempDir, "/tmp",
"--bind", ai.mountDir, "/tmp/.mount_"+ai.md5,
}, cmdArgs...)

return cmdArgs
Expand Down Expand Up @@ -327,6 +328,7 @@ func parseSockets(ai *AppImage) []string {
},
"pulseaudio": {
"--ro-bind-try", filepath.Join(xdg.RuntimeDir, "pulse"), "/run/user/"+uid+"/pulse",
// TODO: fix bwrap error when running in level 1
"--ro-bind-try", ai.resolve("/etc/pulse"), "/etc/pulse",
},
"session": {},
Expand Down
9 changes: 9 additions & 0 deletions zig/build.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.{
.name = "aisap",
.version = "0.9.0",
.dependencies = .{
.basedirs = .{
.url = "https://github.com/mgord9518/basedirs-zig/archive/refs/tags/continuous.tar.gz",
},
}
}
10 changes: 9 additions & 1 deletion zig/examples/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ pub fn build(b: *std.build.Builder) void {
},
});

const known_folders_mod = b.addModule("known-folders", .{
.source_file = .{ .path = "../known-folders/known-folders.zig" },
});

const aisap_mod = b.addModule("aisap", .{
.source_file = .{ .path = "../lib.zig" },
.dependencies = &.{
Expand All @@ -46,6 +50,10 @@ pub fn build(b: *std.build.Builder) void {
.name = "squashfuse",
.module = squashfuse_mod,
},
.{
.name = "known-folders",
.module = known_folders_mod,
},
},
});

Expand All @@ -57,7 +65,7 @@ pub fn build(b: *std.build.Builder) void {

squashfuse.linkVendored(exe, .{
.enable_lz4 = true,
.enable_lzo = true,
.enable_lzo = false,
.enable_zlib = true,
.enable_zstd = true,
.enable_xz = true,
Expand Down
10 changes: 9 additions & 1 deletion zig/examples/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,13 @@ pub fn main() !void {
try ai.md5(&md5_buf),
});

try ai.mount(.{});
try ai.mount(.{
.path = "/tmp/ligma",
});

while (true) {
std.time.sleep(10000000000);
}

std.debug.print("OUT OF MOUNT\n", .{});
}
1 change: 1 addition & 0 deletions zig/known-folders
Submodule known-folders added at fa75e1
35 changes: 32 additions & 3 deletions zig/lib/AppImage.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ const io = std.io;
const fs = std.fs;
const span = std.mem.span;
const expect = std.testing.expect;
const os = std.os;

const Md5 = std.crypto.hash.Md5;

const known_folders = @import("known-folders");
const squashfs = @import("squashfuse");
pub const SquashFs = squashfs.SquashFs;

Expand Down Expand Up @@ -279,15 +281,42 @@ pub const AppImage = struct {

pub const MountOptions = struct {
path: ?[]const u8 = null,
foreground: bool = false,
};

// TODO: refactor
fn getMountDir(ai: *AppImage, buf: []u8) ![]const u8 {
var allocator_buf: [4096]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&allocator_buf);
const allocator = fba.allocator();

const runtime_dir = try known_folders.getPath(allocator, .runtime) orelse unreachable;

var md5_buf: [33]u8 = undefined;
return try std.fmt.bufPrint(buf, "{s}/aisap/mount/{s}", .{ runtime_dir, try ai.md5(&md5_buf) });
}

pub fn mount(ai: *AppImage, opts: MountOptions) !void {
// TODO: proper temp dir
const mount_dir = opts.path orelse "/tmp/mountTemp";
var buf: [os.PATH_MAX]u8 = undefined;

// const cwd = fs.cwd();
// cwd.makePath(runtime_dir) catch |err| {
// if (err != os.MakeDirError.PathAlreadyExists) {}
// };

const mount_dir = opts.path orelse try ai.getMountDir(&buf);

const off = try ai.offset();

try mountHelper.mountImage(ai.path, mount_dir, off);
if (opts.foreground) {
mountHelper.mountImage;
} else {
_ = try std.Thread.spawn(
.{},
mountHelper.mountImage,
.{ ai.path, mount_dir, off },
);
}
}

// This can't be finished until AppImage.wrapArgs works correctly
Expand Down
11 changes: 6 additions & 5 deletions zig/lib/mount.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ const expect = std.testing.expect;

const Md5 = std.crypto.hash.Md5;

// TODO: figure out how to add this package correctly
const squashfs = @import("squashfuse");
pub const SquashFs = squashfs.SquashFs;
const squashfuse = @import("squashfuse");
pub const SquashFs = squashfuse.SquashFs;

const fuse = @import("fuse.zig");
const E = fuse.E;
Expand All @@ -20,13 +19,15 @@ const Squash = struct {
file_tree: std.StringArrayHashMap(SquashFs.Inode.Walker.Entry),
};

// TODO: replace fuse.main because it exits the process
// TODO: replace fuse.main because it prints errors on fail
pub fn mountImage(src: []const u8, dest: []const u8, offset: usize) !void {
var allocator = std.heap.c_allocator;

const args = &[_][:0]const u8{
"aisap_mount",
"aisap_squashfuse",
// Squashfuse doesn't support multithreading
"-s",
"-f",
try allocator.dupeZ(u8, dest),
};

Expand Down

0 comments on commit bc6ec57

Please sign in to comment.