diff --git a/.gitmodules b/.gitmodules index 36df0a3..d6682ba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,9 @@ [submodule "zstd"] path = zstd url = https://github.com/facebook/zstd.git +[submodule "squashfuse"] + path = squashfuse + url = https://github.com/vasi/squashfuse.git +[submodule "fuse-overlayfs"] + path = fuse-overlayfs + url = https://github.com/containers/fuse-overlayfs.git diff --git a/build.zig b/build.zig index 80548a5..6edea22 100644 --- a/build.zig +++ b/build.zig @@ -17,6 +17,140 @@ pub fn build(b: *std.Build) void { // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); + const zstd = b.addStaticLibrary(.{ + .name = "zstd", + .target = target, + .optimize = optimize, + .link_libc = true, + }); + zstd.addAssemblyFile(b.path("zstd/lib/decompress/huf_decompress_amd64.S")); + zstd.addCSourceFiles(.{ + .files = &[_][]const u8{ + "zstd/lib/common/debug.c", + "zstd/lib/common/entropy_common.c", + "zstd/lib/common/error_private.c", + "zstd/lib/common/fse_decompress.c", + "zstd/lib/common/pool.c", + "zstd/lib/common/threading.c", + "zstd/lib/common/xxhash.c", + "zstd/lib/common/zstd_common.c", + + "zstd/lib/compress/fse_compress.c", + "zstd/lib/compress/hist.c", + "zstd/lib/compress/huf_compress.c", + "zstd/lib/compress/zstd_compress.c", + "zstd/lib/compress/zstd_compress_literals.c", + "zstd/lib/compress/zstd_compress_sequences.c", + "zstd/lib/compress/zstd_compress_superblock.c", + "zstd/lib/compress/zstd_double_fast.c", + "zstd/lib/compress/zstd_fast.c", + "zstd/lib/compress/zstd_lazy.c", + "zstd/lib/compress/zstd_ldm.c", + "zstd/lib/compress/zstdmt_compress.c", + "zstd/lib/compress/zstd_opt.c", + + "zstd/lib/decompress/huf_decompress.c", + "zstd/lib/decompress/zstd_ddict.c", + "zstd/lib/decompress/zstd_decompress_block.c", + "zstd/lib/decompress/zstd_decompress.c", + }, + }); + + const squashfuse_autogen = b.addSystemCommand(&[_][]const u8{ + "./autogen.sh", + }); + squashfuse_autogen.setCwd(b.path("squashfuse")); + + const squashfuse_configure = b.addSystemCommand(&[_][]const u8{ + "./configure", + "--without-zlib", + "--without-xz", + "--without-lzo", + "--without-lz4", + "--with-zstd", + }); + squashfuse_configure.setCwd(b.path("squashfuse")); + squashfuse_configure.step.dependOn(&squashfuse_autogen.step); + + const squashfuse_make_generate_swap = b.addSystemCommand(&[_][]const u8{ + "make", + "swap.h.inc", + "swap.c.inc", + }); + squashfuse_make_generate_swap.setCwd(b.path("squashfuse")); + squashfuse_make_generate_swap.step.dependOn(&squashfuse_configure.step); + + const overlayfs_autogen = b.addSystemCommand(&[_][]const u8{ + "./autogen.sh", + }); + overlayfs_autogen.setCwd(b.path("fuse-overlayfs")); + + const overlayfs_configure = b.addSystemCommand(&[_][]const u8{ + "./configure", + }); + overlayfs_configure.setCwd(b.path("fuse-overlayfs")); + overlayfs_configure.step.dependOn(&overlayfs_autogen.step); + + const fuse_fss = b.addStaticLibrary(.{ + .name = "fuse-overlayfs", + .target = target, + .optimize = optimize, + .link_libc = true, + }); + fuse_fss.addIncludePath(b.path("zstd/lib")); + + fuse_fss.linkSystemLibrary("fuse3"); + fuse_fss.addIncludePath(b.path("fuse-overlayfs")); + fuse_fss.addIncludePath(b.path("fuse-overlayfs/lib")); + fuse_fss.addCSourceFiles(.{ + .files = &[_][]const u8{ + "fuse-overlayfs/main.c", + "fuse-overlayfs/lib/hash.c", + "fuse-overlayfs/lib/bitrotate.c", + "fuse-overlayfs/utils.c", + "fuse-overlayfs/plugin-manager.c", + "fuse-overlayfs/direct.c", + }, + .flags = &[_][]const u8{ + "-Dmain=overlayfs_main", + // collision with libcrun + "-Dsafe_openat=overlayfs_safe_openat", + "-DPKGLIBEXECDIR=\"\"", + "-Wno-format", + "-Wno-switch", + }, + }); + fuse_fss.addCSourceFiles(.{ + .files = &[_][]const u8{ + "squashfuse/ll_main.c", + "squashfuse/ll.c", + "squashfuse/ll_inode.c", + "squashfuse/fs.c", + "squashfuse/fuseprivate.c", + "squashfuse/stat.c", + "squashfuse/dir.c", + "squashfuse/file.c", + "squashfuse/xattr.c", + "squashfuse/nonstd-enoattr.c", + "squashfuse/nonstd-makedev.c", + "squashfuse/util.c", + "squashfuse/nonstd-daemon.c", + "squashfuse/nonstd-pread.c", + "squashfuse/swap.c", + "squashfuse/table.c", + "squashfuse/cache_mt.c", + "squashfuse/decompress.c", + "squashfuse/nonstd-stat.c", + }, + .flags = &[_][]const u8{ + "-Dmain=squashfuse_main", + "-D_FILE_OFFSET_BITS=64", + }, + }); + + fuse_fss.step.dependOn(&squashfuse_make_generate_swap.step); + fuse_fss.step.dependOn(&overlayfs_configure.step); + const clap = b.dependency("clap", .{ .optimize = optimize, .target = target, @@ -30,6 +164,9 @@ pub fn build(b: *std.Build) void { .link_libc = true, }); + runtime.linkLibrary(zstd); + runtime.linkLibrary(fuse_fss); + runtime.addIncludePath(b.path("crun")); runtime.addIncludePath(b.path("crun/src")); runtime.addIncludePath(b.path("crun/libocispec/src")); @@ -115,36 +252,9 @@ pub fn build(b: *std.Build) void { }); dockerc.addIncludePath(b.path("zstd/lib")); + dockerc.linkLibrary(zstd); dockerc.addCSourceFiles(.{ .files = &[_][]const u8{ - "zstd/lib/common/debug.c", - "zstd/lib/common/entropy_common.c", - "zstd/lib/common/error_private.c", - "zstd/lib/common/fse_decompress.c", - "zstd/lib/common/pool.c", - "zstd/lib/common/threading.c", - "zstd/lib/common/xxhash.c", - "zstd/lib/common/zstd_common.c", - - "zstd/lib/compress/fse_compress.c", - "zstd/lib/compress/hist.c", - "zstd/lib/compress/huf_compress.c", - "zstd/lib/compress/zstd_compress.c", - "zstd/lib/compress/zstd_compress_literals.c", - "zstd/lib/compress/zstd_compress_sequences.c", - "zstd/lib/compress/zstd_compress_superblock.c", - "zstd/lib/compress/zstd_double_fast.c", - "zstd/lib/compress/zstd_fast.c", - "zstd/lib/compress/zstd_lazy.c", - "zstd/lib/compress/zstd_ldm.c", - "zstd/lib/compress/zstdmt_compress.c", - "zstd/lib/compress/zstd_opt.c", - - "zstd/lib/decompress/huf_decompress.c", - "zstd/lib/decompress/zstd_ddict.c", - "zstd/lib/decompress/zstd_decompress_block.c", - "zstd/lib/decompress/zstd_decompress.c", - "squashfs-tools/squashfs-tools/mksquashfs.c", "squashfs-tools/squashfs-tools/progressbar.c", "squashfs-tools/squashfs-tools/caches-queues-lists.c", @@ -167,9 +277,6 @@ pub fn build(b: *std.Build) void { .flags = &[_][]const u8{ // avoid collision of main function "-Dmain=mksquashfs_main", - // zstd: asm is only used for decompression so it is fine to disable - "-DZSTD_DISABLE_ASM", - // squashfs defines "-DZSTD_SUPPORT", "-D_GNU_SOURCE", "-DVERSION=\"dockerc\"", diff --git a/fuse-overlayfs b/fuse-overlayfs new file mode 160000 index 0000000..147609b --- /dev/null +++ b/fuse-overlayfs @@ -0,0 +1 @@ +Subproject commit 147609b1fb0a6f2dc7f522280a0acebc03be0153 diff --git a/squashfuse b/squashfuse new file mode 160000 index 0000000..94f998c --- /dev/null +++ b/squashfuse @@ -0,0 +1 @@ +Subproject commit 94f998c58d2bb6dff00173f33140a0354adce324 diff --git a/src/main.zig b/src/main.zig index 26acded..d896f22 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5,14 +5,14 @@ const common = @import("common.zig"); const mkdtemp = common.mkdtemp; const extract_file = common.extract_file; -const squashfuse_content = @embedFile("tools/squashfuse"); -const overlayfs_content = @embedFile("tools/fuse-overlayfs"); - const c = @cImport({ @cInclude("libcrun/container.h"); @cInclude("libcrun/custom-handler.h"); }); +extern fn squashfuse_main(argc: c_int, argv: [*:null]const ?[*:0]const u8) c_int; +extern fn overlayfs_main(argc: c_int, argv: [*:null]const ?[*:0]const u8) c_int; + fn getOffset(path: []const u8) !u64 { var file = try std.fs.cwd().openFile(path, .{}); try file.seekFromEnd(-8); @@ -174,12 +174,6 @@ pub fn main() !void { var temp_dir_path = "/tmp/dockerc-XXXXXX".*; try mkdtemp(&temp_dir_path); - const squashfuse_path = try extract_file(&temp_dir_path, "squashfuse", squashfuse_content, allocator); - defer allocator.free(squashfuse_path); - - const overlayfs_path = try extract_file(&temp_dir_path, "fuse-overlayfs", overlayfs_content, allocator); - defer allocator.free(overlayfs_path); - const filesystem_bundle_dir_null = try std.fmt.allocPrintZ(allocator, "{s}/{s}", .{ temp_dir_path, "bundle.squashfs" }); defer allocator.free(filesystem_bundle_dir_null); @@ -188,15 +182,25 @@ pub fn main() !void { const mount_dir_path = try std.fmt.allocPrintZ(allocator, "{s}/mount", .{temp_dir_path}); defer allocator.free(mount_dir_path); - const offsetArg = try std.fmt.allocPrint(allocator, "offset={}", .{try getOffset(executable_path)}); + const offsetArg = try std.fmt.allocPrintZ(allocator, "offset={}", .{try getOffset(executable_path)}); defer allocator.free(offsetArg); - const args_buf = [_][]const u8{ squashfuse_path, "-o", offsetArg, executable_path, filesystem_bundle_dir_null }; + const args_buf = [_:null]?[*:0]const u8{ "squashfuse", "-o", offsetArg, executable_path, filesystem_bundle_dir_null }; - var mountProcess = std.process.Child.init(&args_buf, allocator); - _ = try mountProcess.spawnAndWait(); + { + const pid = try std.posix.fork(); + if (pid == 0) { + std.process.exit(@intCast(squashfuse_main(args_buf.len, &args_buf))); + } - const overlayfs_options = try std.fmt.allocPrint(allocator, "lowerdir={s},upperdir={s}/upper,workdir={s}/work", .{ + const wait_pid_result = std.posix.waitpid(pid, 0); + if (wait_pid_result.status != 0) { + // TODO: extract instead of failing + std.debug.panic("failed to run squashfuse", .{}); + } + } + + const overlayfs_options = try std.fmt.allocPrintZ(allocator, "lowerdir={s},upperdir={s}/upper,workdir={s}/work", .{ filesystem_bundle_dir_null, temp_dir_path, temp_dir_path, @@ -212,8 +216,17 @@ pub fn main() !void { try tmpDir.makeDir("work"); try tmpDir.makeDir("mount"); - var overlayfsProcess = std.process.Child.init(&[_][]const u8{ overlayfs_path, "-o", overlayfs_options, mount_dir_path }, allocator); - _ = try overlayfsProcess.spawnAndWait(); + const overlayfs_args = [_:null]?[*:0]const u8{ "fuse-overlayfs", "-o", overlayfs_options, mount_dir_path }; + + const pid = try std.posix.fork(); + if (pid == 0) { + std.process.exit(@intCast(overlayfs_main(overlayfs_args.len, &overlayfs_args))); + } + + const wait_pid_result = std.posix.waitpid(pid, 0); + if (wait_pid_result.status != 0) { + std.debug.panic("failed to run overlayfs", .{}); + } const rootfs_absolute_path = try std.fmt.allocPrint(allocator, "{s}/mount/rootfs", .{temp_dir_path}); defer allocator.free(rootfs_absolute_path); diff --git a/src/tools/fuse-overlayfs b/src/tools/fuse-overlayfs deleted file mode 100644 index 385ff91..0000000 --- a/src/tools/fuse-overlayfs +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0011ad825dc0274b6e330fb9a8d3d578ea7bbf738bab08934b90be070b8d0a4a -size 1785448 diff --git a/src/tools/squashfuse b/src/tools/squashfuse deleted file mode 100755 index f65dcba..0000000 --- a/src/tools/squashfuse +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2acf6d8609125c68008df48e5febafb98730be116f257a218ccfc2ff8b03832d -size 1836456