From 5c46c77df6a5f8e8185ed78ad2e495cc7b4a3eca Mon Sep 17 00:00:00 2001 From: Stephen Gregoratto Date: Tue, 17 Sep 2024 20:51:14 +1000 Subject: [PATCH 1/6] Rewrite `generate_linux_syscalls` to be completely table based Changes by Arnd Bergmann have migrated all supported architectures to use a table for their syscall lists. This removes the need of calling a C pre-processor and simplifies the logic dramatically. --- tools/generate_linux_syscalls.zig | 828 +++++++----------------------- 1 file changed, 196 insertions(+), 632 deletions(-) diff --git a/tools/generate_linux_syscalls.zig b/tools/generate_linux_syscalls.zig index df1b5127dfb8..d0f982d6f2a4 100644 --- a/tools/generate_linux_syscalls.zig +++ b/tools/generate_linux_syscalls.zig @@ -1,7 +1,7 @@ //! To get started, run this tool with no args and read the help message. //! -//! This tool extracts the Linux syscall numbers from the Linux source tree -//! directly, and emits an enumerated list per supported Zig arch. +//! This tool extracts syscall numbers from the Linux source tree +//! and emits an enumerated list per arch. const std = @import("std"); const mem = std.mem; @@ -26,676 +26,240 @@ const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{ .{ "mmap_pgoff", "mmap2" }, }); -// Only for newer architectures where we use the C preprocessor. -const stdlib_renames_new = std.StaticStringMap([]const u8).initComptime(.{ - .{ "newuname", "uname" }, - .{ "umount", "umount2" }, -}); - -// We use this to deal with the fact that multiple syscalls can be mapped to sys_ni_syscall. -// Thankfully it's only 2 well-known syscalls in newer kernel ports at the moment. -fn getOverridenNameNew(value: []const u8) ?[]const u8 { - if (mem.eql(u8, value, "18")) { - return "sys_lookup_dcookie"; - } else if (mem.eql(u8, value, "42")) { - return "sys_nfsservctl"; - } else { - return null; - } -} - -fn isReservedNameOld(name: []const u8) bool { +/// Filter syscalls that aren't actually syscalls. +fn isReserved(name: []const u8) bool { return std.mem.startsWith(u8, name, "available") or std.mem.startsWith(u8, name, "reserved") or std.mem.startsWith(u8, name, "unused"); } -const default_args: []const []const u8 = &.{ - "-E", - // -dM is cleaner, but -dD preserves iteration order. - "-dD", - // No need for line-markers. - "-P", - "-nostdinc", - // Using -I=[dir] includes the zig linux headers, which we don't want. - "-Itools/include", - "-Itools/include/uapi", - // Output the syscall in a format we can easily recognize. - "-D __SYSCALL(nr, nm)=zigsyscall nm nr", -}; - -const ProcessPreprocessedFileFn = *const fn (bytes: []const u8, writer: anytype) anyerror!void; -const ProcessTableBasedArchFileFn = *const fn ( - bytes: []const u8, - filters: Filters, - writer: anytype, - optional_writer: anytype, -) anyerror!void; - -const FlowControl = enum { - @"break", - @"continue", - none, -}; - -const AbiCheckParams = struct { abi: []const u8, flow: FlowControl }; - -const Filters = struct { - abiCheckParams: ?AbiCheckParams, - fixedName: ?*const fn (name: []const u8) []const u8, - isReservedNameOld: ?*const fn (name: []const u8) bool, -}; - -fn abiCheck(abi: []const u8, params: *const AbiCheckParams) FlowControl { - if (mem.eql(u8, abi, params.abi)) return params.flow; - return .none; +fn abiGen(comptime fields: []const []const u8) fn ([]const u8) bool { + const common = [_][]const u8{"common"} ++ fields; + return struct { + fn gen(abi: []const u8) bool { + for (common) |f| + if (mem.eql(u8, abi, f)) return true; + return false; + } + }.gen; } -fn fixedName(name: []const u8) []const u8 { - return if (stdlib_renames.get(name)) |fixed| fixed else name; +/// Used when the abi column is the same value. +fn everythingAbi(_: []const u8) bool { + return true; } - -const ArchInfo = union(enum) { - table: struct { - name: []const u8, - enum_name: []const u8, - file_path: []const u8, - header: ?[]const u8, - extra_values: ?[]const u8, - process_file: ProcessTableBasedArchFileFn, - filters: Filters, - additional_enum: ?[]const u8, - }, - preprocessor: struct { - name: []const u8, - enum_name: []const u8, - file_path: []const u8, - child_options: struct { - comptime additional_args: ?[]const []const u8 = null, - target: []const u8, - - pub inline fn getArgs(self: *const @This(), zig_exe: []const u8, file_path: []const u8) []const []const u8 { - const additional_args: []const []const u8 = self.additional_args orelse &.{}; - return .{ zig_exe, "cc" } ++ additional_args ++ .{ "-target", self.target } ++ default_args ++ .{file_path}; - } - }, - header: ?[]const u8, - extra_values: ?[]const u8, - process_file: ProcessPreprocessedFileFn, - additional_enum: ?[]const u8, - }, -}; - -const arch_infos = [_]ArchInfo{ - .{ - // These architectures have their syscall definitions generated from a TSV - // file, processed via scripts/syscallhdr.sh. - .table = .{ - .name = "x86", - .enum_name = "X86", - .file_path = "arch/x86/entry/syscalls/syscall_32.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - .abiCheckParams = null, - .fixedName = &fixedName, - .isReservedNameOld = null, - }, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "x64", - .enum_name = "X64", - .file_path = "arch/x86/entry/syscalls/syscall_64.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - // The x32 abi syscalls are always at the end. - .abiCheckParams = .{ .abi = "x32", .flow = .@"break" }, - .fixedName = &fixedName, - .isReservedNameOld = null, - }, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "arm", - .enum_name = "Arm", - .file_path = "arch/arm/tools/syscall.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - .abiCheckParams = .{ .abi = "oabi", .flow = .@"continue" }, - .fixedName = &fixedName, - .isReservedNameOld = null, - }, - .header = " const arm_base = 0x0f0000;\n\n", - // TODO: maybe extract these from arch/arm/include/uapi/asm/unistd.h - .extra_values = - \\ - \\ breakpoint = arm_base + 1, - \\ cacheflush = arm_base + 2, - \\ usr26 = arm_base + 3, - \\ usr32 = arm_base + 4, - \\ set_tls = arm_base + 5, - \\ get_tls = arm_base + 6, - \\ - , - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "sparc", - .enum_name = "Sparc", - .file_path = "arch/sparc/kernel/syscalls/syscall.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - .abiCheckParams = .{ .abi = "64", .flow = .@"continue" }, - .fixedName = &fixedName, - .isReservedNameOld = null, - }, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "sparc64", - .enum_name = "Sparc64", - .file_path = "arch/sparc/kernel/syscalls/syscall.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - .abiCheckParams = .{ .abi = "32", .flow = .@"continue" }, - .fixedName = &fixedName, - .isReservedNameOld = null, - }, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "m68k", - .enum_name = "M68k", - .file_path = "arch/m68k/kernel/syscalls/syscall.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - // abi is always common - .abiCheckParams = null, - .fixedName = &fixedName, - .isReservedNameOld = null, - }, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "mips_o32", - .enum_name = "MipsO32", - .file_path = "arch/mips/kernel/syscalls/syscall_o32.tbl", - .process_file = &processMipsBasedArch, - .filters = .{ - // abi is always o32 - .abiCheckParams = null, - .fixedName = &fixedName, - .isReservedNameOld = &isReservedNameOld, - }, - .header = " const linux_base = 4000;\n\n", - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "mips_n64", - .enum_name = "MipsN64", - .file_path = "arch/mips/kernel/syscalls/syscall_n64.tbl", - .process_file = &processMipsBasedArch, - .filters = .{ - // abi is always n64 - .abiCheckParams = null, - .fixedName = &fixedName, - .isReservedNameOld = &isReservedNameOld, - }, - .header = " const linux_base = 5000;\n\n", - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "mips_n32", - .enum_name = "MipsN32", - .file_path = "arch/mips/kernel/syscalls/syscall_n32.tbl", - .process_file = &processMipsBasedArch, - .filters = .{ - // abi is always n32 - .abiCheckParams = null, - .fixedName = &fixedName, - .isReservedNameOld = &isReservedNameOld, - }, - .header = " const linux_base = 6000;\n\n", - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "powerpc", - .enum_name = "PowerPC", - .file_path = "arch/powerpc/kernel/syscalls/syscall.tbl", - .process_file = &processPowerPcBasedArch, - .filters = .{ - .abiCheckParams = null, - .fixedName = null, - .isReservedNameOld = null, - }, - .header = null, - .extra_values = null, - .additional_enum = "PowerPC64", - }, - }, - .{ - .table = .{ - .name = "s390x", - .enum_name = "S390x", - .file_path = "arch/s390/kernel/syscalls/syscall.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - // 32-bit s390 support in linux is deprecated - .abiCheckParams = .{ .abi = "32", .flow = .@"continue" }, - .fixedName = &fixedName, - .isReservedNameOld = null, - }, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .table = .{ - .name = "xtensa", - .enum_name = "Xtensa", - .file_path = "arch/xtensa/kernel/syscalls/syscall.tbl", - .process_file = &processTableBasedArch, - .filters = .{ - // abi is always common - .abiCheckParams = null, - .fixedName = fixedName, - .isReservedNameOld = &isReservedNameOld, - }, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .preprocessor = .{ - .name = "arm64", - .enum_name = "Arm64", - .file_path = "arch/arm64/include/uapi/asm/unistd.h", - .child_options = .{ - .additional_args = null, - .target = "aarch64-freestanding-none", - }, - .process_file = &processPreprocessedFile, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, +/// "common" or "32" +const abi32 = abiGen(&.{"32"}); +/// "common" or "64" +const abi64 = abiGen(&.{"64"}); +/// "common" or "eabi" +const abiArm = abiGen(&.{"eabi"}); +/// "common", "32" or "nospu" +const abiPpc32 = abiGen(&.{ "32", "nospu" }); +/// "common", "64" or "nospu" +const abiPpc64 = abiGen(&.{ "64", "nospu" }); + +/// These architectures have custom syscall numbers defined in arch-specific tables. +const specific = [_]struct { + var_name: []const u8, + table: []const u8, + abi: *const fn (abi: []const u8) bool, + header: ?[]const u8 = null, + footer: ?[]const u8 = null, +}{ + .{ .var_name = "X86", .table = "arch/x86/entry/syscalls/syscall_32.tbl", .abi = everythingAbi }, + .{ .var_name = "X64", .table = "arch/x86/entry/syscalls/syscall_64.tbl", .abi = abi64 }, .{ - .preprocessor = .{ - .name = "riscv32", - .enum_name = "RiscV32", - .file_path = "arch/riscv/include/uapi/asm/unistd.h", - .child_options = .{ - .additional_args = null, - .target = "riscv32-freestanding-none", - }, - .process_file = &processPreprocessedFile, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .preprocessor = .{ - .name = "riscv64", - .enum_name = "RiscV64", - .file_path = "arch/riscv/include/uapi/asm/unistd.h", - .child_options = .{ - .additional_args = null, - .target = "riscv64-freestanding-none", - }, - .process_file = &processPreprocessedFile, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .preprocessor = .{ - .name = "loongarch", - .enum_name = "LoongArch64", - .file_path = "arch/loongarch/include/uapi/asm/unistd.h", - .child_options = .{ - .additional_args = null, - .target = "loongarch64-freestanding-none", - }, - .process_file = &processPreprocessedFile, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .preprocessor = .{ - .name = "arc", - .enum_name = "Arc", - .file_path = "arch/arc/include/uapi/asm/unistd.h", - .child_options = .{ - .additional_args = null, - .target = "arc-freestanding-none", - }, - .process_file = &processPreprocessedFile, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .preprocessor = .{ - .name = "csky", - .enum_name = "CSky", - .file_path = "arch/csky/include/uapi/asm/unistd.h", - .child_options = .{ - .additional_args = null, - .target = "csky-freestanding-none", - }, - .process_file = &processPreprocessedFile, - .header = null, - .extra_values = null, - .additional_enum = null, - }, - }, - .{ - .preprocessor = .{ - .name = "hexagon", - .enum_name = "Hexagon", - .file_path = "arch/hexagon/include/uapi/asm/unistd.h", - .child_options = .{ - .additional_args = null, - .target = "hexagon-freestanding-none", - }, - .process_file = &processPreprocessedFile, - .header = null, - .extra_values = null, - .additional_enum = null, - }, + .var_name = "Arm", + .table = "arch/arm/tools/syscall.tbl", + .abi = abiArm, + // TODO: These values haven't been brought over from `arch/arm/include/uapi/asm/unistd.h`. + .header = " const arm_base = 0x0f0000;\n\n", + .footer = + \\ + \\ breakpoint = arm_base + 1, + \\ cacheflush = arm_base + 2, + \\ usr26 = arm_base + 3, + \\ usr32 = arm_base + 4, + \\ set_tls = arm_base + 5, + \\ get_tls = arm_base + 6, + \\ + , }, + .{ .var_name = "Sparc", .table = "arch/sparc/kernel/syscalls/syscall.tbl", .abi = abi32 }, + .{ .var_name = "Sparc64", .table = "arch/sparc/kernel/syscalls/syscall.tbl", .abi = abi64 }, + .{ .var_name = "M68k", .table = "arch/m68k/kernel/syscalls/syscall.tbl", .abi = everythingAbi }, + .{ .var_name = "PowerPC", .table = "arch/powerpc/kernel/syscalls/syscall.tbl", .abi = abiPpc32 }, + .{ .var_name = "PowerPC64", .table = "arch/powerpc/kernel/syscalls/syscall.tbl", .abi = abiPpc64 }, + .{ .var_name = "S390x", .table = "arch/s390/kernel/syscalls/syscall.tbl", .abi = abi64 }, + .{ .var_name = "Xtensa", .table = "arch/xtensa/kernel/syscalls/syscall.tbl", .abi = everythingAbi }, + // TODO: Enable these when a backend is available + // .{ .var_name = "SuperH", .table = "arch/sh/kernel/syscalls/syscall.tbl", .abi = everythingAbi }, + // .{ .var_name = "Alpha", .table = "arch/alpha/kernel/syscalls/syscall.tbl", .abi = everythingAbi }, + // .{ .var_name = "PARisc", .table = "arch/parisc/kernel/syscalls/syscall.tbl", .abi = abi32 }, + // .{ .var_name = "PARisc64", .table = "arch/parisc/kernel/syscalls/syscall.tbl", .abi = abi64 }, }; -fn processPreprocessedFile( - bytes: []const u8, - writer: anytype, -) !void { - var lines = mem.tokenizeScalar(u8, bytes, '\n'); - while (lines.next()) |line| { - var fields = mem.tokenizeAny(u8, line, " "); - const prefix = fields.next() orelse return error.Incomplete; +/// The MIPS-based architectures are similar to the specific ones, except that the abi +/// is always the same and syscall numbers are offset by a number specific to the arch. +const mips = [_]struct { + var_name: []const u8, + table: []const u8, + base: usize, +}{ + .{ .var_name = "MipsO32", .table = "arch/mips/kernel/syscalls/syscall_o32.tbl", .base = 4000 }, + .{ .var_name = "MipsN64", .table = "arch/mips/kernel/syscalls/syscall_n64.tbl", .base = 5000 }, + .{ .var_name = "MipsN32", .table = "arch/mips/kernel/syscalls/syscall_n32.tbl", .base = 6000 }, +}; - if (!mem.eql(u8, prefix, "zigsyscall")) continue; +/// These architectures have their syscall numbers defined using the generic syscall +/// list introduced in c. 2012 for AArch64. +/// The 6.11 release converted this list into a single table, where parts of the +/// syscall ABI are enabled based on the presence of certain abi fields: +/// - 32: Syscalls using 64-bit types on 32-bit targets. +/// - 64: 64-bit native syscalls. +/// - time32: 32-bit time syscalls. +/// - renameat: Supports the older renameat syscall along with renameat2. +/// - rlimit: Supports the {get,set}rlimit syscalls. +/// - memfd_secret: Has an implementation of `memfd_secret`. +/// +/// Arch-specfic syscalls between [244...259] are also enabled by adding the arch name as an abi. +/// +/// The abi fields are sourced from the respectiev `arch/{arch}/kernel/Makefile.syscalls` files +/// in the kernel tree. +const generic = [_]struct { + var_name: []const u8, + abi: *const fn (abi: []const u8) bool, +}{ + .{ .var_name = "Arm64", .abi = abiGen(&.{ "64", "renameat", "rlimit", "memfd_secret" }) }, + .{ .var_name = "RiscV32", .abi = abiGen(&.{ "32", "riscv", "memfd_secret" }) }, + .{ .var_name = "RiscV64", .abi = abiGen(&.{ "64", "riscv", "rlimit", "memfd_secret" }) }, + .{ .var_name = "LoongArch64", .abi = abi64 }, + .{ .var_name = "Arc", .abi = abiGen(&.{ "32", "arc", "time32", "renameat", "stat64", "rlimit" }) }, + .{ .var_name = "CSky", .abi = abiGen(&.{ "32", "csky", "time32", "stat64", "rlimit" }) }, + .{ .var_name = "Hexagon", .abi = abiGen(&.{ "32", "hexagon", "time32", "stat64", "rlimit", "renameat" }) }, + // .{ .var_name = "OpenRisc", .abi = abiGen(&.{ "32", "or1k", "time32", "stat64", "rlimit", "renameat" }) }, + // .{ .var_name = "Nios2", .abi = abiGen(&.{ "32", "nios2", "time32", "stat64", "renameat", "rlimit" }) }, +}; +const generic_table = "scripts/syscall.tbl"; - const sys_name = fields.next() orelse return error.Incomplete; - const value = fields.rest(); - const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..]; - const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name; +fn splitLine(line: []const u8) [3][]const u8 { + var fields = mem.tokenizeAny(u8, line, " \t"); + const number = fields.next() orelse @panic("Bad field"); + const abi = fields.next() orelse @panic("Bad field"); + const name = fields.next() orelse @panic("Bad field"); - try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value }); - } + return .{ number, abi, name }; } -fn processTableBasedArch( - bytes: []const u8, - filters: Filters, - writer: anytype, - optional_writer: anytype, -) !void { - _ = optional_writer; - - var lines = mem.tokenizeScalar(u8, bytes, '\n'); - while (lines.next()) |line| { - if (line[0] == '#') continue; - - var fields = mem.tokenizeAny(u8, line, " \t"); - const number = fields.next() orelse return error.Incomplete; - - const abi = fields.next() orelse return error.Incomplete; - if (filters.abiCheckParams) |*params| { - switch (abiCheck(abi, params)) { - .none => {}, - .@"break" => break, - .@"continue" => continue, - } - } - const name = fields.next() orelse return error.Incomplete; - if (filters.isReservedNameOld) |isReservedNameOldFn| { - if (isReservedNameOldFn(name)) continue; - } - const fixed_name = if (filters.fixedName) |fixedNameFn| fixedNameFn(name) else name; - - try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number }); - } -} +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + const allocator = arena.allocator(); -fn processMipsBasedArch( - bytes: []const u8, - filters: Filters, - writer: anytype, - optional_writer: anytype, -) !void { - _ = optional_writer; - - var lines = mem.tokenizeScalar(u8, bytes, '\n'); - while (lines.next()) |line| { - if (line[0] == '#') continue; - - var fields = mem.tokenizeAny(u8, line, " \t"); - const number = fields.next() orelse return error.Incomplete; - - const abi = fields.next() orelse return error.Incomplete; - if (filters.abiCheckParams) |*params| { - switch (abiCheck(abi, params)) { - .none => {}, - .@"break" => break, - .@"continue" => continue, - } - } - const name = fields.next() orelse return error.Incomplete; - if (filters.isReservedNameOld) |isReservedNameOldFn| { - if (isReservedNameOldFn(name)) continue; - } - const fixed_name = if (filters.fixedName) |fixedNameFn| fixedNameFn(name) else name; + const args = try std.process.argsAlloc(allocator); + if (args.len < 2 or mem.eql(u8, args[1], "--help")) + usageAndExit(std.io.getStdErr(), args[0], 1); + const linux_path = args[1]; - try writer.print(" {p} = linux_base + {s},\n", .{ zig.fmtId(fixed_name), number }); - } -} + var buf_out = std.io.bufferedWriter(std.io.getStdOut().writer()); + const writer = buf_out.writer(); -fn processPowerPcBasedArch( - bytes: []const u8, - filters: Filters, - writer: anytype, - optional_writer: anytype, -) !void { - _ = filters; - var lines = mem.tokenizeScalar(u8, bytes, '\n'); - - while (lines.next()) |line| { - if (line[0] == '#') continue; - - var fields = mem.tokenizeAny(u8, line, " \t"); - const number = fields.next() orelse return error.Incomplete; - const abi = fields.next() orelse return error.Incomplete; - const name = fields.next() orelse return error.Incomplete; - const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name; - - if (mem.eql(u8, abi, "spu")) { - continue; - } else if (mem.eql(u8, abi, "32")) { - try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number }); - } else if (mem.eql(u8, abi, "64")) { - try optional_writer.?.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number }); - } else { // common/nospu - try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number }); - try optional_writer.?.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number }); - } - } -} + var linux_dir = try std.fs.cwd().openDir(linux_path, .{}); + defer linux_dir.close(); -fn generateSyscallsFromTable( - allocator: std.mem.Allocator, - buf: []u8, - linux_dir: std.fs.Dir, - writer: anytype, - _arch_info: *const ArchInfo, -) !void { - std.debug.assert(_arch_info.* == .table); + // As of 6.11, the largest table is 24195 bytes. + // 32k should be enough for now. + const buf = try allocator.alloc(u8, 1 << 15); + defer allocator.free(buf); - const arch_info = _arch_info.table; + // Fetch the kernel version from the Makefile variables. + const version = blk: { + const head = try linux_dir.readFile("Makefile", buf[0..128]); + var lines = mem.tokenizeScalar(u8, head, '\n'); + _ = lines.next(); // Skip SPDX identifier + + var ver = mem.zeroes(std.SemanticVersion); + inline for (.{ "major", "minor", "patch" }, .{ "VERSION", "PATCHLEVEL", "SUBLEVEL" }) |f, v| { + const line = lines.next() orelse @panic("Bad line"); + const offset = (v ++ " = ").len; + @field(ver, f) = try fmt.parseInt(usize, line[offset..], 10); + } - const table = try linux_dir.readFile(arch_info.file_path, buf); + break :blk ver; + }; - var optional_array_list: ?std.ArrayList(u8) = if (arch_info.additional_enum) |_| std.ArrayList(u8).init(allocator) else null; - const optional_writer = if (optional_array_list) |_| optional_array_list.?.writer() else null; + try writer.print( + \\// This file is automatically generated, DO NOT edit it manually. + \\// See tools/generate_linux_syscalls.zig for more info. + \\// This list current as of kernel: {} + \\ + \\ + , .{version}); - try writer.print("pub const {s} = enum(usize) {{\n", .{arch_info.enum_name}); + const trailing = "};\n\n"; + for (specific) |arch| { + try writer.print("pub const {s} = enum(usize) {{\n", .{arch.var_name}); + if (arch.header) |h| + try writer.writeAll(h); + const table = try linux_dir.readFile(arch.table, buf); - if (arch_info.header) |header| { - try writer.writeAll(header); - } + var lines = mem.tokenizeScalar(u8, table, '\n'); + while (lines.next()) |line| { + if (line[0] == '#') continue; + const number, const abi, const name = splitLine(line); - try arch_info.process_file(table, arch_info.filters, writer, optional_writer); + if (!arch.abi(abi)) continue; + if (isReserved(name)) continue; - if (arch_info.extra_values) |extra_values| { - try writer.writeAll(extra_values); + const final_name = stdlib_renames.get(name) orelse name; + try writer.print(" {p} = {s},\n", .{ zig.fmtId(final_name), number }); + } + if (arch.footer) |f| + try writer.writeAll(f); + try writer.writeAll(trailing); } - try writer.writeAll("};"); - if (arch_info.additional_enum) |additional_enum| { - try writer.writeAll("\n\n"); - try writer.print("pub const {s} = enum(usize) {{\n", .{additional_enum}); - try writer.writeAll(optional_array_list.?.items); - try writer.writeAll("};"); - } -} + for (mips) |arch| { + try writer.print( + \\pub const {s} = enum(usize) {{ + \\ const linux_base = {d}; + \\ + \\ + , .{ arch.var_name, arch.base }); + const table = try linux_dir.readFile(arch.table, buf); -fn generateSyscallsFromPreprocessor( - allocator: std.mem.Allocator, - linux_dir: std.fs.Dir, - linux_path: []const u8, - zig_exe: []const u8, - writer: anytype, - _arch_info: *const ArchInfo, -) !void { - std.debug.assert(_arch_info.* == .preprocessor); - - const arch_info = _arch_info.preprocessor; - - const child_result = try std.process.Child.run(.{ - .allocator = allocator, - .argv = arch_info.child_options.getArgs(zig_exe, arch_info.file_path), - .cwd = linux_path, - .cwd_dir = linux_dir, - }); - if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr}); - - const defines = switch (child_result.term) { - .Exited => |code| if (code == 0) child_result.stdout else { - std.debug.print("zig cc exited with code {d}\n", .{code}); - std.process.exit(1); - }, - else => { - std.debug.print("zig cc crashed\n", .{}); - std.process.exit(1); - }, - }; + var lines = mem.tokenizeScalar(u8, table, '\n'); + while (lines.next()) |line| { + if (line[0] == '#') continue; + const number, _, const name = splitLine(line); - try writer.print("pub const {s} = enum(usize) {{\n", .{arch_info.enum_name}); - if (arch_info.header) |header| { - try writer.writeAll(header); - } + if (isReserved(name)) continue; - try arch_info.process_file(defines, writer); + const final_name = stdlib_renames.get(name) orelse name; + try writer.print(" {p} = linux_base + {s},\n", .{ zig.fmtId(final_name), number }); + } - if (arch_info.extra_values) |extra_values| { - try writer.writeAll(extra_values); + try writer.writeAll(trailing); } - try writer.writeAll("};"); -} - -pub fn main() !void { - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena.deinit(); - const allocator = arena.allocator(); - - const args = try std.process.argsAlloc(allocator); - if (args.len < 3 or mem.eql(u8, args[1], "--help")) - usageAndExit(std.io.getStdErr(), args[0], 1); - const zig_exe = args[1]; - const linux_path = args[2]; - - var buf_out = std.io.bufferedWriter(std.io.getStdOut().writer()); - const writer = buf_out.writer(); + const table = try linux_dir.readFile(generic_table, buf); + for (generic, 0..) |arch, i| { + try writer.print("pub const {s} = enum(usize) {{\n", .{arch.var_name}); - var linux_dir = try std.fs.cwd().openDir(linux_path, .{}); - defer linux_dir.close(); + var lines = mem.tokenizeScalar(u8, table, '\n'); + while (lines.next()) |line| { + if (line[0] == '#') continue; + const number, const abi, const name = splitLine(line); - try writer.writeAll( - \\// This file is automatically generated. - \\// See tools/generate_linux_syscalls.zig for more info. - \\ - \\ - ); + if (!arch.abi(abi)) continue; + if (isReserved(name)) continue; - // As of 5.17.1, the largest table is 23467 bytes. - // 32k should be enough for now. - const buf = try allocator.alloc(u8, 1 << 15); - defer allocator.free(buf); - - inline for (arch_infos, 0..) |arch_info, i| { - switch (arch_info) { - .table => try generateSyscallsFromTable( - allocator, - buf, - linux_dir, - writer, - &arch_info, - ), - .preprocessor => try generateSyscallsFromPreprocessor( - allocator, - linux_dir, - linux_path, - zig_exe, - writer, - &arch_info, - ), - } - if (i < arch_infos.len - 1) { - try writer.writeAll("\n\n"); - } else { - try writer.writeAll("\n"); + const final_name = stdlib_renames.get(name) orelse name; + try writer.print(" {p} = {s},\n", .{ zig.fmtId(final_name), number }); } + + try writer.writeAll(trailing[0 .. 3 + @as(usize, @intFromBool(i < generic.len - 1))]); } try buf_out.flush(); From 5a4e51daaf47e3ca436e41e8ed1ca2a7efb64576 Mon Sep 17 00:00:00 2001 From: Stephen Gregoratto Date: Tue, 17 Sep 2024 21:00:10 +1000 Subject: [PATCH 2/6] Syscalls: Update list for 6.11 The generic syscall table has different names for syscalls that take a timespec64 on 32-bit targets, in that it adds the `_time64` suffix. Similarly, the `_time32` suffix has been removed. I'm not sure if the existing logic for determining the proper timespec struct to use was subtly broken, but it should be a good chance to finish #4726 - we only have 14 years after all... In other news: - x86_64 gets `uretprobe`, a syscall to speed up returning BPF probes. - Hexagon gets `clone3`, but don't be fooled: it just returns ENOSYS. --- lib/std/os/linux/syscalls.zig | 343 +++++++++++++++++----------------- 1 file changed, 174 insertions(+), 169 deletions(-) diff --git a/lib/std/os/linux/syscalls.zig b/lib/std/os/linux/syscalls.zig index ef04387ea62d..41cfb421531b 100644 --- a/lib/std/os/linux/syscalls.zig +++ b/lib/std/os/linux/syscalls.zig @@ -1,5 +1,6 @@ -// This file is automatically generated. +// This file is automatically generated, DO NOT edit it manually. // See tools/generate_linux_syscalls.zig for more info. +// This list current as of kernel: 6.11.0 pub const X86 = enum(usize) { restart_syscall = 0, @@ -792,6 +793,7 @@ pub const X64 = enum(usize) { statx = 332, io_pgetevents = 333, rseq = 334, + uretprobe = 335, pidfd_send_signal = 424, io_uring_setup = 425, io_uring_enter = 426, @@ -5431,7 +5433,7 @@ pub const Arm64 = enum(usize) { pwrite64 = 68, preadv = 69, pwritev = 70, - sendfile64 = 71, + sendfile = 71, pselect6 = 72, ppoll = 73, signalfd4 = 74, @@ -5440,7 +5442,7 @@ pub const Arm64 = enum(usize) { tee = 77, readlinkat = 78, fstatat64 = 79, - fstat64 = 80, + fstat = 80, sync = 81, fsync = 82, fdatasync = 83, @@ -5583,7 +5585,7 @@ pub const Arm64 = enum(usize) { clone = 220, execve = 221, mmap = 222, - fadvise64_64 = 223, + fadvise64 = 223, swapon = 224, swapoff = 225, mprotect = 226, @@ -5897,6 +5899,8 @@ pub const RiscV32 = enum(usize) { rt_tgsigqueueinfo = 240, perf_event_open = 241, accept4 = 242, + riscv_hwprobe = 258, + riscv_flush_icache = 259, prlimit64 = 261, fanotify_init = 262, fanotify_mark = 263, @@ -5929,26 +5933,26 @@ pub const RiscV32 = enum(usize) { statx = 291, rseq = 293, kexec_file_load = 294, - clock_gettime = 403, - clock_settime = 404, - clock_adjtime = 405, - clock_getres = 406, - clock_nanosleep = 407, - timer_gettime = 408, - timer_settime = 409, - timerfd_gettime = 410, - timerfd_settime = 411, - utimensat = 412, - pselect6 = 413, - ppoll = 414, - io_pgetevents = 416, - recvmmsg = 417, - mq_timedsend = 418, - mq_timedreceive = 419, - semtimedop = 420, - rt_sigtimedwait = 421, - futex = 422, - sched_rr_get_interval = 423, + clock_gettime64 = 403, + clock_settime64 = 404, + clock_adjtime64 = 405, + clock_getres_time64 = 406, + clock_nanosleep_time64 = 407, + timer_gettime64 = 408, + timer_settime64 = 409, + timerfd_gettime64 = 410, + timerfd_settime64 = 411, + utimensat_time64 = 412, + pselect6_time64 = 413, + ppoll_time64 = 414, + io_pgetevents_time64 = 416, + recvmmsg_time64 = 417, + mq_timedsend_time64 = 418, + mq_timedreceive_time64 = 419, + semtimedop_time64 = 420, + rt_sigtimedwait_time64 = 421, + futex_time64 = 422, + sched_rr_get_interval_time64 = 423, pidfd_send_signal = 424, io_uring_setup = 425, io_uring_enter = 426, @@ -5988,8 +5992,6 @@ pub const RiscV32 = enum(usize) { lsm_set_self_attr = 460, lsm_list_modules = 461, mseal = 462, - riscv_flush_icache = (244 + 15), - riscv_hwprobe = (244 + 14), }; pub const RiscV64 = enum(usize) { @@ -6063,7 +6065,7 @@ pub const RiscV64 = enum(usize) { pwrite64 = 68, preadv = 69, pwritev = 70, - sendfile64 = 71, + sendfile = 71, pselect6 = 72, ppoll = 73, signalfd4 = 74, @@ -6072,7 +6074,7 @@ pub const RiscV64 = enum(usize) { tee = 77, readlinkat = 78, fstatat64 = 79, - fstat64 = 80, + fstat = 80, sync = 81, fsync = 82, fdatasync = 83, @@ -6215,7 +6217,7 @@ pub const RiscV64 = enum(usize) { clone = 220, execve = 221, mmap = 222, - fadvise64_64 = 223, + fadvise64 = 223, swapon = 224, swapoff = 225, mprotect = 226, @@ -6236,6 +6238,8 @@ pub const RiscV64 = enum(usize) { perf_event_open = 241, accept4 = 242, recvmmsg = 243, + riscv_hwprobe = 258, + riscv_flush_icache = 259, wait4 = 260, prlimit64 = 261, fanotify_init = 262, @@ -6310,8 +6314,6 @@ pub const RiscV64 = enum(usize) { lsm_set_self_attr = 460, lsm_list_modules = 461, mseal = 462, - riscv_flush_icache = (244 + 15), - riscv_hwprobe = (244 + 14), }; pub const LoongArch64 = enum(usize) { @@ -6385,7 +6387,7 @@ pub const LoongArch64 = enum(usize) { pwrite64 = 68, preadv = 69, pwritev = 70, - sendfile64 = 71, + sendfile = 71, pselect6 = 72, ppoll = 73, signalfd4 = 74, @@ -6393,6 +6395,8 @@ pub const LoongArch64 = enum(usize) { splice = 76, tee = 77, readlinkat = 78, + fstatat64 = 79, + fstat = 80, sync = 81, fsync = 82, fdatasync = 83, @@ -6533,7 +6537,7 @@ pub const LoongArch64 = enum(usize) { clone = 220, execve = 221, mmap = 222, - fadvise64_64 = 223, + fadvise64 = 223, swapon = 224, swapoff = 225, mprotect = 226, @@ -6634,7 +6638,7 @@ pub const Arc = enum(usize) { io_destroy = 1, io_submit = 2, io_cancel = 3, - io_getevents_time32 = 4, + io_getevents = 4, setxattr = 5, lsetxattr = 6, fsetxattr = 7, @@ -6702,8 +6706,8 @@ pub const Arc = enum(usize) { preadv = 69, pwritev = 70, sendfile64 = 71, - pselect6_time32 = 72, - ppoll_time32 = 73, + pselect6 = 72, + ppoll = 73, signalfd4 = 74, vmsplice = 75, splice = 76, @@ -6716,9 +6720,9 @@ pub const Arc = enum(usize) { fdatasync = 83, sync_file_range = 84, timerfd_create = 85, - timerfd_settime32 = 86, - timerfd_gettime32 = 87, - utimensat_time32 = 88, + timerfd_settime = 86, + timerfd_gettime = 87, + utimensat = 88, acct = 89, capget = 90, capset = 91, @@ -6728,24 +6732,24 @@ pub const Arc = enum(usize) { waitid = 95, set_tid_address = 96, unshare = 97, - futex_time32 = 98, + futex = 98, set_robust_list = 99, get_robust_list = 100, - nanosleep_time32 = 101, + nanosleep = 101, getitimer = 102, setitimer = 103, kexec_load = 104, init_module = 105, delete_module = 106, timer_create = 107, - timer_gettime32 = 108, + timer_gettime = 108, timer_getoverrun = 109, - timer_settime32 = 110, + timer_settime = 110, timer_delete = 111, - clock_settime32 = 112, - clock_gettime32 = 113, - clock_getres_time32 = 114, - clock_nanosleep_time32 = 115, + clock_settime = 112, + clock_gettime = 113, + clock_getres = 114, + clock_nanosleep = 115, syslog = 116, ptrace = 117, sched_setparam = 118, @@ -6757,7 +6761,7 @@ pub const Arc = enum(usize) { sched_yield = 124, sched_get_priority_max = 125, sched_get_priority_min = 126, - sched_rr_get_interval_time32 = 127, + sched_rr_get_interval = 127, restart_syscall = 128, kill = 129, tkill = 130, @@ -6767,7 +6771,7 @@ pub const Arc = enum(usize) { rt_sigaction = 134, rt_sigprocmask = 135, rt_sigpending = 136, - rt_sigtimedwait_time32 = 137, + rt_sigtimedwait = 137, rt_sigqueueinfo = 138, rt_sigreturn = 139, setpriority = 140, @@ -6801,7 +6805,7 @@ pub const Arc = enum(usize) { getcpu = 168, gettimeofday = 169, settimeofday = 170, - adjtimex_time32 = 171, + adjtimex = 171, getpid = 172, getppid = 173, getuid = 174, @@ -6812,8 +6816,8 @@ pub const Arc = enum(usize) { sysinfo = 179, mq_open = 180, mq_unlink = 181, - mq_timedsend_time32 = 182, - mq_timedreceive_time32 = 183, + mq_timedsend = 182, + mq_timedreceive = 183, mq_notify = 184, mq_getsetattr = 185, msgget = 186, @@ -6822,7 +6826,7 @@ pub const Arc = enum(usize) { msgsnd = 189, semget = 190, semctl = 191, - semtimedop_time32 = 192, + semtimedop = 192, semop = 193, shmget = 194, shmctl = 195, @@ -6873,14 +6877,19 @@ pub const Arc = enum(usize) { rt_tgsigqueueinfo = 240, perf_event_open = 241, accept4 = 242, - recvmmsg_time32 = 243, + recvmmsg = 243, + cacheflush = 244, + arc_settls = 245, + arc_gettls = 246, + sysfs = 247, + arc_usr_cmpxchg = 248, wait4 = 260, prlimit64 = 261, fanotify_init = 262, fanotify_mark = 263, name_to_handle_at = 264, open_by_handle_at = 265, - clock_adjtime32 = 266, + clock_adjtime = 266, syncfs = 267, setns = 268, sendmmsg = 269, @@ -6906,29 +6915,29 @@ pub const Arc = enum(usize) { pkey_alloc = 289, pkey_free = 290, statx = 291, - io_pgetevents_time32 = 292, + io_pgetevents = 292, rseq = 293, kexec_file_load = 294, - clock_gettime = 403, - clock_settime = 404, - clock_adjtime = 405, - clock_getres = 406, - clock_nanosleep = 407, - timer_gettime = 408, - timer_settime = 409, - timerfd_gettime = 410, - timerfd_settime = 411, - utimensat = 412, - pselect6 = 413, - ppoll = 414, - io_pgetevents = 416, - recvmmsg = 417, - mq_timedsend = 418, - mq_timedreceive = 419, - semtimedop = 420, - rt_sigtimedwait = 421, - futex = 422, - sched_rr_get_interval = 423, + clock_gettime64 = 403, + clock_settime64 = 404, + clock_adjtime64 = 405, + clock_getres_time64 = 406, + clock_nanosleep_time64 = 407, + timer_gettime64 = 408, + timer_settime64 = 409, + timerfd_gettime64 = 410, + timerfd_settime64 = 411, + utimensat_time64 = 412, + pselect6_time64 = 413, + ppoll_time64 = 414, + io_pgetevents_time64 = 416, + recvmmsg_time64 = 417, + mq_timedsend_time64 = 418, + mq_timedreceive_time64 = 419, + semtimedop_time64 = 420, + rt_sigtimedwait_time64 = 421, + futex_time64 = 422, + sched_rr_get_interval_time64 = 423, pidfd_send_signal = 424, io_uring_setup = 425, io_uring_enter = 426, @@ -6967,11 +6976,6 @@ pub const Arc = enum(usize) { lsm_set_self_attr = 460, lsm_list_modules = 461, mseal = 462, - cacheflush = (244 + 0), - arc_settls = (244 + 1), - arc_gettls = (244 + 2), - arc_usr_cmpxchg = (244 + 4), - sysfs = (244 + 3), }; pub const CSky = enum(usize) { @@ -6979,7 +6983,7 @@ pub const CSky = enum(usize) { io_destroy = 1, io_submit = 2, io_cancel = 3, - io_getevents_time32 = 4, + io_getevents = 4, setxattr = 5, lsetxattr = 6, fsetxattr = 7, @@ -7046,8 +7050,8 @@ pub const CSky = enum(usize) { preadv = 69, pwritev = 70, sendfile64 = 71, - pselect6_time32 = 72, - ppoll_time32 = 73, + pselect6 = 72, + ppoll = 73, signalfd4 = 74, vmsplice = 75, splice = 76, @@ -7060,9 +7064,9 @@ pub const CSky = enum(usize) { fdatasync = 83, sync_file_range = 84, timerfd_create = 85, - timerfd_settime32 = 86, - timerfd_gettime32 = 87, - utimensat_time32 = 88, + timerfd_settime = 86, + timerfd_gettime = 87, + utimensat = 88, acct = 89, capget = 90, capset = 91, @@ -7072,24 +7076,24 @@ pub const CSky = enum(usize) { waitid = 95, set_tid_address = 96, unshare = 97, - futex_time32 = 98, + futex = 98, set_robust_list = 99, get_robust_list = 100, - nanosleep_time32 = 101, + nanosleep = 101, getitimer = 102, setitimer = 103, kexec_load = 104, init_module = 105, delete_module = 106, timer_create = 107, - timer_gettime32 = 108, + timer_gettime = 108, timer_getoverrun = 109, - timer_settime32 = 110, + timer_settime = 110, timer_delete = 111, - clock_settime32 = 112, - clock_gettime32 = 113, - clock_getres_time32 = 114, - clock_nanosleep_time32 = 115, + clock_settime = 112, + clock_gettime = 113, + clock_getres = 114, + clock_nanosleep = 115, syslog = 116, ptrace = 117, sched_setparam = 118, @@ -7101,7 +7105,7 @@ pub const CSky = enum(usize) { sched_yield = 124, sched_get_priority_max = 125, sched_get_priority_min = 126, - sched_rr_get_interval_time32 = 127, + sched_rr_get_interval = 127, restart_syscall = 128, kill = 129, tkill = 130, @@ -7111,7 +7115,7 @@ pub const CSky = enum(usize) { rt_sigaction = 134, rt_sigprocmask = 135, rt_sigpending = 136, - rt_sigtimedwait_time32 = 137, + rt_sigtimedwait = 137, rt_sigqueueinfo = 138, rt_sigreturn = 139, setpriority = 140, @@ -7145,7 +7149,7 @@ pub const CSky = enum(usize) { getcpu = 168, gettimeofday = 169, settimeofday = 170, - adjtimex_time32 = 171, + adjtimex = 171, getpid = 172, getppid = 173, getuid = 174, @@ -7156,8 +7160,8 @@ pub const CSky = enum(usize) { sysinfo = 179, mq_open = 180, mq_unlink = 181, - mq_timedsend_time32 = 182, - mq_timedreceive_time32 = 183, + mq_timedsend = 182, + mq_timedreceive = 183, mq_notify = 184, mq_getsetattr = 185, msgget = 186, @@ -7166,7 +7170,7 @@ pub const CSky = enum(usize) { msgsnd = 189, semget = 190, semctl = 191, - semtimedop_time32 = 192, + semtimedop = 192, semop = 193, shmget = 194, shmctl = 195, @@ -7217,14 +7221,16 @@ pub const CSky = enum(usize) { rt_tgsigqueueinfo = 240, perf_event_open = 241, accept4 = 242, - recvmmsg_time32 = 243, + recvmmsg = 243, + set_thread_area = 244, + cacheflush = 245, wait4 = 260, prlimit64 = 261, fanotify_init = 262, fanotify_mark = 263, name_to_handle_at = 264, open_by_handle_at = 265, - clock_adjtime32 = 266, + clock_adjtime = 266, syncfs = 267, setns = 268, sendmmsg = 269, @@ -7250,29 +7256,29 @@ pub const CSky = enum(usize) { pkey_alloc = 289, pkey_free = 290, statx = 291, - io_pgetevents_time32 = 292, + io_pgetevents = 292, rseq = 293, kexec_file_load = 294, - clock_gettime = 403, - clock_settime = 404, - clock_adjtime = 405, - clock_getres = 406, - clock_nanosleep = 407, - timer_gettime = 408, - timer_settime = 409, - timerfd_gettime = 410, - timerfd_settime = 411, - utimensat = 412, - pselect6 = 413, - ppoll = 414, - io_pgetevents = 416, - recvmmsg = 417, - mq_timedsend = 418, - mq_timedreceive = 419, - semtimedop = 420, - rt_sigtimedwait = 421, - futex = 422, - sched_rr_get_interval = 423, + clock_gettime64 = 403, + clock_settime64 = 404, + clock_adjtime64 = 405, + clock_getres_time64 = 406, + clock_nanosleep_time64 = 407, + timer_gettime64 = 408, + timer_settime64 = 409, + timerfd_gettime64 = 410, + timerfd_settime64 = 411, + utimensat_time64 = 412, + pselect6_time64 = 413, + ppoll_time64 = 414, + io_pgetevents_time64 = 416, + recvmmsg_time64 = 417, + mq_timedsend_time64 = 418, + mq_timedreceive_time64 = 419, + semtimedop_time64 = 420, + rt_sigtimedwait_time64 = 421, + futex_time64 = 422, + sched_rr_get_interval_time64 = 423, pidfd_send_signal = 424, io_uring_setup = 425, io_uring_enter = 426, @@ -7311,8 +7317,6 @@ pub const CSky = enum(usize) { lsm_set_self_attr = 460, lsm_list_modules = 461, mseal = 462, - set_thread_area = (244 + 0), - cacheflush = (244 + 1), }; pub const Hexagon = enum(usize) { @@ -7320,7 +7324,7 @@ pub const Hexagon = enum(usize) { io_destroy = 1, io_submit = 2, io_cancel = 3, - io_getevents_time32 = 4, + io_getevents = 4, setxattr = 5, lsetxattr = 6, fsetxattr = 7, @@ -7388,8 +7392,8 @@ pub const Hexagon = enum(usize) { preadv = 69, pwritev = 70, sendfile64 = 71, - pselect6_time32 = 72, - ppoll_time32 = 73, + pselect6 = 72, + ppoll = 73, signalfd4 = 74, vmsplice = 75, splice = 76, @@ -7402,9 +7406,9 @@ pub const Hexagon = enum(usize) { fdatasync = 83, sync_file_range = 84, timerfd_create = 85, - timerfd_settime32 = 86, - timerfd_gettime32 = 87, - utimensat_time32 = 88, + timerfd_settime = 86, + timerfd_gettime = 87, + utimensat = 88, acct = 89, capget = 90, capset = 91, @@ -7414,24 +7418,24 @@ pub const Hexagon = enum(usize) { waitid = 95, set_tid_address = 96, unshare = 97, - futex_time32 = 98, + futex = 98, set_robust_list = 99, get_robust_list = 100, - nanosleep_time32 = 101, + nanosleep = 101, getitimer = 102, setitimer = 103, kexec_load = 104, init_module = 105, delete_module = 106, timer_create = 107, - timer_gettime32 = 108, + timer_gettime = 108, timer_getoverrun = 109, - timer_settime32 = 110, + timer_settime = 110, timer_delete = 111, - clock_settime32 = 112, - clock_gettime32 = 113, - clock_getres_time32 = 114, - clock_nanosleep_time32 = 115, + clock_settime = 112, + clock_gettime = 113, + clock_getres = 114, + clock_nanosleep = 115, syslog = 116, ptrace = 117, sched_setparam = 118, @@ -7443,7 +7447,7 @@ pub const Hexagon = enum(usize) { sched_yield = 124, sched_get_priority_max = 125, sched_get_priority_min = 126, - sched_rr_get_interval_time32 = 127, + sched_rr_get_interval = 127, restart_syscall = 128, kill = 129, tkill = 130, @@ -7453,7 +7457,7 @@ pub const Hexagon = enum(usize) { rt_sigaction = 134, rt_sigprocmask = 135, rt_sigpending = 136, - rt_sigtimedwait_time32 = 137, + rt_sigtimedwait = 137, rt_sigqueueinfo = 138, rt_sigreturn = 139, setpriority = 140, @@ -7487,7 +7491,7 @@ pub const Hexagon = enum(usize) { getcpu = 168, gettimeofday = 169, settimeofday = 170, - adjtimex_time32 = 171, + adjtimex = 171, getpid = 172, getppid = 173, getuid = 174, @@ -7498,8 +7502,8 @@ pub const Hexagon = enum(usize) { sysinfo = 179, mq_open = 180, mq_unlink = 181, - mq_timedsend_time32 = 182, - mq_timedreceive_time32 = 183, + mq_timedsend = 182, + mq_timedreceive = 183, mq_notify = 184, mq_getsetattr = 185, msgget = 186, @@ -7508,7 +7512,7 @@ pub const Hexagon = enum(usize) { msgsnd = 189, semget = 190, semctl = 191, - semtimedop_time32 = 192, + semtimedop = 192, semop = 193, shmget = 194, shmctl = 195, @@ -7559,14 +7563,14 @@ pub const Hexagon = enum(usize) { rt_tgsigqueueinfo = 240, perf_event_open = 241, accept4 = 242, - recvmmsg_time32 = 243, + recvmmsg = 243, wait4 = 260, prlimit64 = 261, fanotify_init = 262, fanotify_mark = 263, name_to_handle_at = 264, open_by_handle_at = 265, - clock_adjtime32 = 266, + clock_adjtime = 266, syncfs = 267, setns = 268, sendmmsg = 269, @@ -7592,29 +7596,29 @@ pub const Hexagon = enum(usize) { pkey_alloc = 289, pkey_free = 290, statx = 291, - io_pgetevents_time32 = 292, + io_pgetevents = 292, rseq = 293, kexec_file_load = 294, - clock_gettime = 403, - clock_settime = 404, - clock_adjtime = 405, - clock_getres = 406, - clock_nanosleep = 407, - timer_gettime = 408, - timer_settime = 409, - timerfd_gettime = 410, - timerfd_settime = 411, - utimensat = 412, - pselect6 = 413, - ppoll = 414, - io_pgetevents = 416, - recvmmsg = 417, - mq_timedsend = 418, - mq_timedreceive = 419, - semtimedop = 420, - rt_sigtimedwait = 421, - futex = 422, - sched_rr_get_interval = 423, + clock_gettime64 = 403, + clock_settime64 = 404, + clock_adjtime64 = 405, + clock_getres_time64 = 406, + clock_nanosleep_time64 = 407, + timer_gettime64 = 408, + timer_settime64 = 409, + timerfd_gettime64 = 410, + timerfd_settime64 = 411, + utimensat_time64 = 412, + pselect6_time64 = 413, + ppoll_time64 = 414, + io_pgetevents_time64 = 416, + recvmmsg_time64 = 417, + mq_timedsend_time64 = 418, + mq_timedreceive_time64 = 419, + semtimedop_time64 = 420, + rt_sigtimedwait_time64 = 421, + futex_time64 = 422, + sched_rr_get_interval_time64 = 423, pidfd_send_signal = 424, io_uring_setup = 425, io_uring_enter = 426, @@ -7626,6 +7630,7 @@ pub const Hexagon = enum(usize) { fsmount = 432, fspick = 433, pidfd_open = 434, + clone3 = 435, close_range = 436, openat2 = 437, pidfd_getfd = 438, From a16b32ac562f1f7e2eb0efeac2d7636b8d4170ec Mon Sep 17 00:00:00 2001 From: Stephen Gregoratto Date: Sat, 19 Oct 2024 18:07:45 +1100 Subject: [PATCH 3/6] Target: Bump Linux minimum requirements for kernel+glibc As per #21738, the minimum kernel has been bumped to 5.11, and glibc to 2.34. The maximum has also been updated to the new 6.11 release. --- lib/std/Target.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/std/Target.zig b/lib/std/Target.zig index def304bc6c84..d98db2f72fe8 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -505,11 +505,11 @@ pub const Os = struct { .linux => .{ .linux = .{ .range = .{ - .min = .{ .major = 4, .minor = 19, .patch = 0 }, - .max = .{ .major = 6, .minor = 10, .patch = 3 }, + .min = .{ .major = 5, .minor = 1, .patch = 0 }, + .max = .{ .major = 6, .minor = 11, .patch = 3 }, }, .glibc = blk: { - const default_min = .{ .major = 2, .minor = 28, .patch = 0 }; + const default_min = .{ .major = 2, .minor = 34, .patch = 0 }; for (std.zig.target.available_libcs) |libc| { // We don't know the ABI here. We can get away with not checking it From c11471c9c6fe716ffb521a5e801feda8e3b5284b Mon Sep 17 00:00:00 2001 From: Stephen Gregoratto Date: Wed, 23 Oct 2024 18:51:30 +1100 Subject: [PATCH 4/6] Linux: Always use time64 APIs `std.os.linux` has been reworked to use 64-bit time APIs on all targets. This required auditing all types used by the Kernel ABI for each of the supported targets, along with other some rewrites in `std.posix`. = `std.os.linux` The `Stat` structures for each target are now merged together into the `KernelStat` struct that switches on the target, similar to existing types. Targets that have a `stat64` structure have been modified to make that it's default, and all definitions have been re-written to match the kernel headers exactly using the `c_` int types. Of course, newer linux ports don't even implement the `stat(2)` family, instead requiring userspace to wrap it using `statx(2)`. Thus, a new `Stat` type has been created to hold information from both APIs. The new public variable `has_fstatat` has also been introduced, so that callers can check if the current target at least implements `fstatat(2)`, and to use `statx(2)` if not. The `major`, `minor` and `makedev` functions have also been ported over to make the translation from `statx(2)` possible. == `timespec` The KernelStat `(a|c|m)time` fields are no longer defined as `timespecs`, since their signedness and bit size vary by target. Instead, the new `timespec.makeTimespec` function is used, which does some comptime checks on the time types before performing `@intCasts` on each field. Speaking of, the `timespec` type has been redefined to be the same as `__kernel_timespec`, as it is the modern 64-bit type that the kernel is using going forward. Since some syscalls (e.g. `timerfd_(get|set)time`) require the `timespec64` type, it has been added as well. Note that the only difference between it and `__kernel_timespec` is that `ts_nsec` is defined as a `c_long`, thus explicit padding fields are added and zeroed out for 32-bit targets to avoid issued with uninitialised memory. == Misc. - The VDSO `clock_gettime` symbol now points to the proper 64-bit verrsion for each arch. - The `Time64` struct has been created to hold all the proper `time64` syscalls for each target. = `std.posix` - Add `fstatatLinux` that either uses `fstatat` or `statx` depending on the value of `linux.has_fstatat`. - Move `std.os.fstat(at)_wasi` into the `std.posix.fstat(at)Wasi` in light of #21023. - Move the libc path for `fstatat` into the new function `fstatatC`. - Mark `fstatatZ` as `inline` since the logic is simplified. --- lib/std/fs/Dir.zig | 7 +- lib/std/fs/File.zig | 8 +- lib/std/os.zig | 34 -- lib/std/os/linux.zig | 898 ++++++++++++++++++++++++------ lib/std/os/linux/IoUring.zig | 12 +- lib/std/os/linux/aarch64.zig | 43 -- lib/std/os/linux/arm.zig | 45 +- lib/std/os/linux/io_uring_sqe.zig | 4 +- lib/std/os/linux/loongarch64.zig | 5 - lib/std/os/linux/mips.zig | 58 +- lib/std/os/linux/mips64.zig | 55 -- lib/std/os/linux/powerpc.zig | 44 +- lib/std/os/linux/powerpc64.zig | 41 -- lib/std/os/linux/riscv32.zig | 38 -- lib/std/os/linux/riscv64.zig | 38 -- lib/std/os/linux/s390x.zig | 36 -- lib/std/os/linux/sparc64.zig | 45 -- lib/std/os/linux/test.zig | 20 +- lib/std/os/linux/x86.zig | 45 +- lib/std/os/linux/x86_64.zig | 45 -- lib/std/posix.zig | 176 ++++-- lib/std/posix/test.zig | 12 +- 22 files changed, 895 insertions(+), 814 deletions(-) diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig index fab9679838b3..33408f4deda4 100644 --- a/lib/std/fs/Dir.zig +++ b/lib/std/fs/Dir.zig @@ -2694,10 +2694,9 @@ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat { defer file.close(); return file.stat(); } - if (native_os == .wasi and !builtin.link_libc) { - const st = try std.os.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true }); - return Stat.fromWasi(st); - } + if (native_os == .wasi and !builtin.link_libc) + return Stat.fromWasi(try posix.fstatatWasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true })); + if (native_os == .linux) { const sub_path_c = try posix.toPosixPath(sub_path); var stx = std.mem.zeroes(linux.Statx); diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 36e7999bf79d..a0272fdfb76d 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -522,10 +522,8 @@ pub fn stat(self: File) StatError!Stat { }; } - if (builtin.os.tag == .wasi and !builtin.link_libc) { - const st = try std.os.fstat_wasi(self.handle); - return Stat.fromWasi(st); - } + if (builtin.os.tag == .wasi and !builtin.link_libc) + return Stat.fromWasi(try posix.fstatWasi(self.handle)); if (builtin.os.tag == .linux) { var stx = std.mem.zeroes(linux.Statx); @@ -1090,7 +1088,7 @@ pub fn metadata(self: File) MetadataError!Metadata { .statx = stx, }; }, - .wasi => .{ .stat = try std.os.fstat_wasi(self.handle) }, + .wasi => .{ .stat = try posix.fstatWasi(self.handle) }, else => .{ .stat = try posix.fstat(self.handle) }, }, }; diff --git a/lib/std/os.zig b/lib/std/os.zig index 27e6577111f9..235c6347b7d8 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -237,37 +237,3 @@ pub fn getFdPath(fd: std.posix.fd_t, out_buffer: *[max_path_bytes]u8) std.posix. else => unreachable, // made unreachable by isGetFdPathSupportedOnTarget above } } - -/// WASI-only. Same as `fstatat` but targeting WASI. -/// `pathname` should be encoded as valid UTF-8. -/// See also `fstatat`. -pub fn fstatat_wasi(dirfd: posix.fd_t, pathname: []const u8, flags: wasi.lookupflags_t) posix.FStatAtError!wasi.filestat_t { - var stat: wasi.filestat_t = undefined; - switch (wasi.path_filestat_get(dirfd, flags, pathname.ptr, pathname.len, &stat)) { - .SUCCESS => return stat, - .INVAL => unreachable, - .BADF => unreachable, // Always a race condition. - .NOMEM => return error.SystemResources, - .ACCES => return error.AccessDenied, - .FAULT => unreachable, - .NAMETOOLONG => return error.NameTooLong, - .NOENT => return error.FileNotFound, - .NOTDIR => return error.FileNotFound, - .NOTCAPABLE => return error.AccessDenied, - .ILSEQ => return error.InvalidUtf8, - else => |err| return posix.unexpectedErrno(err), - } -} - -pub fn fstat_wasi(fd: posix.fd_t) posix.FStatError!wasi.filestat_t { - var stat: wasi.filestat_t = undefined; - switch (wasi.fd_filestat_get(fd, &stat)) { - .SUCCESS => return stat, - .INVAL => unreachable, - .BADF => unreachable, // Always a race condition. - .NOMEM => return error.SystemResources, - .ACCES => return error.AccessDenied, - .NOTCAPABLE => return error.AccessDenied, - else => |err| return posix.unexpectedErrno(err), - } -} diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index bccbba5aed19..bb27fdd77344 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -95,7 +95,6 @@ pub const HWCAP = arch_bits.HWCAP; pub const MMAP2_UNIT = arch_bits.MMAP2_UNIT; pub const REG = arch_bits.REG; pub const SC = arch_bits.SC; -pub const Stat = arch_bits.Stat; pub const VDSO = arch_bits.VDSO; pub const blkcnt_t = arch_bits.blkcnt_t; pub const blksize_t = arch_bits.blksize_t; @@ -108,8 +107,6 @@ pub const msghdr_const = arch_bits.msghdr_const; pub const nlink_t = arch_bits.nlink_t; pub const off_t = arch_bits.off_t; pub const time_t = arch_bits.time_t; -pub const timeval = arch_bits.timeval; -pub const timezone = arch_bits.timezone; pub const ucontext_t = arch_bits.ucontext_t; pub const user_desc = arch_bits.user_desc; pub const getcontext = arch_bits.getcontext; @@ -121,7 +118,7 @@ pub const IOCTL = @import("linux/ioctl.zig"); pub const SECCOMP = @import("linux/seccomp.zig"); pub const syscalls = @import("linux/syscalls.zig"); -pub const SYS = switch (@import("builtin").cpu.arch) { +pub const SYS = switch (native_arch) { .x86 => syscalls.X86, .x86_64 => syscalls.X64, .aarch64, .aarch64_be => syscalls.Arm64, @@ -136,7 +133,7 @@ pub const SYS = switch (@import("builtin").cpu.arch) { .loongarch64 => syscalls.LoongArch64, .m68k => syscalls.M68k, .mips, .mipsel => syscalls.MipsO32, - .mips64, .mips64el => if (builtin.abi == .gnuabin32) + .mips64, .mips64el => if (native_abi == .gnuabin32) syscalls.MipsN32 else syscalls.MipsN64, @@ -147,6 +144,27 @@ pub const SYS = switch (@import("builtin").cpu.arch) { else => @compileError("The Zig Standard Library is missing syscall definitions for the target CPU architecture"), }; +/// Selects the proper syscall that uses the modern 64-bit time types. +const Time64 = struct { + const clock_adjtime: SYS = if (@hasField(SYS, "clock_adjtime64")) .clock_adjtime64 else .clock_adjtime; + const clock_gettime: SYS = if (@hasField(SYS, "clock_gettime64")) .clock_gettime64 else .clock_gettime; + const clock_settime: SYS = if (@hasField(SYS, "clock_settime64")) .clock_settime64 else .clock_settime; + const clock_getres: SYS = if (@hasField(SYS, "clock_getres_time64")) .clock_getres_time64 else .clock_getres; + const clock_nanosleep: SYS = if (@hasField(SYS, "clock_nanosleep_time64")) .clock_nanosleep_time64 else .clock_nanosleep; + const futex: SYS = if (@hasField(SYS, "futex_time64")) .futex_time64 else .futex; + const mq_timedreceive: SYS = if (@hasField(SYS, "mq_timedreceive_time64")) .mq_timedreceive_time64 else .mq_timedreceive; + const mq_timedsend: SYS = if (@hasField(SYS, "mq_timedsend_time64")) .mq_timedsend_time64 else .mq_timedsend; + const ppoll: SYS = if (@hasField(SYS, "ppoll_time64")) .ppoll_time64 else .ppoll; + const pselect6: SYS = if (@hasField(SYS, "pselect6_time64")) .pselect6_time64 else .pselect6; + const rt_sigtimedwait: SYS = if (@hasField(SYS, "rt_sigtimedwait_time64")) .rt_sigtimedwait_time64 else .rt_sigtimedwait; + const sched_rr_get_interval: SYS = if (@hasField(SYS, "sched_rr_get_interval_time64")) .sched_rr_get_interval_time64 else .sched_rr_get_interval; + const timer_gettime: SYS = if (@hasField(SYS, "timer_gettime64")) .timer_gettime64 else .timer_gettime; + const timer_settime: SYS = if (@hasField(SYS, "timer_settime64")) .timer_settime64 else .timer_settime; + const timerfd_gettime: SYS = if (@hasField(SYS, "timerfd_gettime64")) .timerfd_gettime64 else .timerfd_gettime; + const timerfd_settime: SYS = if (@hasField(SYS, "timerfd_settime64")) .timerfd_settime64 else .timerfd_settime; + const utimensat: SYS = if (@hasField(SYS, "utimensat_time64")) .utimensat_time64 else .utimensat; +}; + pub const MAP_TYPE = enum(u4) { SHARED = 0x01, PRIVATE = 0x02, @@ -469,6 +487,520 @@ pub const O = switch (native_arch) { else => @compileError("missing std.os.linux.O constants for this architecture"), }; +/// Structure that contains information about files. +/// Used to map `KernelStat` and `Statx` into something sane for `std.posix`. +/// Use `KernelStat` for the proper type to use for the `stat(2)` family of syscalls. +pub const Stat = struct { + /// Device. + dev: dev_t, + /// File serial number. + ino: ino_t, + /// File mode. + mode: mode_t, + /// Link count. + nlink: nlink_t, + /// User ID of the file's owner. + uid: uid_t, + /// Group ID of the file's owner. + gid: gid_t, + /// Device number, if this file is a device. + rdev: dev_t, + /// Size of file, in bytes. + size: i64, + /// Optimal block size for I/O. + blksize: i64, + /// Number of 512-byte blocks allocated. + blocks: i64, + /// Time of last access. + atime: timespec, + /// Time of last modification. + mtime: timespec, + /// Time of last status change. + ctime: timespec, + + pub fn fromKernel(st: KernelStat) @This() { + return .{ + .dev = st.dev, + .ino = st.ino, + .mode = st.mode, + .nlink = st.nlink, + .uid = st.uid, + .gid = st.gid, + .rdev = st.rdev, + .size = @intCast(st.size), + .blksize = @intCast(st.blksize), + .blocks = @intCast(st.blocks), + .atime = st.atime(), + .mtime = st.mtime(), + .ctime = st.ctime(), + }; + } + + pub fn fromStatx(stx: Statx) @This() { + return .{ + .dev = makedev(stx.dev_major, stx.dev_minor), + .ino = stx.ino, + .mode = stx.mode, + .nlink = stx.nlink, + .uid = stx.uid, + .gid = stx.gid, + .rdev = makedev(stx.rdev_major, stx.rdev_minor), + .size = @bitCast(stx.size), + .blksize = @as(i32, @bitCast(stx.blksize)), + .blocks = @intCast(stx.blocks), + .atime = stx.atime.toTimespec(), + .mtime = stx.mtime.toTimespec(), + .ctime = stx.ctime.toTimespec(), + }; + } +}; + +/// The canonical, 64-bit `stat` structure defined for each architecture. +/// Can be one of the following choices: +/// - `struct stat` on a 64-bit target. +/// - `struct stat64` on a 32-bit target. +/// - `struct stat64` on a 64-bit target. +/// +/// Note the "64" refers to file sizes (i.e. `size` and `blocks`) - +/// the time fields are not guaranteed to be 64-bits wide. +/// Applications that require this should use `statx(2)`, as: +/// - The file size and time fields are 64-bits wide. +/// - Modern Linux ports will not implement `fstatat(2)`, +/// in favor of libraries like libc using `statx(2)` to implement it anyway. +/// +/// See `std.os.fstatat_linux` for how this is done. +pub const KernelStat = switch (native_arch) { + .x86 => extern struct { // stat64 + dev: c_ulonglong, + __pad0: [4]u8 = .{ 0, 0, 0, 0 }, + __ino: c_ulong = 0, + mode: c_uint, + nlink: c_uint, + uid: c_ulong, + gid: c_ulong, + rdev: c_ulonglong, + __pad3: [4]u8 = .{ 0, 0, 0, 0 }, + size: c_longlong, + blksize: c_ulong, + blocks: c_ulonglong, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_uint, + ctim: c_ulong, + ctim_nsec: c_ulong, + ino: c_ulonglong, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .x86_64 => extern struct { // stat + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + __pad0: c_uint = 0, + rdev: c_ulong, + size: c_long, + blksize: c_long, + blocks: c_long, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_ulong, + ctim: c_ulong, + ctim_nsec: c_ulong, + __unused: [3]c_long = .{ 0, 0, 0 }, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .arm, .armeb, .thumb, .thumbeb => extern struct { // stat64 + dev: c_ulonglong, + __pad0: [4]u8 = .{ 0, 0, 0, 0 }, + __ino: c_ulong = 0, + mode: c_uint, + nlink: c_uint, + uid: c_ulong, + gid: c_ulong, + rdev: c_ulonglong, + __pad3: [4]u8 = .{ 0, 0, 0, 0 }, + size: c_longlong, + blksize: c_ulong, + blocks: c_ulonglong, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_ulong, + ctim: c_ulong, + ctim_nsec: c_ulong, + ino: c_ulonglong, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .sparc64 => extern struct { // stat64 + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + __pad0: c_uint = 0, + rdev: c_ulong, + size: c_long, + blksize: c_long, + blocks: c_long, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_ulong, + ctim: c_ulong, + ctim_nsec: c_ulong, + __unused: [3]c_long = .{ 0, 0, 0 }, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .mips, .mipsel => extern struct { // stat64 + dev: c_ulong, + __pad0: [3]c_ulong = .{ 0, 0, 0 }, + ino: c_ulonglong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_uint, + __pad1: [3]c_uint = .{ 0, 0, 0 }, + size: c_longlong, + atim: c_long, + atim_nsec: c_ulong, + mtim: c_long, + mtim_nsec: c_ulong, + ctim: c_long, + ctim_nsec: c_ulong, + blksize: c_ulong, + __pad2: c_uint = 0, + blocks: c_longlong, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .mips64, .mips64el => extern struct { // stat + dev: c_uint, + __pad0: [3]c_uint = .{ 0, 0, 0 }, + ino: c_ulong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_uint, + __pad1: [3]c_uint = .{ 0, 0, 0 }, + size: c_long, + atim: c_uint, + atim_nsec: c_uint, + mtim: c_uint, + mtim_nsec: c_uint, + ctim: c_uint, + ctim_nsec: c_uint, + blksize: c_uint, + __pad2: c_uint = 0, + blocks: c_ulong, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .powerpc, .powerpcle => extern struct { // stat64 + dev: c_ulonglong, + ino: c_ulonglong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __pad2: c_ushort = 0, + size: c_longlong, + blksize: c_int, + blocks: c_longlong, + atim: c_int, + atim_nsec: c_uint, + mtim: c_int, + mtim_nsec: c_uint, + ctim: c_int, + ctim_nsec: c_uint, + __unused4: c_uint = 0, + __unused5: c_uint = 0, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .powerpc64, .powerpc64le => extern struct { // stat64 + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + size: c_long, + blksize: c_ulong, + blocks: c_ulong, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_ulong, + ctim: c_ulong, + ctim_nsec: c_ulong, + __unused4: c_ulong = 0, + __unused5: c_ulong = 0, + __unused6: c_ulong = 0, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .s390x => extern struct { + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + __pad1: c_uint = 0, + rdev: c_ulong, + size: c_ulong, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_ulong, + ctim: c_ulong, + ctim_nsec: c_ulong, + blksize: c_ulong, + blocks: c_long, + __unused: [3]c_ulong = .{ 0, 0, 0 }, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .m68k => extern struct { // stat64 + dev: c_ulonglong, + __pad1: [2]u8 = .{ 0, 0 }, + __ino: c_ulong = 0, + mode: c_uint, + nlink: c_uint, + uid: c_ulong, + gid: c_ulong, + rdev: c_ulonglong, + __pad3: [2]u8 = .{ 0, 0 }, + size: c_longlong, + blksize: c_ulong, + blocks: c_ulonglong, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_ulong, + ctim: c_ulong, + ctim_nsec: c_ulong, + ino: c_ulonglong, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .xtensa => extern struct { // stat64 + dev: c_ulonglong, + ino: c_ulonglong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + size: c_longlong, + blksize: c_ulong, + __unused2: c_ulong = 0, + blocks: c_ulonglong, + atim: c_ulong, + atim_nsec: c_ulong, + mtim: c_ulong, + mtim_nsec: c_ulong, + ctim: c_ulong, + ctim_nsec: c_ulong, + __unused4: c_ulong = 0, + __unused5: c_ulong = 0, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + .csky, + .hexagon, + .riscv32, + .loongarch32, + => extern struct { // generic stat64 + dev: c_ulonglong, + ino: c_ulonglong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __pad1: c_ulonglong = 0, + size: c_longlong, + blksize: c_int, + __pad2: c_int = 0, + blocks: c_longlong, + atim: c_int, + atim_nsec: c_uint, + mtim: c_int, + mtim_nsec: c_uint, + ctim: c_int, + ctim_nsec: c_uint, + __unused4: c_uint = 0, + __unused5: c_uint = 0, + }, + .aarch64, + .aarch64_be, + .riscv64, + .loongarch64, + => extern struct { // generic stat + dev: c_ulong, + ino: c_ulong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad1: c_ulong = 0, + size: c_long, + blksize: c_int, + __pad2: c_int = 0, + blocks: c_long, + atim: c_long, + atim_nsec: c_ulong, + mtim: c_long, + mtim_nsec: c_ulong, + ctim: c_long, + ctim_nsec: c_ulong, + __unused4: c_uint = 0, + __unused5: c_uint = 0, + + pub fn atime(self: @This()) timespec { + return timespec.makeTimespec(self.atim, self.atim_nsec); + } + + pub fn mtime(self: @This()) timespec { + return timespec.makeTimespec(self.mtim, self.mtim_nsec); + } + + pub fn ctime(self: @This()) timespec { + return timespec.makeTimespec(self.ctim, self.ctim_nsec); + } + }, + else => @compileError("missing std.linux.Stat definition for this architecture"), +}; + +/// If true, this target has implemented `fstatat(2)`. +/// Otherwise, `statx(2)` will need to be used instead. +pub const has_fstatat = @hasField(SYS, "fstatat64"); + /// Set by startup code, used by `getauxval`. pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; @@ -508,22 +1040,7 @@ const require_aligned_register_pair = builtin.cpu.arch.isMIPS32() or builtin.cpu.arch.isArmOrThumb(); -// Split a 64bit value into a {LSB,MSB} pair. -// The LE/BE variants specify the endianness to assume. -fn splitValueLE64(val: i64) [2]u32 { - const u: u64 = @bitCast(val); - return [2]u32{ - @as(u32, @truncate(u)), - @as(u32, @truncate(u >> 32)), - }; -} -fn splitValueBE64(val: i64) [2]u32 { - const u: u64 = @bitCast(val); - return [2]u32{ - @as(u32, @truncate(u >> 32)), - @as(u32, @truncate(u)), - }; -} +/// Split a 64bit value into a {LSB,MSB} pair. fn splitValue64(val: i64) [2]u32 { const u: u64 = @bitCast(val); switch (native_endian) { @@ -610,7 +1127,13 @@ pub fn futimens(fd: i32, times: *const [2]timespec) usize { } pub fn utimensat(dirfd: i32, path: ?[*:0]const u8, times: *const [2]timespec, flags: u32) usize { - return syscall4(.utimensat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(times), flags); + return syscall4( + Time64.utimensat, + @bitCast(@as(isize, dirfd)), + @intFromPtr(path), + @intFromPtr(times), + flags, + ); } pub fn fallocate(fd: i32, mode: i32, offset: i64, length: i64) usize { @@ -638,11 +1161,22 @@ pub fn fallocate(fd: i32, mode: i32, offset: i64, length: i64) usize { } pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*const timespec) usize { - return syscall4(.futex, @intFromPtr(uaddr), futex_op, @as(u32, @bitCast(val)), @intFromPtr(timeout)); + return syscall4( + Time64.futex, + @intFromPtr(uaddr), + futex_op, + @as(u32, @bitCast(val)), + @intFromPtr(timeout), + ); } pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize { - return syscall3(.futex, @intFromPtr(uaddr), futex_op, @as(u32, @bitCast(val))); + return syscall3( + Time64.futex, + @intFromPtr(uaddr), + futex_op, + @as(u32, @bitCast(val)), + ); } /// Given an array of `futex_waitv`, wait on each uaddr. @@ -951,28 +1485,22 @@ pub fn munmap(address: [*]const u8, length: usize) usize { } pub fn poll(fds: [*]pollfd, n: nfds_t, timeout: i32) usize { - if (@hasField(SYS, "poll")) { - return syscall3(.poll, @intFromPtr(fds), n, @as(u32, @bitCast(timeout))); - } else { - return syscall5( - .ppoll, - @intFromPtr(fds), + return if (@hasField(SYS, "poll")) + syscall3(.poll, @intFromPtr(fds), n, @as(u32, @bitCast(timeout))) + else + ppoll( + fds, n, - @intFromPtr(if (timeout >= 0) - ×pec{ - .sec = @divTrunc(timeout, 1000), - .nsec = @rem(timeout, 1000) * 1000000, - } + if (timeout >= 0) + ×pec{ .sec = @divTrunc(timeout, 1000), .nsec = @rem(timeout, 1000) * 1000000 } else - null), - 0, - NSIG / 8, + null, + null, ); - } } -pub fn ppoll(fds: [*]pollfd, n: nfds_t, timeout: ?*timespec, sigmask: ?*const sigset_t) usize { - return syscall5(.ppoll, @intFromPtr(fds), n, @intFromPtr(timeout), @intFromPtr(sigmask), NSIG / 8); +pub fn ppoll(fds: ?[*]pollfd, n: nfds_t, timeout: ?*const timespec, sigmask: ?*const sigset_t) usize { + return syscall5(Time64.ppoll, @intFromPtr(fds), n, @intFromPtr(timeout), @intFromPtr(sigmask), NSIG / 8); } pub fn read(fd: i32, buf: [*]u8, count: usize) usize { @@ -1466,60 +1994,68 @@ pub fn wait4(pid: pid_t, status: *u32, flags: u32, usage: ?*rusage) usize { } pub fn waitid(id_type: P, id: i32, infop: *siginfo_t, flags: u32) usize { - return syscall5(.waitid, @intFromEnum(id_type), @as(usize, @bitCast(@as(isize, id))), @intFromPtr(infop), flags, 0); + return syscall5(.waitid, @intFromEnum(id_type), @bitCast(@as(isize, id)), @intFromPtr(infop), flags, 0); } pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) usize { - if (@hasField(SYS, "fcntl64")) { - return syscall3(.fcntl64, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, cmd))), arg); - } else { - return syscall3(.fcntl, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, cmd))), arg); - } + return syscall3( + if (@hasField(SYS, "fcntl64")) .fcntl64 else .fcntl, + @bitCast(@as(isize, fd)), + @bitCast(@as(isize, cmd)), + arg, + ); } pub fn flock(fd: fd_t, operation: i32) usize { - return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation)))); + return syscall2(.flock, @bitCast(@as(isize, fd)), @bitCast(@as(isize, operation))); } -// We must follow the C calling convention when we call into the VDSO -const VdsoClockGettime = *align(1) const fn (clockid_t, *timespec) callconv(.C) usize; -var vdso_clock_gettime: ?VdsoClockGettime = &init_vdso_clock_gettime; +// The init function must follow the C calling convention so it can be replaced later. +// NOTE: Sparc uses `timespec64`, which on Sparc64 is equivalent to `timespec`. +// This logic may need to change if the Sparc target is introduced. +const VdsoClockGettime = ?*align(1) const fn (clockid_t, *timespec) callconv(.C) usize; +var vdso_clock_gettime: VdsoClockGettime = &init_vdso_clock_gettime; pub fn clock_gettime(clk_id: clockid_t, tp: *timespec) usize { if (VDSO != void) { - const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered); - if (ptr) |f| { - const rc = f(clk_id, tp); - switch (rc) { - 0, @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL)))) => return rc, + if (@atomicLoad(VdsoClockGettime, &vdso_clock_gettime, .unordered)) |f| { + const EINVAL: usize = @bitCast(-@as(isize, @intFromEnum(E.INVAL))); + switch (f(clk_id, tp)) { + 0, EINVAL => |rc| return rc, else => {}, } } } - return syscall2(.clock_gettime, @intFromEnum(clk_id), @intFromPtr(tp)); + + return syscall2(Time64.clock_gettime, @intFromEnum(clk_id), @intFromPtr(tp)); } fn init_vdso_clock_gettime(clk: clockid_t, ts: *timespec) callconv(.C) usize { - const ptr: ?VdsoClockGettime = @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM)); + const ptr: VdsoClockGettime = @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM)); // Note that we may not have a VDSO at all, update the stub address anyway // so that clock_gettime will fall back on the good old (and slow) syscall - @atomicStore(?VdsoClockGettime, &vdso_clock_gettime, ptr, .monotonic); + @atomicStore(VdsoClockGettime, &vdso_clock_gettime, ptr, .monotonic); // Call into the VDSO if available if (ptr) |f| return f(clk, ts); - return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS)))); + return @bitCast(-@as(isize, @intFromEnum(E.NOSYS))); } pub fn clock_getres(clk_id: i32, tp: *timespec) usize { - return syscall2(.clock_getres, @as(usize, @bitCast(@as(isize, clk_id))), @intFromPtr(tp)); + return syscall2(Time64.clock_getres, @bitCast(@as(isize, clk_id)), @intFromPtr(tp)); } pub fn clock_settime(clk_id: i32, tp: *const timespec) usize { - return syscall2(.clock_settime, @as(usize, @bitCast(@as(isize, clk_id))), @intFromPtr(tp)); + return syscall2(Time64.clock_settime64, @bitCast(@as(isize, clk_id)), @intFromPtr(tp)); } -pub fn clock_nanosleep(clockid: clockid_t, flags: TIMER, request: *const timespec, remain: ?*timespec) usize { +pub fn clock_nanosleep( + clockid: clockid_t, + flags: TIMER, + request: *const timespec, + remain: ?*timespec, +) usize { return syscall4( - .clock_nanosleep, + Time64.clock_nanosleep, @intFromEnum(clockid), @as(u32, @bitCast(flags)), @intFromPtr(request), @@ -1527,18 +2063,16 @@ pub fn clock_nanosleep(clockid: clockid_t, flags: TIMER, request: *const timespe ); } -pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) usize { +pub fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) usize { return syscall2(.gettimeofday, @intFromPtr(tv), @intFromPtr(tz)); } -pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize { +pub fn settimeofday(noalias tv: *const timeval, noalias tz: ?*const timezone) usize { return syscall2(.settimeofday, @intFromPtr(tv), @intFromPtr(tz)); } pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { - if (native_arch == .riscv32) { - @compileError("No nanosleep syscall on this architecture."); - } else return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem)); + return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem)); } pub fn pause() usize { @@ -1955,62 +2489,48 @@ pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flag return syscall4(.accept4, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(addr), @intFromPtr(len), flags); } -pub fn fstat(fd: i32, stat_buf: *Stat) usize { - if (native_arch == .riscv32) { - // riscv32 has made the interesting decision to not implement some of - // the older stat syscalls, including this one. - @compileError("No fstat syscall on this architecture."); - } else if (@hasField(SYS, "fstat64")) { - return syscall2(.fstat64, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(stat_buf)); - } else { - return syscall2(.fstat, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(stat_buf)); - } +pub fn fstat(fd: i32, statbuf: *KernelStat) usize { + return syscall2( + if (@hasField(SYS, "fstat64")) .fstat64 else .stat, + @bitCast(@as(isize, fd)), + @intFromPtr(statbuf), + ); } -pub fn stat(pathname: [*:0]const u8, statbuf: *Stat) usize { - if (native_arch == .riscv32) { - // riscv32 has made the interesting decision to not implement some of - // the older stat syscalls, including this one. - @compileError("No stat syscall on this architecture."); - } else if (@hasField(SYS, "stat64")) { - return syscall2(.stat64, @intFromPtr(pathname), @intFromPtr(statbuf)); - } else { - return syscall2(.stat, @intFromPtr(pathname), @intFromPtr(statbuf)); - } +pub fn stat(noalias pathname: [*:0]const u8, noalias statbuf: *KernelStat) usize { + return syscall2( + if (@hasField(SYS, "stat64")) .stat64 else .stat, + @intFromPtr(pathname), + @intFromPtr(statbuf), + ); } -pub fn lstat(pathname: [*:0]const u8, statbuf: *Stat) usize { - if (native_arch == .riscv32) { - // riscv32 has made the interesting decision to not implement some of - // the older stat syscalls, including this one. - @compileError("No lstat syscall on this architecture."); - } else if (@hasField(SYS, "lstat64")) { - return syscall2(.lstat64, @intFromPtr(pathname), @intFromPtr(statbuf)); - } else { - return syscall2(.lstat, @intFromPtr(pathname), @intFromPtr(statbuf)); - } +pub fn lstat(noalias pathname: [*:0]const u8, noalias statbuf: *KernelStat) usize { + return syscall2( + if (@hasField(SYS, "lstat64")) .lstat64 else .lstat, + @intFromPtr(pathname), + @intFromPtr(statbuf), + ); } -pub fn fstatat(dirfd: i32, path: [*:0]const u8, stat_buf: *Stat, flags: u32) usize { - if (native_arch == .riscv32) { - // riscv32 has made the interesting decision to not implement some of - // the older stat syscalls, including this one. - @compileError("No fstatat syscall on this architecture."); - } else if (@hasField(SYS, "fstatat64")) { - return syscall4(.fstatat64, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(stat_buf), flags); - } else { - return syscall4(.fstatat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), @intFromPtr(stat_buf), flags); - } +pub fn fstatat(dirfd: i32, noalias path: [*:0]const u8, noalias statbuf: *KernelStat, flags: u32) usize { + return syscall4( + if (@hasField(SYS, "fstatat64")) .fstatat64 else .fstatat, + @bitCast(@as(isize, dirfd)), + @intFromPtr(path), + @intFromPtr(statbuf), + flags, + ); } -pub fn statx(dirfd: i32, path: [*:0]const u8, flags: u32, mask: u32, statx_buf: *Statx) usize { +pub fn statx(dirfd: i32, noalias path: [*:0]const u8, flags: u32, mask: u32, noalias statxbuf: *Statx) usize { return syscall5( .statx, - @as(usize, @bitCast(@as(isize, dirfd))), + @bitCast(@as(isize, dirfd)), @intFromPtr(path), flags, mask, - @intFromPtr(statx_buf), + @intFromPtr(statxbuf), ); } @@ -2116,24 +2636,26 @@ pub fn eventfd(count: u32, flags: u32) usize { } pub fn timerfd_create(clockid: clockid_t, flags: TFD) usize { - return syscall2( - .timerfd_create, - @intFromEnum(clockid), - @as(u32, @bitCast(flags)), - ); + return syscall2(.timerfd_create, @intFromEnum(clockid), @as(u32, @bitCast(flags))); } -pub const itimerspec = extern struct { - it_interval: timespec, - it_value: timespec, -}; - pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize { - return syscall2(.timerfd_gettime, @bitCast(@as(isize, fd)), @intFromPtr(curr_value)); + return syscall2(Time64.timerfd_gettime, @bitCast(@as(isize, fd)), @intFromPtr(curr_value)); } -pub fn timerfd_settime(fd: i32, flags: TFD.TIMER, new_value: *const itimerspec, old_value: ?*itimerspec) usize { - return syscall4(.timerfd_settime, @bitCast(@as(isize, fd)), @as(u32, @bitCast(flags)), @intFromPtr(new_value), @intFromPtr(old_value)); +pub fn timerfd_settime( + fd: i32, + flags: TFD.TIMER, + noalias new_value: *const itimerspec, + noalias old_value: ?*itimerspec, +) usize { + return syscall4( + Time64.timerfd_settime, + @bitCast(@as(isize, fd)), + @as(u32, @bitCast(flags)), + @intFromPtr(new_value), + @intFromPtr(old_value), + ); } // Flags for the 'setitimer' system call @@ -6052,7 +6574,7 @@ pub const io_uring_sync_cancel_reg = extern struct { addr: u64, fd: i32, flags: u32, - timeout: kernel_timespec, + timeout: timespec, pad: [4]u64, }; @@ -6107,71 +6629,79 @@ pub const statx_timestamp = extern struct { sec: i64, nsec: u32, __pad1: u32, + + fn toTimespec(self: @This()) timespec { + return .{ .sec = self.sec, .nsec = @as(i32, @bitCast(self.nsec)) }; + } }; /// Renamed to `Statx` to not conflict with the `statx` function. pub const Statx = extern struct { /// Mask of bits indicating filled fields mask: u32, - /// Block size for filesystem I/O blksize: u32, - /// Extra file attribute indicators attributes: u64, - /// Number of hard links nlink: u32, - /// User ID of owner uid: uid_t, - /// Group ID of owner gid: gid_t, - /// File type and mode mode: u16, __pad1: u16, - /// Inode number ino: u64, - /// Total size in bytes size: u64, - /// Number of 512B blocks allocated blocks: u64, - /// Mask to show what's supported in `attributes`. attributes_mask: u64, - /// Last access file timestamp atime: statx_timestamp, - /// Creation file timestamp btime: statx_timestamp, - /// Last status change file timestamp ctime: statx_timestamp, - /// Last modification file timestamp mtime: statx_timestamp, - /// Major ID, if this file represents a device. rdev_major: u32, - /// Minor ID, if this file represents a device. rdev_minor: u32, - /// Major ID of the device containing the filesystem where this file resides. dev_major: u32, - /// Minor ID of the device containing the filesystem where this file resides. dev_minor: u32, - - __pad2: [14]u64, + __pad2: [14]u64 = [1]u64{0} ** 14, }; +/// Returns the major number from a device number. +pub fn major(dev: dev_t) u32 { + return ((dev >> 8) & 0xfff) | ((dev >> 32) & ~@as(u32, 0xfff)); +} + +/// Returns the minor number from a device number +pub fn minor(dev: dev_t) u32 { + return (dev & 0xff) | ((dev >> 12) & ~@as(u32, 0xff)); +} + +/// Create a device number from a major/minor pair. +fn makedev(x: u32, y: u32) dev_t { + const xx: u64 = x; + const yy: u64 = y; + const xmask: u32 = 0xfff; + const ymask: u32 = 0xff; + + return ((yy & ymask) << 0) | + ((xx & xmask) << 8) | + ((yy & ~ymask) << 12) | + ((xx & ~xmask) << 32); +} + pub const addrinfo = extern struct { flags: AI, family: i32, @@ -6873,17 +7403,12 @@ pub const SIOCOUTQ = T.IOCOUTQ; pub const SOCK_IOC_TYPE = 0x89; -pub const SIOCGSTAMP_NEW = IOCTL.IOR(SOCK_IOC_TYPE, 0x06, i64[2]); -pub const SIOCGSTAMP_OLD = IOCTL.IOR('s', 100, timeval); - -/// Get stamp (timeval) -pub const SIOCGSTAMP = if (native_arch == .x86_64 or @sizeOf(timeval) == 8) SIOCGSTAMP_OLD else SIOCGSTAMP_NEW; - -pub const SIOCGSTAMPNS_NEW = IOCTL.IOR(SOCK_IOC_TYPE, 0x07, i64[2]); -pub const SIOCGSTAMPNS_OLD = IOCTL.IOR('s', 101, kernel_timespec); - +// Get stamp (timeval) +pub const SIOCGSTAMP = SIOCGSTAMP_NEW; +pub const SIOCGSTAMP_NEW = IOCTL.IOR(SOCK_IOC_TYPE, 0x06, timeval); /// Get stamp (timespec) -pub const SIOCGSTAMPNS = if (native_arch == .x86_64 or @sizeOf(timespec) == 8) SIOCGSTAMPNS_OLD else SIOCGSTAMPNS_NEW; +pub const SIOCGSTAMPNS = SIOCGSTAMPNS_NEW; +pub const SIOCGSTAMPNS_NEW = IOCTL.IOR(SOCK_IOC_TYPE, 0x07, timespec); // Routing table calls. /// Add routing table entry @@ -7523,16 +8048,67 @@ pub const POSIX_FADV = switch (native_arch) { }, }; -/// The timespec struct used by the kernel. -pub const kernel_timespec = extern struct { +/// The modern timespec struct used by the kernel (aka `kernel_timespec`). +pub const timespec = extern struct { + /// Seconds. sec: i64, + /// Nanoseconds. nsec: i64, + + pub fn makeTimespec(sec: anytype, nsec: anytype) @This() { + comptime { + for (.{ @typeInfo(@TypeOf(sec)), @typeInfo(@TypeOf(nsec)) }) |i| { + assert(i == .int and (i.int.bits == 32 or i.int.bits == 64)); + } + } + return .{ .sec = @intCast(sec), .nsec = @intCast(nsec) }; + } }; -// https://github.com/ziglang/zig/issues/4726#issuecomment-2190337877 -pub const timespec = if (native_arch == .riscv32) kernel_timespec else extern struct { +/// The other 64-bit timespec used by the kernel. +pub const timespec64 = if (usize_bits == 64) + timespec +else + // Explicit padding bytes have been and are zeroed out to remove any issues re: uninitialised memory. + extern struct { + /// Seconds. + sec: i64, + __pad_be: if (native_endian == .big) u32 else u0 = 0, + /// Nanoseconds + nsec: c_long, + __pad_le: if (native_endian == .little) u32 else u0 = 0, + }; + +/// The 64-bit version of `itimerspec` used by the kernel (itimerspec64). +/// See `include/linux/timer64.h` in the kernel source tree. +pub const itimerspec = extern struct { + /// Timer period. + interval: timespec64, + /// Timer expiration. + value: timespec64, +}; + +/// The modern timeval struct used by the kernel (aka `kernel_sock_timeval`). +pub const sock_timeval = extern struct { + /// Seconds. + sec: i64, + /// Microseconds. + usec: i64, +}; + +/// The old timeval struct used by the kernel (aka `kernel_old_timeval`). +pub const timeval = extern struct { + /// Seconds sec: isize, - nsec: isize, + /// Microseconds + usec: isize, +}; + +pub const timezone = extern struct { + /// Minutes west of Greenwich. + minuteswest: c_int, + /// Type of DST correction. + dsttime: c_int, }; pub const XDP = struct { diff --git a/lib/std/os/linux/IoUring.zig b/lib/std/os/linux/IoUring.zig index 731877e5aef1..55c3e70497a3 100644 --- a/lib/std/os/linux/IoUring.zig +++ b/lib/std/os/linux/IoUring.zig @@ -832,7 +832,7 @@ pub fn close_direct(self: *IoUring, user_data: u64, file_index: u32) !*linux.io_ pub fn timeout( self: *IoUring, user_data: u64, - ts: *const linux.kernel_timespec, + ts: *const linux.timespec, count: u32, flags: u32, ) !*linux.io_uring_sqe { @@ -881,7 +881,7 @@ pub fn timeout_remove( pub fn link_timeout( self: *IoUring, user_data: u64, - ts: *const linux.kernel_timespec, + ts: *const linux.timespec, flags: u32, ) !*linux.io_uring_sqe { const sqe = try self.get_sqe(); @@ -2261,7 +2261,7 @@ test "timeout (after a relative time)" { const ms = 10; const margin = 5; - const ts: linux.kernel_timespec = .{ .sec = 0, .nsec = ms * 1000000 }; + const ts: linux.timespec = .{ .sec = 0, .nsec = ms * 1000000 }; const started = std.time.milliTimestamp(); const sqe = try ring.timeout(0x55555555, &ts, 0, 0); @@ -2290,7 +2290,7 @@ test "timeout (after a number of completions)" { }; defer ring.deinit(); - const ts: linux.kernel_timespec = .{ .sec = 3, .nsec = 0 }; + const ts: linux.timespec = .{ .sec = 3, .nsec = 0 }; const count_completions: u64 = 1; const sqe_timeout = try ring.timeout(0x66666666, &ts, count_completions, 0); try testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode); @@ -2323,7 +2323,7 @@ test "timeout_remove" { }; defer ring.deinit(); - const ts: linux.kernel_timespec = .{ .sec = 3, .nsec = 0 }; + const ts: linux.timespec = .{ .sec = 3, .nsec = 0 }; const sqe_timeout = try ring.timeout(0x88888888, &ts, 0, 0); try testing.expectEqual(linux.IORING_OP.TIMEOUT, sqe_timeout.opcode); try testing.expectEqual(@as(u64, 0x88888888), sqe_timeout.user_data); @@ -2391,7 +2391,7 @@ test "accept/connect/recv/link_timeout" { const sqe_recv = try ring.recv(0xffffffff, socket_test_harness.server, .{ .buffer = buffer_recv[0..] }, 0); sqe_recv.flags |= linux.IOSQE_IO_LINK; - const ts = linux.kernel_timespec{ .sec = 0, .nsec = 1000000 }; + const ts = linux.timespec{ .sec = 0, .nsec = 1000000 }; _ = try ring.link_timeout(0x22222222, &ts, 0); const nr_wait = try ring.submit(); diff --git a/lib/std/os/linux/aarch64.zig b/lib/std/os/linux/aarch64.zig index 9248360ae97d..e5dc5bdd85a4 100644 --- a/lib/std/os/linux/aarch64.zig +++ b/lib/std/os/linux/aarch64.zig @@ -11,7 +11,6 @@ const gid_t = linux.gid_t; const pid_t = linux.pid_t; const stack_t = linux.stack_t; const sigset_t = linux.sigset_t; -const timespec = std.os.linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ("svc #0" @@ -221,48 +220,6 @@ pub const ino_t = usize; pub const dev_t = usize; pub const blkcnt_t = isize; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad: usize, - size: off_t, - blksize: blksize_t, - __pad2: i32, - blocks: blkcnt_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [2]u32, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - -pub const timeval = extern struct { - sec: isize, - usec: isize, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const mcontext_t = extern struct { fault_address: usize, regs: [31]usize, diff --git a/lib/std/os/linux/arm.zig b/lib/std/os/linux/arm.zig index 1d22b8c3dba7..6ec12de8c10e 100644 --- a/lib/std/os/linux/arm.zig +++ b/lib/std/os/linux/arm.zig @@ -11,7 +11,6 @@ const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; const sockaddr = linux.sockaddr; -const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ("svc #0" @@ -194,7 +193,7 @@ pub const F = struct { }; pub const VDSO = struct { - pub const CGT_SYM = "__vdso_clock_gettime"; + pub const CGT_SYM = "__vdso_clock_gettime64"; pub const CGT_VER = "LINUX_2.6"; }; @@ -263,48 +262,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - __dev_padding: u32, - __ino_truncated: u32, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __rdev_padding: u32, - size: off_t, - blksize: blksize_t, - blocks: blkcnt_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - ino: ino_t, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - -pub const timeval = extern struct { - sec: i32, - usec: i32, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const mcontext_t = extern struct { trap_no: usize, error_code: usize, diff --git a/lib/std/os/linux/io_uring_sqe.zig b/lib/std/os/linux/io_uring_sqe.zig index 71be7a1f9900..3513ca36f272 100644 --- a/lib/std/os/linux/io_uring_sqe.zig +++ b/lib/std/os/linux/io_uring_sqe.zig @@ -315,7 +315,7 @@ pub const io_uring_sqe = extern struct { pub fn prep_timeout( sqe: *linux.io_uring_sqe, - ts: *const linux.kernel_timespec, + ts: *const linux.timespec, count: u32, flags: u32, ) void { @@ -344,7 +344,7 @@ pub const io_uring_sqe = extern struct { pub fn prep_link_timeout( sqe: *linux.io_uring_sqe, - ts: *const linux.kernel_timespec, + ts: *const linux.timespec, flags: u32, ) void { sqe.prep_rw(.LINK_TIMEOUT, -1, @intFromPtr(ts), 1, 0); diff --git a/lib/std/os/linux/loongarch64.zig b/lib/std/os/linux/loongarch64.zig index def391549462..ab0a334dc3a1 100644 --- a/lib/std/os/linux/loongarch64.zig +++ b/lib/std/os/linux/loongarch64.zig @@ -150,11 +150,6 @@ pub const ino_t = u64; pub const dev_t = u32; pub const blkcnt_t = i64; -pub const timeval = extern struct { - tv_sec: time_t, - tv_usec: i64, -}; - pub const F = struct { pub const DUPFD = 0; pub const GETFD = 1; diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig index e6cb5f790025..cf03cffb0b5c 100644 --- a/lib/std/os/linux/mips.zig +++ b/lib/std/os/linux/mips.zig @@ -9,7 +9,6 @@ const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; const sockaddr = linux.sockaddr; -const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ( @@ -288,7 +287,7 @@ pub const F = struct { pub const MMAP2_UNIT = 4096; pub const VDSO = struct { - pub const CGT_SYM = "__vdso_clock_gettime"; + pub const CGT_SYM = "__vdso_clock_gettime64"; pub const CGT_VER = "LINUX_2.6"; }; @@ -330,61 +329,6 @@ pub const off_t = i64; pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; - -// The `stat64` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32). - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32). - size: off_t, - atim: i32, - atim_nsec: u32, - mtim: i32, - mtim_nsec: u32, - ctim: i32, - ctim_nsec: u32, - blksize: blksize_t, - __pad3: u32, - blocks: blkcnt_t, - - pub fn atime(self: @This()) timespec { - return .{ - .sec = self.atim, - .nsec = self.atim_nsec, - }; - } - - pub fn mtime(self: @This()) timespec { - return .{ - .sec = self.mtim, - .nsec = self.mtim_nsec, - }; - } - - pub fn ctime(self: @This()) timespec { - return .{ - .sec = self.ctim, - .nsec = self.ctim_nsec, - }; - } -}; - -pub const timeval = extern struct { - sec: isize, - usec: isize, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const Elf_Symndx = u32; /// TODO diff --git a/lib/std/os/linux/mips64.zig b/lib/std/os/linux/mips64.zig index 5e6661eae5cf..c143cf94cf6e 100644 --- a/lib/std/os/linux/mips64.zig +++ b/lib/std/os/linux/mips64.zig @@ -9,7 +9,6 @@ const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; const sockaddr = linux.sockaddr; -const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ( @@ -310,60 +309,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32). - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad1: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32). - size: off_t, - atim: u32, - atim_nsec: u32, - mtim: u32, - mtim_nsec: u32, - ctim: u32, - ctim_nsec: u32, - blksize: blksize_t, - __pad3: u32, - blocks: blkcnt_t, - - pub fn atime(self: @This()) timespec { - return .{ - .sec = self.atim, - .nsec = self.atim_nsec, - }; - } - - pub fn mtime(self: @This()) timespec { - return .{ - .sec = self.mtim, - .nsec = self.mtim_nsec, - }; - } - - pub fn ctime(self: @This()) timespec { - return .{ - .sec = self.ctim, - .nsec = self.ctim_nsec, - }; - } -}; - -pub const timeval = extern struct { - sec: isize, - usec: isize, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const Elf_Symndx = u32; /// TODO diff --git a/lib/std/os/linux/powerpc.zig b/lib/std/os/linux/powerpc.zig index 7b56b94823cd..5d9c280aaac9 100644 --- a/lib/std/os/linux/powerpc.zig +++ b/lib/std/os/linux/powerpc.zig @@ -11,7 +11,6 @@ const pid_t = linux.pid_t; const stack_t = linux.stack_t; const sigset_t = linux.sigset_t; const sockaddr = linux.sockaddr; -const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ( @@ -230,7 +229,7 @@ pub const F = struct { }; pub const VDSO = struct { - pub const CGT_SYM = "__kernel_clock_gettime"; + pub const CGT_SYM = "__kernel_clock_gettime64"; pub const CGT_VER = "LINUX_2.6.15"; }; @@ -271,47 +270,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __rdev_padding: i16, - size: off_t, - blksize: blksize_t, - blocks: blkcnt_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [2]u32, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - -pub const timeval = extern struct { - sec: time_t, - usec: isize, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const greg_t = u32; pub const gregset_t = [48]greg_t; pub const fpregset_t = [33]f64; diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig index 06b67c17f163..4a1a0a7d8fbf 100644 --- a/lib/std/os/linux/powerpc64.zig +++ b/lib/std/os/linux/powerpc64.zig @@ -11,7 +11,6 @@ const pid_t = linux.pid_t; const stack_t = linux.stack_t; const sigset_t = linux.sigset_t; const sockaddr = linux.sockaddr; -const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ( @@ -252,46 +251,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - ino: ino_t, - nlink: nlink_t, - mode: mode_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - size: off_t, - blksize: blksize_t, - blocks: blkcnt_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [3]u64, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - -pub const timeval = extern struct { - sec: isize, - usec: isize, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const greg_t = u64; pub const gregset_t = [48]greg_t; pub const fpregset_t = [33]f64; diff --git a/lib/std/os/linux/riscv32.zig b/lib/std/os/linux/riscv32.zig index 457d7e50b4b4..95eeb26ebe20 100644 --- a/lib/std/os/linux/riscv32.zig +++ b/lib/std/os/linux/riscv32.zig @@ -8,7 +8,6 @@ const gid_t = std.os.linux.gid_t; const pid_t = std.os.linux.pid_t; const sockaddr = linux.sockaddr; const socklen_t = linux.socklen_t; -const timespec = std.os.linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ("ecall" @@ -174,11 +173,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -pub const timeval = extern struct { - sec: time_t, - usec: i64, -}; - pub const Flock = extern struct { type: i16, whence: i16, @@ -212,38 +206,6 @@ pub const msghdr_const = extern struct { flags: i32, }; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad: usize, - size: off_t, - blksize: blksize_t, - __pad2: i32, - blocks: blkcnt_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [2]u32, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - pub const Elf_Symndx = u32; pub const MMAP2_UNIT = 4096; diff --git a/lib/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig index e33169c5b115..89397035b46c 100644 --- a/lib/std/os/linux/riscv64.zig +++ b/lib/std/os/linux/riscv64.zig @@ -8,7 +8,6 @@ const gid_t = std.os.linux.gid_t; const pid_t = std.os.linux.pid_t; const sockaddr = linux.sockaddr; const socklen_t = linux.socklen_t; -const timespec = std.os.linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ("ecall" @@ -174,11 +173,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -pub const timeval = extern struct { - sec: time_t, - usec: i64, -}; - pub const Flock = extern struct { type: i16, whence: i16, @@ -212,38 +206,6 @@ pub const msghdr_const = extern struct { flags: i32, }; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad: usize, - size: off_t, - blksize: blksize_t, - __pad2: i32, - blocks: blkcnt_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [2]u32, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - pub const Elf_Symndx = u32; pub const VDSO = struct { diff --git a/lib/std/os/linux/s390x.zig b/lib/std/os/linux/s390x.zig index efc48af4ff39..9c139848b0d0 100644 --- a/lib/std/os/linux/s390x.zig +++ b/lib/std/os/linux/s390x.zig @@ -8,7 +8,6 @@ const gid_t = std.os.linux.gid_t; const pid_t = std.os.linux.pid_t; const sockaddr = linux.sockaddr; const socklen_t = linux.socklen_t; -const timespec = std.os.linux.timespec; const stack_t = std.os.linux.stack_t; const sigset_t = std.os.linux.sigset_t; @@ -184,11 +183,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -pub const timeval = extern struct { - sec: time_t, - usec: i64, -}; - pub const Flock = extern struct { type: i16, whence: i16, @@ -221,36 +215,6 @@ pub const msghdr_const = extern struct { flags: i32, }; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - ino: ino_t, - nlink: nlink_t, - mode: mode_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - size: off_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - blksize: blksize_t, - blocks: blkcnt_t, - __unused: [3]c_ulong, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - pub const Elf_Symndx = u64; pub const VDSO = struct { diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig index c146ed17cf2a..e3aef7183606 100644 --- a/lib/std/os/linux/sparc64.zig +++ b/lib/std/os/linux/sparc64.zig @@ -12,7 +12,6 @@ const sockaddr = linux.sockaddr; const socklen_t = linux.socklen_t; const iovec = std.posix.iovec; const iovec_const = std.posix.iovec_const; -const timespec = linux.timespec; pub fn syscall_pipe(fd: *[2]i32) usize { return asm volatile ( @@ -300,50 +299,6 @@ pub const nlink_t = u32; pub const blksize_t = isize; pub const blkcnt_t = isize; -// The `stat64` definition used by the kernel. -pub const Stat = extern struct { - dev: u64, - ino: u64, - nlink: u64, - - mode: u32, - uid: u32, - gid: u32, - __pad0: u32, - - rdev: u64, - size: i64, - blksize: i64, - blocks: i64, - - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [3]u64, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - -pub const timeval = extern struct { - sec: isize, - usec: i32, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - // TODO I'm not sure if the code below is correct, need someone with more // knowledge about sparc64 linux internals to look into. diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig index a8ebec47a5ed..3e7aa6a42332 100644 --- a/lib/std/os/linux/test.zig +++ b/lib/std/os/linux/test.zig @@ -44,14 +44,13 @@ test "timer" { const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, .{}); try expect(linux.E.init(timer_fd) == .SUCCESS); - const time_interval = linux.timespec{ + const time_interval = linux.timespec64{ .sec = 0, - .nsec = 2000000, + .nsec = 2 * std.time.ns_per_ms, }; - const new_time = linux.itimerspec{ - .it_interval = time_interval, - .it_value = time_interval, + .interval = time_interval, + .value = time_interval, }; err = linux.E.init(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null)); @@ -86,9 +85,10 @@ test "statx" { else => unreachable, } - if (builtin.cpu.arch == .riscv32) return error.SkipZigTest; // No fstatat, so the rest of the test is meaningless. + if (linux.has_fstatat == false) + return error.SkipZigTest; // No fstatat, so the rest of the test is meaningless. - var stat_buf: linux.Stat = undefined; + var stat_buf: linux.KernelStat = undefined; switch (linux.E.init(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) { .SUCCESS => {}, else => unreachable, @@ -97,9 +97,9 @@ test "statx" { try expect(stat_buf.mode == statx_buf.mode); try expect(@as(u32, @bitCast(stat_buf.uid)) == statx_buf.uid); try expect(@as(u32, @bitCast(stat_buf.gid)) == statx_buf.gid); - try expect(@as(u64, @bitCast(@as(i64, stat_buf.size))) == statx_buf.size); - try expect(@as(u64, @bitCast(@as(i64, stat_buf.blksize))) == statx_buf.blksize); - try expect(@as(u64, @bitCast(@as(i64, stat_buf.blocks))) == statx_buf.blocks); + try expect(@as(u64, @intCast(stat_buf.size)) == statx_buf.size); + try expect(@as(u64, @intCast(stat_buf.blksize)) == statx_buf.blksize); + try expect(@as(u64, @intCast(stat_buf.blocks)) == statx_buf.blocks); } test "user and group ids" { diff --git a/lib/std/os/linux/x86.zig b/lib/std/os/linux/x86.zig index abcfb99b3777..7ebb750eebb9 100644 --- a/lib/std/os/linux/x86.zig +++ b/lib/std/os/linux/x86.zig @@ -11,7 +11,6 @@ const pid_t = linux.pid_t; const stack_t = linux.stack_t; const sigset_t = linux.sigset_t; const sockaddr = linux.sockaddr; -const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ("int $0x80" @@ -225,7 +224,7 @@ pub const F = struct { pub const MMAP2_UNIT = 4096; pub const VDSO = struct { - pub const CGT_SYM = "__vdso_clock_gettime"; + pub const CGT_SYM = "__vdso_clock_gettime64"; pub const CGT_VER = "LINUX_2.6"; }; @@ -268,48 +267,6 @@ pub const ino_t = u64; pub const dev_t = u64; pub const blkcnt_t = i64; -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - __dev_padding: u32, - __ino_truncated: u32, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __rdev_padding: u32, - size: off_t, - blksize: blksize_t, - blocks: blkcnt_t, - atim: timespec, - mtim: timespec, - ctim: timespec, - ino: ino_t, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - -pub const timeval = extern struct { - sec: i32, - usec: i32, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const mcontext_t = extern struct { gregs: [19]usize, fpregs: [*]u8, diff --git a/lib/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig index cef15105eee7..9afc738d9d6b 100644 --- a/lib/std/os/linux/x86_64.zig +++ b/lib/std/os/linux/x86_64.zig @@ -13,7 +13,6 @@ const stack_t = linux.stack_t; const sigset_t = linux.sigset_t; const sockaddr = linux.sockaddr; const socklen_t = linux.socklen_t; -const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { return asm volatile ("syscall" @@ -252,50 +251,6 @@ pub const msghdr_const = extern struct { pub const off_t = i64; pub const ino_t = u64; pub const dev_t = u64; - -// The `stat` definition used by the Linux kernel. -pub const Stat = extern struct { - dev: dev_t, - ino: ino_t, - nlink: usize, - - mode: u32, - uid: uid_t, - gid: gid_t, - __pad0: u32, - rdev: dev_t, - size: off_t, - blksize: isize, - blocks: i64, - - atim: timespec, - mtim: timespec, - ctim: timespec, - __unused: [3]isize, - - pub fn atime(self: @This()) timespec { - return self.atim; - } - - pub fn mtime(self: @This()) timespec { - return self.mtim; - } - - pub fn ctime(self: @This()) timespec { - return self.ctim; - } -}; - -pub const timeval = extern struct { - sec: isize, - usec: isize, -}; - -pub const timezone = extern struct { - minuteswest: i32, - dsttime: i32, -}; - pub const Elf_Symndx = u32; pub const greg_t = usize; diff --git a/lib/std/posix.zig b/lib/std/posix.zig index bb21a79690b8..85fe0b317be7 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -1676,7 +1676,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: O, mode: mode_t) OpenE errdefer close(fd); if (flags.write) { - const info = try std.os.fstat_wasi(fd); + const info = try fstatWasi(fd); if (info.filetype == .DIRECTORY) return error.IsDir; } @@ -4350,12 +4350,16 @@ pub const FStatError = error{ /// Return information about a file descriptor. pub fn fstat(fd: fd_t) FStatError!Stat { - if (native_os == .wasi and !builtin.link_libc) { - return Stat.fromFilestat(try std.os.fstat_wasi(fd)); - } - if (native_os == .windows) { + if (native_os == .windows) @compileError("fstat is not yet implemented on Windows"); - } + if (native_os == .wasi and !builtin.link_libc) + return Stat.fromFilestat(try fstatWasi(fd)); + + if (native_os == .linux and !builtin.link_libc) + return fstatatLinux(fd, "", AT.EMPTY_PATH) catch |err| switch (err) { + error.SymLinkLoop, error.FileNotFound, error.NameTooLong => unreachable, + else => |e| e, + }; const fstat_sym = if (lfs64_abi) system.fstat64 else system.fstat; var stat = mem.zeroes(Stat); @@ -4369,6 +4373,19 @@ pub fn fstat(fd: fd_t) FStatError!Stat { } } +pub fn fstatWasi(fd: fd_t) FStatError!wasi.filestat_t { + var stat: wasi.filestat_t = undefined; + return switch (wasi.fd_filestat_get(fd, &stat)) { + .SUCCESS => stat, + .INVAL => unreachable, + .BADF => unreachable, // Always a race condition. + .NOMEM => return error.SystemResources, + .ACCES => return error.AccessDenied, + .NOTCAPABLE => return error.AccessDenied, + else => |err| return unexpectedErrno(err), + }; +} + pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, @@ -4381,51 +4398,109 @@ pub const FStatAtError = FStatError || error{ /// which is relative to `dirfd` handle. /// On WASI, `pathname` should be encoded as valid UTF-8. /// On other platforms, `pathname` is an opaque sequence of bytes with no particular encoding. -/// See also `fstatatZ` and `std.os.fstatat_wasi`. +/// See also `fstatatZ`. pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat { - if (native_os == .wasi and !builtin.link_libc) { - const filestat = try std.os.fstatat_wasi(dirfd, pathname, .{ - .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0, - }); - return Stat.fromFilestat(filestat); - } else if (native_os == .windows) { + if (native_os == .windows) @compileError("fstatat is not yet implemented on Windows"); - } else { - const pathname_c = try toPosixPath(pathname); - return fstatatZ(dirfd, &pathname_c, flags); - } -} - -/// Same as `fstatat` but `pathname` is null-terminated. -/// See also `fstatat`. -pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat { - if (native_os == .wasi and !builtin.link_libc) { - const filestat = try std.os.fstatat_wasi(dirfd, mem.sliceTo(pathname, 0), .{ + if (native_os == .wasi and !builtin.link_libc) + return Stat.fromFilestat(try fstatatWasi(dirfd, pathname, .{ .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0, - }); - return Stat.fromFilestat(filestat); - } + })); - const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat; - var stat = mem.zeroes(Stat); - switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) { + const pathname_c = try toPosixPath(pathname); + return fstatatZ(dirfd, &pathname_c, flags); +} + +/// Same as `fstatat` but for WASI. +/// `pathname` should be encoded as a valid UTF-8 string. +pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: wasi.lookupflags_t) FStatAtError!wasi.filestat_t { + var stat: wasi.filestat_t = undefined; + return switch (wasi.path_filestat_get(dirfd, flags, pathname.ptr, pathname.len, &stat)) { .SUCCESS => return stat, .INVAL => unreachable, .BADF => unreachable, // Always a race condition. .NOMEM => return error.SystemResources, .ACCES => return error.AccessDenied, - .PERM => return error.AccessDenied, .FAULT => unreachable, .NAMETOOLONG => return error.NameTooLong, - .LOOP => return error.SymLinkLoop, .NOENT => return error.FileNotFound, .NOTDIR => return error.FileNotFound, - .ILSEQ => |err| if (native_os == .wasi) - return error.InvalidUtf8 - else - return unexpectedErrno(err), + .NOTCAPABLE => return error.AccessDenied, + .ILSEQ => return error.InvalidUtf8, else => |err| return unexpectedErrno(err), - } + }; +} + +/// Same as `fstatat` except it uses `statx(2)` if the target does not implement `fstatat(2)`. +fn fstatatLinux( + dirfd: fd_t, + pathname: [*:0]const u8, + flags: u32, +) (FStatError || error{ NameTooLong, FileNotFound, SymLinkLoop })!linux.Stat { + const buf, const rc = if (linux.has_fstatat) blk: { + var stat = mem.zeroes(linux.KernelStat); + const rc = linux.fstatat(dirfd, pathname, &stat, flags); + break :blk .{ stat, rc }; + } else blk: { + var statx = mem.zeroes(linux.Statx); + const rc = linux.statx(dirfd, pathname, flags | AT.NO_AUTOMOUNT, linux.STATX_BASIC_STATS, &statx); + break :blk .{ statx, rc }; + }; + return switch (errno(rc)) { + .SUCCESS => if (linux.has_fstatat) + linux.Stat.fromKernel(buf) + else + linux.Stat.fromStatx(buf), + .INVAL => unreachable, + .BADF => unreachable, // Always a race condition. + .NOMEM => error.SystemResources, + .ACCES => error.AccessDenied, + .PERM => error.AccessDenied, + .FAULT => unreachable, + .NAMETOOLONG => error.NameTooLong, + .LOOP => error.SymLinkLoop, + .NOENT => error.FileNotFound, + .NOTDIR => error.FileNotFound, + else => |err| unexpectedErrno(err), + }; +} + +/// Same as `fstatat` but for targets using libc. +fn fstatatC(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat { + const sym = if (lfs64_abi) system.fstatat64 else system.fstatat; + var stat = mem.zeroes(Stat); + return switch (errno(sym(dirfd, pathname, &stat, flags))) { + .SUCCESS => stat, + .INVAL => unreachable, + .BADF => unreachable, // Always a race condition. + .NOMEM => error.SystemResources, + .ACCES => error.AccessDenied, + .PERM => error.AccessDenied, + .FAULT => unreachable, + .NAMETOOLONG => error.NameTooLong, + .LOOP => error.SymLinkLoop, + .NOENT => error.FileNotFound, + .NOTDIR => error.FileNotFound, + .ILSEQ => |err| return if (native_os == .wasi) + error.InvalidUtf8 + else + unexpectedErrno(err), + else => |err| unexpectedErrno(err), + }; +} + +/// Same as `fstatat` but `pathname` is null-terminated. +pub inline fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat { + return if (native_os == .windows) + @compileError("fstatat is not yet implemented on Windows") + else if (native_os == .wasi and !builtin.link_libc) + Stat.fromFilestat(try fstatatWasi(dirfd, mem.sliceTo(pathname, 0), .{ + .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0, + })) + else if (native_os == .linux and !builtin.link_libc) + fstatatLinux(dirfd, pathname, flags) + else + fstatatC(dirfd, pathname, flags); } pub const KQueueError = error{ @@ -4865,42 +4940,33 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr const path_w = try windows.sliceToPrefixedFileW(dirfd, path); return faccessatW(dirfd, path_w.span().ptr); } else if (native_os == .wasi and !builtin.link_libc) { - const resolved: RelativePathWasi = .{ .dir_fd = dirfd, .relative_path = path }; - - const st = blk: { - break :blk std.os.fstatat_wasi(dirfd, path, .{ - .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0, - }); - } catch |err| switch (err) { + const st = fstatatWasi(dirfd, path, .{ + .SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0, + }) catch |err| switch (err) { error.AccessDenied => return error.PermissionDenied, else => |e| return e, }; if (mode != F_OK) { var directory: wasi.fdstat_t = undefined; - if (wasi.fd_fdstat_get(resolved.dir_fd, &directory) != .SUCCESS) { + if (wasi.fd_fdstat_get(dirfd, &directory) != .SUCCESS) return error.PermissionDenied; - } var rights: wasi.rights_t = .{}; if (mode & R_OK != 0) { - if (st.filetype == .DIRECTORY) { - rights.FD_READDIR = true; - } else { + if (st.filetype == .DIRECTORY) + rights.FD_READDIR = true + else rights.FD_READ = true; - } - } - if (mode & W_OK != 0) { - rights.FD_WRITE = true; } + if (mode & W_OK != 0) rights.FD_WRITE = true; // No validation for X_OK // https://github.com/ziglang/zig/issues/18882 const rights_int: u64 = @bitCast(rights); const inheriting_int: u64 = @bitCast(directory.fs_rights_inheriting); - if ((rights_int & inheriting_int) != rights_int) { + if ((rights_int & inheriting_int) != rights_int) return error.PermissionDenied; - } } return; } diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index dba7dcde6d9c..c5baede2c30b 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -1129,15 +1129,21 @@ test "timerfd" { const tfd = try posix.timerfd_create(.MONOTONIC, .{ .CLOEXEC = true }); defer posix.close(tfd); - // Fire event 10_000_000ns = 10ms after the posix.timerfd_settime call. - var sit: linux.itimerspec = .{ .it_interval = .{ .sec = 0, .nsec = 0 }, .it_value = .{ .sec = 0, .nsec = 10 * (1000 * 1000) } }; + // Fire event 10ms after the posix.timerfd_settime call. + var sit: linux.itimerspec = .{ + .interval = .{ .sec = 0, .nsec = 0 }, + .value = .{ .sec = 0, .nsec = 10 * std.time.ns_per_ms }, + }; try posix.timerfd_settime(tfd, .{}, &sit, null); var fds: [1]posix.pollfd = .{.{ .fd = tfd, .events = linux.POLL.IN, .revents = 0 }}; try expectEqual(@as(usize, 1), try posix.poll(&fds, -1)); // -1 => infinite waiting const git = try posix.timerfd_gettime(tfd); - const expect_disarmed_timer: linux.itimerspec = .{ .it_interval = .{ .sec = 0, .nsec = 0 }, .it_value = .{ .sec = 0, .nsec = 0 } }; + const expect_disarmed_timer: linux.itimerspec = .{ + .interval = .{ .sec = 0, .nsec = 0 }, + .value = .{ .sec = 0, .nsec = 0 }, + }; try expectEqual(expect_disarmed_timer, git); } From 05b651571d34f5b4de02c5cc1098585a4c33df61 Mon Sep 17 00:00:00 2001 From: Stephen Gregoratto Date: Mon, 28 Oct 2024 18:37:22 +1100 Subject: [PATCH 5/6] `std.c`: Unify largefile and time64 support on Linux This commit follows the work done in `std.os.linux`, in that the `Stat`, `time_t` and `timespec` types have been audited against the libc definitions and fixed appropriately. Targeting the `largefile` and `time64` functions require linking to specific symbols. In order not to over-complicate `std.posix`, which already uses `lfs64_abi`, the logic for selecting the right function has been moved into `std.c`. These functions are imported from the new file `vlfts.zig` along with the two options `largefile_abi` and `time64_abi`. This allows `std.c` to select the proper symbol for e.g. fstatat, which could be one of the following: - `fstatat`. - `fstatat64`. - `__fstatat64_time64`. - `fstatat_time64`. Simple, isn't it... --- lib/std/c.zig | 1007 +++++++++++++++++++++++++++++++++++-------- lib/std/c/vlfts.zig | 154 +++++++ lib/std/posix.zig | 156 +++---- 3 files changed, 1064 insertions(+), 253 deletions(-) create mode 100644 lib/std/c/vlfts.zig diff --git a/lib/std/c.zig b/lib/std/c.zig index d28f5b0ac4b8..e9393335f727 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -19,6 +19,7 @@ const netbsd = @import("c/netbsd.zig"); const dragonfly = @import("c/dragonfly.zig"); const haiku = @import("c/haiku.zig"); const openbsd = @import("c/openbsd.zig"); +const vlfts = @import("c/vlfts.zig"); // These constants are shared among all operating systems even when not linking // libc. @@ -82,7 +83,7 @@ pub const off_t = switch (native_os) { }; pub const timespec = switch (native_os) { - .linux => linux.timespec, + .linux => linux.timespec64, .emscripten => emscripten.timespec, .wasi => extern struct { sec: time_t, @@ -5803,22 +5804,44 @@ pub const stack_t = switch (native_os) { flags: i32, }, }; + pub const time_t = switch (native_os) { - .linux => linux.time_t, + .linux => if (native_abi.isMusl()) + i64 // 64-bit since version 1.2. + else if (versionCheck(.{ .major = 2, .minor = 34, .patch = 0 })) + i64 // Complete Y2038 support since version 2.34. + else if (vlfts.time64_abi) + i64 + else + // True for: + // - glibc older than 2.34. + // - Musl older than 1.2. + // - Bionic[1], since time_t -> __kernel_time_t -> __kernel_long_t. + // [1] https://android.googlesource.com/platform/bionic/+/refs/heads/main/libc/include/bits/timespec.h + c_long, .emscripten => emscripten.time_t, .haiku, .dragonfly => isize, else => i64, }; + pub const suseconds_t = switch (native_os) { .solaris, .illumos => i64, .freebsd, .dragonfly => c_long, .netbsd => c_int, .haiku => i32, + // See `time_t` above. + .linux => if (native_abi.isMusl()) + i64 + else if (versionCheck(.{ .major = 2, .minor = 34, .patch = 0 })) + i64 + else if (vlfts.time64_abi) + i64 + else + c_long, else => void, }; pub const timeval = switch (native_os) { - .linux => linux.timeval, .emscripten => emscripten.timeval, .windows => extern struct { sec: c_long, @@ -5838,8 +5861,18 @@ pub const timeval = switch (native_os) { sec: time_t, usec: c_long, }, + // See `time_t` above. + .linux => if (native_abi.isMusl()) + linux.sock_timeval + else if (versionCheck(.{ .major = 2, .minor = 34, .patch = 0 })) + linux.sock_timeval + else if (vlfts.time64_abi) + linux.sock_timeval + else + linux.timeval, else => void, }; + pub const timezone = switch (native_os) { .linux => linux.timezone, .emscripten => emscripten.timezone, @@ -6403,23 +6436,283 @@ pub const EAI = switch (native_os) { pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int; pub const Stat = switch (native_os) { - .linux => switch (native_arch) { - .sparc64 => extern struct { - dev: u64, - __pad1: u16, - ino: ino_t, - mode: u32, - nlink: u32, + .linux => if (native_abi.isAndroid()) + // Android uses Bionic libc, which uses the kernel definitions. + linux.KernelStat + else if (native_abi.isGnu()) switch (native_arch) { + .aarch64, .aarch64_be, .loongarch64 => extern struct { + dev: c_ulong, + ino: c_ulong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad1: c_ulong = 0, + size: c_long, + blksize: c_int, + blocks: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + __reserved: [2]c_int, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .arm, .armeb, .thumb, .thumbeb, .m68k, .x86 => extern struct { // stat64 + dev: c_ulonglong, + __pad1: c_ushort = 0, + __ino: c_ulong = 0, + mode: c_uint, + nlink: c_ulong, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __pad2: c_ushort = 0, + size: c_longlong, + blksize: c_long, + blkcnt: c_longlong, + atim: timespec, + mtim: timespec, + ctim: timespec, + ino: c_ulonglong, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .csky, .riscv32, .riscv64 => extern struct { + dev: c_ulonglong, + ino: c_ulonglong, + mode: c_uint, + nlink: c_ulong, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __pad1: c_ulonglong = 0, + size: c_longlong, + blksize: c_int, + __pad2: c_int = 0, + blocks: c_longlong, + atim: timespec, + mtim: timespec, + ctim: timespec, + __reserved: [2]c_int, + + pub fn atime(self: @This()) timespec { + return self.atim; + } - uid: u32, - gid: u32, - rdev: u64, - __pad2: u16, + pub fn mtime(self: @This()) timespec { + return self.mtim; + } - size: off_t, - blksize: isize, - blocks: i64, + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .mips, .mipsel => extern struct { + dev: c_ulong, + __pad1: [3]c_long = .{ 0, 0, 0 }, + ino: c_ulonglong, + mode: c_uint, + nlink: c_ulong, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad2: [3]c_long = .{ 0, 0, 0 }, + size: c_longlong, + atim: timespec, + mtim: timespec, + ctim: timespec, + blksize: c_long, + __pad4: c_long = 0, + blocks: c_longlong, + __pad5: [14]c_long = [1]c_long{0} ** 14, + }, + .mips64, .mips64el => if (native_abi == .gnuabin32) + extern struct { + dev: c_ulonglong, + __pad1: [3]c_int = .{ 0, 0, 0 }, + ino: c_ulonglong, + mode: c_uint, + nlink: c_int, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __pad2: [3]c_int = .{ 0, 0, 0 }, + size: c_longlong, + atim: timespec, + mtim: timespec, + ctim: timespec, + blksize: c_long, + __pad4: c_uint = 0, + blocks: c_longlong, + __pad5: [14]c_int = [1]c_int{0} ** 14, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + } + else + extern struct { + dev: c_ulong, + __pad1: [3]c_int = .{ 0, 0, 0 }, + ino: c_ulong, + mode: c_uint, + nlink: c_ulong, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad2: [3]c_int = .{ 0, 0, 0 }, + size: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + blksize: c_long, + __pad4: c_uint = 0, + blocks: c_long, + __pad5: [14]c_int = [1]c_int{0} ** 14, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .powerpc => extern struct { + dev: c_ulonglong, + ino: c_ulonglong, + mode: c_uint, + nlink: c_ulong, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __pad2: c_ushort = 0, + size: c_longlong, + blksize: c_long, + blocks: c_longlong, + atim: timespec, + mtim: timespec, + ctim: timespec, + __reserved4: c_ulong, + __reserved5: c_ulong, + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .powerpc64, .powerpc64le => extern struct { + dev: c_ulong, + ino: c_ulong, + mode: c_uint, + nlink: c_ulong, + uid: c_uint, + gid: c_uint, + __pad2: c_uint = 0, + rdev: c_ulong, + size: c_long, + blksize: c_long, + blocks: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + __reserved: [3]c_ulong = .{ 0, 0, 0 }, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .s390x => extern struct { + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + __reserved0: c_int = 0, + rdev: c_ulong, + size: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + blksize: c_int, + blocks: c_long, + __reserved: [3]c_long, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .sparc64 => extern struct { + dev: c_ulong, + __pad1: c_ushort = 0, + ino: c_ulong, + mode: c_uint, + nlink: c_ulong, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad2: c_ushort = 0, + size: c_long, + blksize: c_long, + blocks: c_long, atim: timespec, mtim: timespec, ctim: timespec, @@ -6437,24 +6730,22 @@ pub const Stat = switch (native_os) { return self.ctim; } }, - .mips, .mipsel => if (builtin.target.isMusl()) extern struct { - dev: dev_t, - __pad0: [2]i32, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad1: [2]i32, - size: off_t, + .x86_64 => extern struct { + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + __pad0: c_int = 0, + rdev: c_ulong, + size: c_long, + blksize: c_long, + blkcnt: c_long, atim: timespec, mtim: timespec, ctim: timespec, - blksize: blksize_t, - __pad3: i32, - blocks: blkcnt_t, - __pad4: [14]i32, + __reserved: [3]c_long = .{ 0, 0, 0 }, pub fn atime(self: @This()) timespec { return self.atim; @@ -6467,24 +6758,26 @@ pub const Stat = switch (native_os) { pub fn ctime(self: @This()) timespec { return self.ctim; } - } else extern struct { - dev: u32, - __pad0: [3]u32, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: u32, - __pad1: [3]u32, - size: off_t, + }, + else => void, + } else if (native_abi.isMusl()) switch (native_arch) { + .aarch64, .aarch64_be, .loongarch64 => extern struct { + dev: c_ulong, + ino: c_ulong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad1: c_ulong = 0, + size: c_long, + blksize: c_int, + __pad2: c_int = 0, + blocks: c_long, atim: timespec, mtim: timespec, ctim: timespec, - blksize: blksize_t, - __pad3: u32, - blocks: blkcnt_t, - __pad4: [14]u32, + __unused: [2]c_int = .{ 0, 0 }, pub fn atime(self: @This()) timespec { return self.atim; @@ -6498,25 +6791,26 @@ pub const Stat = switch (native_os) { return self.ctim; } }, - .mips64, .mips64el => if (builtin.target.isMusl()) extern struct { - dev: dev_t, - __pad0: [3]i32, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad1: [2]u32, - size: off_t, - __pad2: i32, + .arm, .armeb, .thumb, .thumbeb, .x86 => extern struct { + dev: c_ulonglong, + __dev_padding: c_int = 0, + __ino_truncated: c_long = 0, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __rdev_pading: c_int = 0, + size: c_longlong, + blksize: c_long, + blocks: c_longlong, + __atim32: [2]c_long, + __mtim32: [2]c_long, + __ctim32: [2]c_long, + ino: c_ulonglong, atim: timespec, mtim: timespec, ctim: timespec, - blksize: blksize_t, - __pad3: u32, - blocks: blkcnt_t, - __pad4: [14]i32, pub fn atime(self: @This()) timespec { return self.atim; @@ -6529,24 +6823,27 @@ pub const Stat = switch (native_os) { pub fn ctime(self: @This()) timespec { return self.ctim; } - } else extern struct { - dev: dev_t, - __pad0: [3]u32, - ino: ino_t, - mode: mode_t, - nlink: nlink_t, - uid: uid_t, - gid: gid_t, - rdev: dev_t, - __pad1: [3]u32, - size: off_t, + }, + .m68k => extern struct { + dev: c_ulonglong, + __dev_padding: c_short = 0, + __ino_truncated: c_long = 0, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __rdev_padding: c_short = 0, + size: c_longlong, + blksize: c_long, + blocks: c_longlong, + __atim32: [2]c_long, + __mtim32: [2]c_long, + __ctim32: [2]c_long, + ino: c_ulonglong, atim: timespec, mtim: timespec, ctim: timespec, - blksize: blksize_t, - __pad3: u32, - blocks: blkcnt_t, - __pad4: [14]i32, pub fn atime(self: @This()) timespec { return self.atim; @@ -6560,9 +6857,251 @@ pub const Stat = switch (native_os) { return self.ctim; } }, + .mips, .mipsel => extern struct { + dev: c_longlong, + __pad1: [2]c_long = .{ 0, 0 }, + ino: c_ulonglong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_longlong, + __pad2: [2]c_long = .{ 0, 0 }, + size: c_longlong, + __atim32: [2]c_long, + __mtim32: [2]c_long, + __ctim32: [2]c_long, + blksize: c_long, + __pad3: c_long = 0, + blocks: c_longlong, + atim: timespec, + mtim: timespec, + ctim: timespec, + __pad4: [2]c_long = .{ 0, 0 }, - else => std.os.linux.Stat, // libc stat is the same as kernel stat. - }, + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .mips64, .mips64el => extern struct { + dev: c_ulong, + __pad1: [3]c_int = .{ 0, 0, 0 }, + ino: c_ulong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad2: [2]c_int = .{ 0, 0 }, + size: c_long, + __pad3: c_int = 0, + atim: timespec, + mtim: timespec, + ctim: timespec, + blksize: c_long, + __pad4: c_uint = 0, + blocks: c_long, + __pad5: [14]c_int = [1]c_int{0} ** 14, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .powerpc => extern struct { + dev: c_ulonglong, + ino: c_ulonglong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __rdev_pading: c_short = 0, + size: c_longlong, + blksize: c_long, + blocks: c_longlong, + __atim32: [2]c_long, + __mtim32: [2]c_long, + __ctim32: [2]c_long, + __unused: [2]c_uint = .{ 0, 0 }, + atim: timespec, + mtim: timespec, + ctim: timespec, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .powerpc64, .powerpc64le => extern struct { + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + size: c_long, + blksize: c_long, + blocks: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [3]c_long = .{ 0, 0, 0 }, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .riscv32 => extern struct { + dev: c_ulonglong, + ino: c_ulonglong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulonglong, + __pad1: c_ulonglong = 0, + size: c_longlong, + blksize: c_int, + __pad2: c_int = 0, + blocks: c_longlong, + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [2]c_uint = .{ 0, 0 }, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .riscv64 => extern struct { + dev: c_ulong, + ino: c_ulong, + mode: c_uint, + nlink: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + __pad1: c_ulong = 0, + size: c_long, + blksize: c_int, + __pad2: c_int = 0, + blocks: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [2]c_uint = .{ 0, 0 }, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .s390x => extern struct { + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + rdev: c_ulong, + size: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + blksize: c_long, + blocks: c_long, + __unused: [3]c_ulong = .{ 0, 0, 0 }, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + .x86_64 => extern struct { + dev: c_ulong, + ino: c_ulong, + nlink: c_ulong, + mode: c_uint, + uid: c_uint, + gid: c_uint, + __pad0: c_uint = 0, + rdev: c_ulong, + size: c_long, + blksize: c_long, + blocks: c_long, + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [3]c_long = .{ 0, 0, 0 }, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } + }, + else => void, + } else void, .emscripten => emscripten.Stat, .wasi => extern struct { dev: dev_t, @@ -8998,11 +9537,21 @@ pub const close = switch (native_os) { pub const clock_getres = switch (native_os) { .netbsd => private.__clock_getres50, - else => private.clock_getres, + else => blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__clock_getres64; + if (native_abi.isMusl()) break :blk vlfts.__clock_getres_time64; + } + break :blk private.clock_getres; + }, }; pub const clock_gettime = switch (native_os) { .netbsd => private.__clock_gettime50, + .linux => if (vlfts.time64_abi) + vlfts.__clock_gettime64 + else + private.clock_gettime, else => private.clock_gettime, }; @@ -9012,7 +9561,14 @@ pub const fstat = switch (native_os) { else => private.fstat, }, .netbsd => private.__fstat50, - else => private.fstat, + else => blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__fstat64_time64; + if (native_abi.isMusl()) break :blk vlfts.__fstat_time64; + } + if (vlfts.largefile_abi) break :blk vlfts.fstat64; + break :blk private.fstat; + }, }; pub const fstatat = switch (native_os) { @@ -9020,31 +9576,30 @@ pub const fstatat = switch (native_os) { .x86_64 => private.@"fstatat$INODE64", else => private.fstatat, }, + .linux => blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__fstatat64_time64; + if (native_abi.isMusl()) break :blk vlfts.__fstatat_time64; + } + if (vlfts.largefile_abi) break :blk vlfts.fstatat64; + break :blk private.fstatat; + }, else => private.fstatat, }; pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd; pub extern "c" fn getpwuid(uid: uid_t) ?*passwd; -pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int; -pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64; -pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque; -pub extern "c" fn open64(path: [*:0]const u8, oflag: O, ...) c_int; -pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int; -pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize; -pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize; -pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: i64) isize; -pub extern "c" fn pwritev64(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: i64) isize; -pub extern "c" fn sendfile64(out_fd: fd_t, in_fd: fd_t, offset: ?*i64, count: usize) isize; -pub extern "c" fn setrlimit64(resource: rlimit_resource, rlim: *const rlimit) c_int; pub const arc4random_buf = switch (native_os) { .dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .macos, .ios, .tvos, .watchos, .visionos => private.arc4random_buf, else => {}, }; + pub const getentropy = switch (native_os) { .emscripten => private.getentropy, else => {}, }; + pub const getrandom = switch (native_os) { .freebsd => private.getrandom, .linux => if (versionCheck(.{ .major = 2, .minor = 25, .patch = 0 })) private.getrandom else {}, @@ -9065,29 +9620,30 @@ pub extern "c" fn epoll_pwait( sigmask: *const sigset_t, ) c_int; -pub extern "c" fn timerfd_create(clockid: clockid_t, flags: c_int) c_int; -pub extern "c" fn timerfd_settime( - fd: c_int, - flags: c_int, - new_value: *const itimerspec, - old_value: ?*itimerspec, -) c_int; -pub extern "c" fn timerfd_gettime(fd: c_int, curr_value: *itimerspec) c_int; +pub const timerfd_create = switch (native_os) { + .linux, .illumos, .freebsd, .netbsd => private.timerfd_create, + else => {}, +}; +pub const timerfd_settime = switch (native_os) { + .linux => if (vlfts.time64_abi) vlfts.__timerfd_settime64 else private.timerfd_settime, + .illumos, .freebsd, .netbsd => private.timerfd_settime, + else => {}, +}; +pub const timerfd_gettime = switch (native_os) { + .linux => if (vlfts.time64_abi) vlfts.__timerfd_gettime64 else private.timerfd_gettime, + .illumos, .freebsd, .netbsd => private.timerfd_gettime, + else => {}, +}; pub extern "c" fn inotify_init1(flags: c_uint) c_int; pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*:0]const u8, mask: u32) c_int; pub extern "c" fn inotify_rm_watch(fd: fd_t, wd: c_int) c_int; -pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int; -pub extern "c" fn fstatat64(dirfd: fd_t, noalias path: [*:0]const u8, noalias stat_buf: *Stat, flags: u32) c_int; -pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int; -pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE; -pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int; -pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int; +pub const fallocate = if (vlfts.largefile_abi) vlfts.fallocate64 else private.fallocate; pub const sendfile = switch (native_os) { .freebsd => freebsd.sendfile, .macos, .ios, .tvos, .watchos, .visionos => darwin.sendfile, - .linux => private.sendfile, + .linux => if (vlfts.largefile_abi) vlfts.sendfile64 else private.sendfile, else => {}, }; /// See std.elf for constants for this @@ -9100,7 +9656,10 @@ pub const sigaltstack = switch (native_os) { else => private.sigaltstack, }; -pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int; +pub const memfd_create = switch (native_os) { + .linux, .freebsd => private.memfd_create, + else => {}, +}; pub const pipe2 = switch (native_os) { .dragonfly, .emscripten, .netbsd, .freebsd, .solaris, .illumos, .openbsd, .linux => private.pipe2, else => {}, @@ -9113,7 +9672,6 @@ pub const copy_file_range = switch (native_os) { pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int; -pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int; pub extern "c" fn mincore( addr: *align(std.mem.page_size) anyopaque, length: usize, @@ -9126,24 +9684,39 @@ pub extern "c" fn madvise( advice: u32, ) c_int; -pub const getdirentries = switch (native_os) { - .macos, .ios, .tvos, .watchos, .visionos => private.__getdirentries64, - else => private.getdirentries, -}; +pub const getdirentries = if (native_os.isDarwin()) + private.__getdirentries64 +else if (vlfts.largefile_abi) + vlfts.getdirentries64 +else + private.getdirentries; pub const getdents = switch (native_os) { .netbsd => private.__getdents30, - else => private.getdents, + else => if (vlfts.largefile_abi) vlfts.getdents64 else private.getdents, }; pub const getrusage = switch (native_os) { .netbsd => private.__getrusage50, - else => private.getrusage, + else => blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__getrusage64; + if (native_abi.isMusl()) break :blk vlfts.__getrusage_time64; + } + if (vlfts.largefile_abi) break :blk vlfts.__getrusage64; + break :blk private.getrusage; + }, }; pub const gettimeofday = switch (native_os) { .netbsd => private.__gettimeofday50, - else => private.gettimeofday, + else => blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__gettimeofday64; + if (native_abi.isMusl()) break :blk vlfts.__gettimeofday_time64; + } + break :blk private.gettimeofday; + }, }; pub const msync = switch (native_os) { @@ -9153,7 +9726,13 @@ pub const msync = switch (native_os) { pub const nanosleep = switch (native_os) { .netbsd => private.__nanosleep50, - else => private.nanosleep, + else => blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__nanosleep64; + if (native_abi.isMusl()) break :blk vlfts.__nanosleep_time64; + } + break :blk private.nanosleep; + }, }; pub const readdir = switch (native_os) { @@ -9162,7 +9741,7 @@ pub const readdir = switch (native_os) { else => private.readdir, }, .windows => {}, - else => private.readdir, + else => if (vlfts.largefile_abi) vlfts.readdir64 else private.readdir, }; pub const realpath = switch (native_os) { @@ -9200,7 +9779,14 @@ pub const stat = switch (native_os) { .x86_64 => private.@"stat$INODE64", else => private.stat, }, - else => private.stat, + else => blk: { + if (vlfts.time64_abi) { + if (builtin.abi.isGnu()) break :blk vlfts.__stat64_time64; + if (builtin.abi.isMusl()) break :blk vlfts.__stat_time64; + } + if (vlfts.largefile_abi) break :blk vlfts.stat64; + break :blk private.stat; + }, }; pub const _msize = switch (native_os) { @@ -9237,7 +9823,7 @@ pub const flock = switch (native_os) { pub extern "c" var environ: [*:null]?[*:0]u8; -pub extern "c" fn fopen(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE; +pub const fopen = if (vlfts.largefile_abi) vlfts.fopen64 else private.fopen; pub extern "c" fn fclose(stream: *FILE) c_int; pub extern "c" fn fwrite(noalias ptr: [*]const u8, size_of_type: usize, item_count: usize, noalias stream: *FILE) usize; pub extern "c" fn fread(noalias ptr: [*]u8, size_of_type: usize, item_count: usize, noalias stream: *FILE) usize; @@ -9247,20 +9833,20 @@ pub extern "c" fn abort() noreturn; pub extern "c" fn exit(code: c_int) noreturn; pub extern "c" fn _exit(code: c_int) noreturn; pub extern "c" fn isatty(fd: fd_t) c_int; -pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: whence_t) off_t; -pub extern "c" fn open(path: [*:0]const u8, oflag: O, ...) c_int; -pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int; -pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int; +pub const lseek = if (vlfts.largefile_abi) vlfts.lseek64 else private.lseek; +pub const open = if (vlfts.largefile_abi) vlfts.open64 else private.open; +pub const openat = if (vlfts.largefile_abi) vlfts.openat64 else private.openat; +pub const ftruncate = if (vlfts.largefile_abi) vlfts.ftruncate64 else private.ftruncate; pub extern "c" fn raise(sig: c_int) c_int; pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize; -pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: off_t) isize; -pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: off_t) isize; -pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) isize; -pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize; +pub const pread = if (vlfts.largefile_abi) vlfts.pread64 else private.pread; +pub const preadv = if (vlfts.largefile_abi) vlfts.preadv64 else private.preadv; pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize; -pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize; -pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: fd_t, offset: off_t) *anyopaque; +pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) isize; +pub const mmap = if (vlfts.largefile_abi) vlfts.mmap64 else private.mmap; +pub const pwrite = if (vlfts.largefile_abi) vlfts.pwrite64 else private.pwrite; +pub const pwritev = if (vlfts.largefile_abi) vlfts.pwritev64 else private.pwritev; pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int; pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int; pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8) c_int; @@ -9269,7 +9855,7 @@ pub extern "c" fn unlink(path: [*:0]const u8) c_int; pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int; pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; pub extern "c" fn waitpid(pid: pid_t, status: ?*c_int, options: c_int) pid_t; -pub extern "c" fn wait4(pid: pid_t, status: ?*c_int, options: c_int, ru: ?*rusage) pid_t; +pub const wait4 = if (vlfts.time64_abi) vlfts.__wait4_time64 else private.wait4; pub const fork = switch (native_os) { .dragonfly, .freebsd, @@ -9317,8 +9903,14 @@ pub extern "c" fn sysctlbyname(name: [*:0]const u8, oldp: ?*anyopaque, oldlenp: pub extern "c" fn sysctlnametomib(name: [*:0]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int; pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int; -pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int; -pub extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int; +pub const fcntl = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.__fcntl_time64 +else + private.fcntl; +pub const ioctl = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.__ioctl_time64 +else + private.ioctl; pub extern "c" fn uname(buf: *utsname) c_int; pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; @@ -9331,8 +9923,14 @@ pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias add pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; pub extern "c" fn accept(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t) c_int; pub extern "c" fn accept4(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t, flags: c_uint) c_int; -pub extern "c" fn getsockopt(sockfd: fd_t, level: i32, optname: u32, noalias optval: ?*anyopaque, noalias optlen: *socklen_t) c_int; -pub extern "c" fn setsockopt(sockfd: fd_t, level: i32, optname: u32, optval: ?*const anyopaque, optlen: socklen_t) c_int; +pub const getsockopt = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.__getsockopt64 +else + private.getsockopt; +pub const setsockopt = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.__setsockopt64 +else + private.setsockopt; pub extern "c" fn send(sockfd: fd_t, buf: *const anyopaque, len: usize, flags: u32) isize; pub extern "c" fn sendto( sockfd: fd_t, @@ -9342,8 +9940,10 @@ pub extern "c" fn sendto( dest_addr: ?*const sockaddr, addrlen: socklen_t, ) isize; -pub extern "c" fn sendmsg(sockfd: fd_t, msg: *const msghdr_const, flags: u32) isize; - +pub const sendmsg = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.__sendmsg64 +else + private.sendmsg; pub extern "c" fn recv( sockfd: fd_t, arg1: ?*anyopaque, @@ -9358,7 +9958,10 @@ pub extern "c" fn recvfrom( noalias src_addr: ?*sockaddr, noalias addrlen: ?*socklen_t, ) if (native_os == .windows) c_int else isize; -pub extern "c" fn recvmsg(sockfd: fd_t, msg: *msghdr, flags: u32) isize; +pub const recvmsg = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.__recvmsg64 +else + private.recvmsg; pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int; @@ -9376,11 +9979,34 @@ pub extern "c" fn malloc(usize) ?*anyopaque; pub extern "c" fn realloc(?*anyopaque, usize) ?*anyopaque; pub extern "c" fn free(?*anyopaque) void; -pub extern "c" fn futimes(fd: fd_t, times: *[2]timeval) c_int; -pub extern "c" fn utimes(path: [*:0]const u8, times: *[2]timeval) c_int; - -pub extern "c" fn utimensat(dirfd: fd_t, pathname: [*:0]const u8, times: *[2]timespec, flags: u32) c_int; -pub extern "c" fn futimens(fd: fd_t, times: *const [2]timespec) c_int; +pub const utimes = blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__utimes64; + if (native_abi.isMusl()) break :blk vlfts.__utimes_time64; + } + break :blk private.utimes; +}; +pub const futimes = blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__futimes64; + if (native_abi.isMusl()) break :blk vlfts.__futimes_time64; + } + break :blk private.futimes; +}; +pub const utimensat = blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__utimensat64; + if (native_abi.isMusl()) break :blk vlfts.__utimensat_time64; + } + break :blk private.utimensat; +}; +pub const futimens = blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__futimens64; + if (native_abi.isMusl()) break :blk vlfts.__futimens_time64; + } + break :blk private.futimens; +}; pub extern "c" fn pthread_create( noalias newthread: *pthread_t, @@ -9514,7 +10140,13 @@ pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) E; pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{}; pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) E; -pub extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) E; +pub const pthread_cond_timedwait = blk: { + if (vlfts.time64_abi) { + if (native_abi.isGnu()) break :blk vlfts.__pthread_cond_timedwait64; + if (native_abi.isMusl()) break :blk vlfts.__pthread_cond_timedwait_time64; + } + break :blk private.pthread_cond_timedwait; +}; pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) E; pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) E; pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) E; @@ -9539,10 +10171,23 @@ pub extern "c" fn syncfs(fd: c_int) c_int; pub extern "c" fn fsync(fd: c_int) c_int; pub extern "c" fn fdatasync(fd: c_int) c_int; -pub extern "c" fn prctl(option: c_int, ...) c_int; +pub const prctl = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.__prctl_time64 +else + private.prctl; -pub extern "c" fn getrlimit(resource: rlimit_resource, rlim: *rlimit) c_int; -pub extern "c" fn setrlimit(resource: rlimit_resource, rlim: *const rlimit) c_int; +pub const getrlimit = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.getrlimit64 +else + private.getrlimit; +pub const setrlimit = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.setrlimit64 +else + private.setrlimit; +pub const prlimit = if (vlfts.time64_abi and native_abi.isGnu()) + vlfts.prlimit64 +else + private.prlimit; pub extern "c" fn fmemopen(noalias buf: ?*anyopaque, size: usize, noalias mode: [*:0]const u8) ?*FILE; @@ -9881,47 +10526,75 @@ pub const umtx_wakeup = dragonfly.umtx_wakeup; /// External definitions shared by two or more operating systems. const private = struct { - extern "c" fn close(fd: fd_t) c_int; + extern "c" fn _msize(memblock: ?*anyopaque) usize; + extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void; extern "c" fn clock_getres(clk_id: clockid_t, tp: *timespec) c_int; extern "c" fn clock_gettime(clk_id: clockid_t, tp: *timespec) c_int; + extern "c" fn close(fd: fd_t) c_int; extern "c" fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, len: usize, flags: c_uint) isize; + extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int; + extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int; extern "c" fn flock(fd: fd_t, operation: c_int) c_int; + extern "c" fn fopen(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE; extern "c" fn fork() c_int; extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, buf: *Stat, flag: u32) c_int; - extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; + extern "c" fn futimens(fd: fd_t, times: *const [2]timespec) c_int; + extern "c" fn futimes(fd: fd_t, times: *const [2]timeval) c_int; + extern "c" fn getcontext(ucp: *ucontext_t) c_int; extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) switch (native_os) { .freebsd => isize, .solaris, .illumos => usize, else => c_int, }; + extern "c" fn ftruncate(fd: c_int, length: off_t) c_int; + extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; + extern "c" fn getentropy(buffer: [*]u8, size: usize) c_int; + extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize; + extern "c" fn getrlimit(resource: rlimit_resource, rlim: *rlimit) c_int; extern "c" fn getrusage(who: c_int, usage: *rusage) c_int; + extern "c" fn getsockopt(sockfd: fd_t, level: i32, optname: u32, noalias optval: ?*anyopaque, noalias optlen: *socklen_t) c_int; extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; + extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int; + extern "c" fn lseek(fd: fd_t, offset: off_t, whence: whence_t) off_t; + extern "c" fn malloc_size(?*const anyopaque) usize; + extern "c" fn malloc_usable_size(?*const anyopaque) usize; + extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int; extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int; + extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque; extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; + extern "c" fn open(path: [*:0]const u8, oflag: O, ...) c_int; + extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int; extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int; + extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int; + extern "c" fn prctl(option: c_int, ...) c_int; + extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: off_t) isize; + extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: off_t) isize; + extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int; + extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) E; + extern "c" fn pthread_setname_np(thread: pthread_t, name: [*:0]const u8) c_int; + extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize; + extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize; extern "c" fn readdir(dir: *DIR) ?*dirent; extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; + extern "c" fn recvmsg(sockfd: fd_t, msg: *msghdr, flags: u32) isize; extern "c" fn sched_yield() c_int; extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize; + extern "c" fn sendmsg(sockfd: fd_t, msg: *const msghdr_const, flags: u32) isize; + extern "c" fn setrlimit(resource: rlimit_resource, rlim: *const rlimit) c_int; + extern "c" fn setsockopt(sockfd: fd_t, level: i32, optname: u32, optval: ?*const anyopaque, optlen: socklen_t) c_int; extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; + extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; extern "c" fn sigfillset(set: ?*sigset_t) void; extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; - extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; - - extern "c" fn pthread_setname_np(thread: pthread_t, name: [*:0]const u8) c_int; - extern "c" fn getcontext(ucp: *ucontext_t) c_int; - - extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize; - extern "c" fn getentropy(buffer: [*]u8, size: usize) c_int; - extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void; - - extern "c" fn _msize(memblock: ?*anyopaque) usize; - extern "c" fn malloc_size(?*const anyopaque) usize; - extern "c" fn malloc_usable_size(?*const anyopaque) usize; - extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int; + extern "c" fn timerfd_create(clockid: clockid_t, flags: TFD) c_int; + extern "c" fn timerfd_gettime(fd: i32, curr_value: *itimerspec) c_int; + extern "c" fn timerfd_settime(fd: i32, flags: TFD.TIMER, new_value: *const itimerspec, old_value: ?*itimerspec) c_int; + extern "c" fn utimensat(dirfd: fd_t, pathname: [*:0]const u8, times: *const [2]timespec, flags: u32) c_int; + extern "c" fn utimes(path: [*:0]const u8, times: ?*const [2]timeval) c_int; + extern "c" fn wait4(pid: pid_t, status: ?*c_int, options: c_int, ru: ?*rusage) pid_t; /// macos modernized symbols. /// x86_64 links to $INODE64 suffix for 64-bit support. @@ -9932,32 +10605,30 @@ const private = struct { extern "c" fn @"stat$INODE64"(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; /// macos modernized symbols. - extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; extern "c" fn __getdirentries64(fd: fd_t, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize; - + extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; extern "c" fn pthread_threadid_np(thread: ?pthread_t, thread_id: *u64) c_int; /// netbsd modernized symbols. extern "c" fn __clock_getres50(clk_id: clockid_t, tp: *timespec) c_int; extern "c" fn __clock_gettime50(clk_id: clockid_t, tp: *timespec) c_int; extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int; + extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int; extern "c" fn __getrusage50(who: c_int, usage: *rusage) c_int; extern "c" fn __gettimeofday50(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; extern "c" fn __libc_thr_yield() c_int; extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int; extern "c" fn __nanosleep50(rqtp: *const timespec, rmtp: ?*timespec) c_int; extern "c" fn __sigaction14(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; + extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int; extern "c" fn __sigfillset14(set: ?*sigset_t) void; extern "c" fn __sigprocmask14(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; extern "c" fn __socket30(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; extern "c" fn __stat50(path: [*:0]const u8, buf: *Stat) c_int; - extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int; - extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int; // Don't forget to add another clown when an OS picks yet another unique // symbol name for errno location! // 🤡🤡🤡🤡🤡🤡 - extern "c" fn ___errno() *c_int; extern "c" fn __errno() *c_int; extern "c" fn __errno_location() *c_int; diff --git a/lib/std/c/vlfts.zig b/lib/std/c/vlfts.zig new file mode 100644 index 000000000000..859c9fe9eac7 --- /dev/null +++ b/lib/std/c/vlfts.zig @@ -0,0 +1,154 @@ +//! VLFTS - Very Large File and Time Symbols. +//! This file contains a list of symbols exported by glibc/musl that support using +//! 64-bit file offsets and 64-bit seconds in timestamps (or both!). +const std = @import("std"); +const builtin = @import("builtin"); +const c = std.c; + +const clockid_t = c.clockid_t; +const DIR = c.DIR; +const dirent = c.dirent; +const E = c.E; +const fd_t = c.fd_t; +const FILE = c.FILE; +const iovec = c.iovec; +const iovec_const = c.iovec_const; +const itimerspec = c.itimerspec; +const MAP = c.MAP; +const msghdr = c.msghdr; +const O = c.O; +const off_t = c.off_t; +const page_size = std.mem.page_size; +const pid_t = c.pid_t; +const pthread_cond_t = c.pthread_cond_t; +const pthread_mutex_t = c.pthread_mutex_t; +const rlimit = c.rlimit; +const rlimit_resource = c.rlimit_resource; +const rusage = c.rusage; +const sem_t = c.sem_t; +const socklen_t = c.socklen_t; +const Stat = c.Stat; +const TFD = c.TFD; +const timespec = c.timespec; +const timeval = c.timeval; +const timezone = c.timezone; +const usize_bits = @typeInfo(usize).int.bits; + +/// True if this target should use the "largefile" ABI. +/// This is only true when linking against glibc, as: +/// - musl always uses 64-bit file offsets. +/// - The largefile symbols are weakly linked to the normal symbols on 64-bit targets, +/// while musl defines them in the header files. +pub const largefile_abi = builtin.os.tag == .linux and + builtin.link_libc and + builtin.abi.isGnu(); + +/// True if this target should use the "time64" ABI. +pub const time64_abi = builtin.os.tag == .linux and + builtin.link_libc and + (builtin.abi.isGnu() or builtin.abi.isMusl()) and + switch (builtin.cpu.arch) { + // 32-bit targets. + .arm, + .armeb, + .csky, + .hexagon, + .m68k, + .mips, + .mipsel, + .powerpc, + .powerpcle, + .sparc, + .thumb, + .thumbeb, + .xtensa, + => true, + // 64-bit targets. + .aarch64_be, + .aarch64, + .loongarch64, + .powerpc64, + .powerpc64le, + .riscv64, + .s390x, + .sparc64, + .x86_64, + => false, + // Modern 32-bit targets with 64-bit time. + // See the glibc headers and . + .arc, + .riscv32, + .loongarch32, + => false, + // 64-bit targets running in a 32-bit mode. + .mips64, + .mips64el, + => builtin.abi == .gnuabin32, + .x86 => builtin.abi != .gnux32, + else => @compileError("unsupported abi"), +}; + +// Symbols shared between both c libraries. +pub extern "c" fn __clock_gettime64(clk_id: clockid_t, tp: *timespec) c_int; +pub extern "c" fn __clock_nanosleep_time64(clockid: clockid_t, flags: u32, t: *const timespec, remain: ?*timespec) c_int; +pub extern "c" fn __clock_settime64(clk_id: clockid_t, tp: *const timespec) c_int; +pub extern "c" fn __ioctl_time64(fd: fd_t, request: c_int, ...) c_int; +pub extern "c" fn __sem_timedwait64(sem: *sem_t, abs_timeout: *const timespec) c_int; +pub extern "c" fn __timerfd_gettime64(fd: i32, curr_value: *itimerspec) c_int; +pub extern "c" fn __timerfd_settime64(fd: i32, flags: TFD.TIMER, noalias new_value: *const itimerspec, noalias old_value: ?*itimerspec) c_int; +pub extern "c" fn __wait4_time64(pid: pid_t, rstatus: ?*c_int, options: c_int, ru: ?*rusage) pid_t; +// glibc specific +pub extern "c" fn __adjtime64(delta: *const timeval, olddelta: *timeval) c_int; +pub extern "c" fn __clock_getres64(clk_id: clockid_t, tp: ?*timespec) c_int; +pub extern "c" fn __fcntl_time64(fd: fd_t, cmd: c_int, ...) c_int; +pub extern "c" fn __fstat64_time64(fd: fd_t, buf: *Stat) c_int; +pub extern "c" fn __fstatat64_time64(dirfd: fd_t, noalias path: [*:0]const u8, noalias buf: *Stat, flag: u32) c_int; +pub extern "c" fn __futimens64(fd: fd_t, times: ?*const [2]timespec) c_int; +pub extern "c" fn __futimes64(fd: fd_t, times: *[2]timeval) c_int; +pub extern "c" fn __getrusage64(who: c_int, usage: *rusage) c_int; +pub extern "c" fn __getsockopt64(sockfd: fd_t, level: i32, optname: u32, noalias optval: ?*anyopaque, noalias optlen: *socklen_t) c_int; +pub extern "c" fn __gettimeofday64(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; +pub extern "c" fn __nanosleep64(rqtp: *const timespec, rmtp: ?*timespec) c_int; +pub extern "c" fn __prctl_time64(option: c_int, ...) c_int; +pub extern "c" fn __pthread_cond_timedwait64(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) E; +pub extern "c" fn __recvmsg64(sockfd: fd_t, msg: *msghdr, flags: u32) isize; +pub extern "c" fn __sendmsg64(sockfd: fd_t, msg: *const msghdr, flags: u32) c_int; +pub extern "c" fn __setsockopt64(sockfd: fd_t, level: i32, optname: u32, optval: ?*const anyopaque, optlen: socklen_t) c_int; +pub extern "c" fn __stat64_time64(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; +pub extern "c" fn __utimensat64(dirfd: fd_t, pathname: [*:0]const u8, times: ?*const [2]timespec, flags: u32) c_int; +pub extern "c" fn __utimes64(path: [*:0]const u8, times: *[2]timeval) c_int; +pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int; +pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE; +pub extern "c" fn fstat64(fd: fd_t, buf: *Stat) c_int; +pub extern "c" fn fstatat64(dirfd: fd_t, noalias path: [*:0]const u8, noalias stat_buf: *Stat, flags: u32) c_int; +pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int; +pub extern "c" fn getdents64(fd: c_int, buf_ptr: [*]u8, nbytes: usize) isize; +pub extern "c" fn getdirentries64(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; +pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int; +pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64; +pub extern "c" fn mmap64(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque; +pub extern "c" fn open64(path: [*:0]const u8, oflag: O, ...) c_int; +pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int; +pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize; +pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize; +pub extern "c" fn prlimit64(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int; +pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: i64) isize; +pub extern "c" fn pwritev64(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: i64) isize; +pub extern "c" fn readdir64(dir: *DIR) ?*dirent; +pub extern "c" fn sendfile64(out_fd: fd_t, in_fd: fd_t, offset: ?*i64, count: usize) isize; +pub extern "c" fn setrlimit64(resource: rlimit_resource, rlim: *const rlimit) c_int; +pub extern "c" fn stat64(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; +pub extern "c" fn truncate64(path: [*:0]const u8, length: off_t) c_int; +// musl specific +pub extern "c" fn __clock_getres_time64(clk_id: clockid_t, tp: ?*timespec) c_int; +pub extern "c" fn __fstat_time64(fd: fd_t, buf: *Stat) c_int; +pub extern "c" fn __fstatat_time64(dirfd: fd_t, noalias path: [*:0]const u8, noalias buf: *Stat, flag: u32) c_int; +pub extern "c" fn __futimens_time64(fd: fd_t, times: ?*const [2]timespec) c_int; +pub extern "c" fn __futimes_time64(fd: fd_t, times: *[2]timeval) c_int; +pub extern "c" fn __getrusage_time64(who: c_int, usage: *rusage) c_int; +pub extern "c" fn __gettimeofday_time64(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; +pub extern "c" fn __nanosleep_time64(rqtp: *const timespec, rmtp: ?*timespec) c_int; +pub extern "c" fn __pthread_cond_timedwait_time64(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) E; +pub extern "c" fn __stat_time64(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; +pub extern "c" fn __utimensat_time64(dirfd: fd_t, pathname: [*:0]const u8, times: ?*const [2]timespec, flags: u32) c_int; +pub extern "c" fn __utimes_time64(path: [*:0]const u8, times: *[2]timeval) c_int; diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 85fe0b317be7..ff9e9670773d 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -997,9 +997,8 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { else => maxInt(isize), }; - const pread_sym = if (lfs64_abi) system.pread64 else system.pread; while (true) { - const rc = pread_sym(fd, buf.ptr, @min(buf.len, max_count), @bitCast(offset)); + const rc = system.pread(fd, buf.ptr, @min(buf.len, max_count), @bitCast(offset)); switch (errno(rc)) { .SUCCESS => return @intCast(rc), .INTR => continue, @@ -1070,9 +1069,8 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { } } - const ftruncate_sym = if (lfs64_abi) system.ftruncate64 else system.ftruncate; while (true) { - switch (errno(ftruncate_sym(fd, @bitCast(length)))) { + switch (errno(system.ftruncate(fd, @bitCast(length)))) { .SUCCESS => return, .INTR => continue, .FBIG => return error.FileTooBig, @@ -1135,9 +1133,8 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { } } - const preadv_sym = if (lfs64_abi) system.preadv64 else system.preadv; while (true) { - const rc = preadv_sym(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset)); + const rc = system.preadv(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset)); switch (errno(rc)) { .SUCCESS => return @bitCast(rc), .INTR => continue, @@ -1413,9 +1410,8 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { else => maxInt(isize), }; - const pwrite_sym = if (lfs64_abi) system.pwrite64 else system.pwrite; while (true) { - const rc = pwrite_sym(fd, bytes.ptr, @min(bytes.len, max_count), @bitCast(offset)); + const rc = system.pwrite(fd, bytes.ptr, @min(bytes.len, max_count), @bitCast(offset)); switch (errno(rc)) { .SUCCESS => return @intCast(rc), .INTR => continue, @@ -1498,9 +1494,8 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz } } - const pwritev_sym = if (lfs64_abi) system.pwritev64 else system.pwritev; while (true) { - const rc = pwritev_sym(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset)); + const rc = system.pwritev(fd, iov.ptr, @min(iov.len, IOV_MAX), @bitCast(offset)); switch (errno(rc)) { .SUCCESS => return @intCast(rc), .INTR => continue, @@ -1618,9 +1613,8 @@ pub fn openZ(file_path: [*:0]const u8, flags: O, perm: mode_t) OpenError!fd_t { return open(mem.sliceTo(file_path, 0), flags, perm); } - const open_sym = if (lfs64_abi) system.open64 else system.open; while (true) { - const rc = open_sym(file_path, flags, perm); + const rc = system.open(file_path, flags, perm); switch (errno(rc)) { .SUCCESS => return @intCast(rc), .INTR => continue, @@ -1697,37 +1691,44 @@ pub fn openatWasi( base: wasi.rights_t, inheriting: wasi.rights_t, ) OpenError!fd_t { - while (true) { - var fd: fd_t = undefined; - switch (wasi.path_open(dir_fd, lookup_flags, file_path.ptr, file_path.len, oflags, base, inheriting, fdflags, &fd)) { - .SUCCESS => return fd, - .INTR => continue, - - .FAULT => unreachable, - // Provides INVAL with a linux host on a bad path name, but NOENT on Windows - .INVAL => return error.BadPathName, - .BADF => unreachable, - .ACCES => return error.AccessDenied, - .FBIG => return error.FileTooBig, - .OVERFLOW => return error.FileTooBig, - .ISDIR => return error.IsDir, - .LOOP => return error.SymLinkLoop, - .MFILE => return error.ProcessFdQuotaExceeded, - .NAMETOOLONG => return error.NameTooLong, - .NFILE => return error.SystemFdQuotaExceeded, - .NODEV => return error.NoDevice, - .NOENT => return error.FileNotFound, - .NOMEM => return error.SystemResources, - .NOSPC => return error.NoSpaceLeft, - .NOTDIR => return error.NotDir, - .PERM => return error.AccessDenied, - .EXIST => return error.PathAlreadyExists, - .BUSY => return error.DeviceBusy, - .NOTCAPABLE => return error.AccessDenied, - .ILSEQ => return error.InvalidUtf8, - else => |err| return unexpectedErrno(err), - } - } + var fd: fd_t = undefined; + while (true) switch (wasi.path_open( + dir_fd, + lookup_flags, + file_path.ptr, + file_path.len, + oflags, + base, + inheriting, + fdflags, + &fd, + )) { + .SUCCESS => return fd, + .INTR => continue, + .FAULT => unreachable, + // Provides INVAL with a linux host on a bad path name, but NOENT on Windows + .INVAL => return error.BadPathName, + .BADF => unreachable, + .ACCES => return error.AccessDenied, + .FBIG => return error.FileTooBig, + .OVERFLOW => return error.FileTooBig, + .ISDIR => return error.IsDir, + .LOOP => return error.SymLinkLoop, + .MFILE => return error.ProcessFdQuotaExceeded, + .NAMETOOLONG => return error.NameTooLong, + .NFILE => return error.SystemFdQuotaExceeded, + .NODEV => return error.NoDevice, + .NOENT => return error.FileNotFound, + .NOMEM => return error.SystemResources, + .NOSPC => return error.NoSpaceLeft, + .NOTDIR => return error.NotDir, + .PERM => return error.AccessDenied, + .EXIST => return error.PathAlreadyExists, + .BUSY => return error.DeviceBusy, + .NOTCAPABLE => return error.AccessDenied, + .ILSEQ => return error.InvalidUtf8, + else => |err| return unexpectedErrno(err), + }; } /// A struct to contain all lookup/rights flags accepted by `wasi.path_open` @@ -1788,9 +1789,8 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: O, mode: mode_t) O return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode); } - const openat_sym = if (lfs64_abi) system.openat64 else system.openat; while (true) { - const rc = openat_sym(dir_fd, file_path, flags, mode); + const rc = system.openat(dir_fd, file_path, flags, mode); switch (errno(rc)) { .SUCCESS => return @intCast(rc), .INTR => continue, @@ -4361,9 +4361,8 @@ pub fn fstat(fd: fd_t) FStatError!Stat { else => |e| e, }; - const fstat_sym = if (lfs64_abi) system.fstat64 else system.fstat; var stat = mem.zeroes(Stat); - switch (errno(fstat_sym(fd, &stat))) { + switch (errno(system.fstat(fd, &stat))) { .SUCCESS => return stat, .INVAL => unreachable, .BADF => unreachable, // Always a race condition. @@ -4467,9 +4466,8 @@ fn fstatatLinux( /// Same as `fstatat` but for targets using libc. fn fstatatC(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat { - const sym = if (lfs64_abi) system.fstatat64 else system.fstatat; var stat = mem.zeroes(Stat); - return switch (errno(sym(dirfd, pathname, &stat, flags))) { + return switch (errno(system.fstatat(dirfd, pathname, &stat, flags))) { .SUCCESS => stat, .INVAL => unreachable, .BADF => unreachable, // Always a race condition. @@ -4797,8 +4795,7 @@ pub fn mmap( fd: fd_t, offset: u64, ) MMapError![]align(mem.page_size) u8 { - const mmap_sym = if (lfs64_abi) system.mmap64 else system.mmap; - const rc = mmap_sym(ptr, length, prot, @bitCast(flags), fd, @bitCast(offset)); + const rc = system.mmap(ptr, length, prot, @bitCast(flags), fd, @bitCast(offset)); const err: E = if (builtin.link_libc) blk: { if (rc != std.c.MAP_FAILED) return @as([*]align(mem.page_size) u8, @ptrCast(@alignCast(rc)))[0..length]; break :blk @enumFromInt(system._errno().*); @@ -5217,8 +5214,7 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { } } - const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; - switch (errno(lseek_sym(fd, @bitCast(offset), SEEK.SET))) { + switch (errno(system.lseek(fd, @bitCast(offset), SEEK.SET))) { .SUCCESS => return, .BADF => unreachable, // always a race condition .INVAL => return error.Unseekable, @@ -5259,8 +5255,7 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void { else => |err| return unexpectedErrno(err), } } - const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; - switch (errno(lseek_sym(fd, @bitCast(offset), SEEK.CUR))) { + switch (errno(system.lseek(fd, @bitCast(offset), SEEK.CUR))) { .SUCCESS => return, .BADF => unreachable, // always a race condition .INVAL => return error.Unseekable, @@ -5301,8 +5296,7 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void { else => |err| return unexpectedErrno(err), } } - const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; - switch (errno(lseek_sym(fd, @bitCast(offset), SEEK.END))) { + switch (errno(system.lseek(fd, @bitCast(offset), SEEK.END))) { .SUCCESS => return, .BADF => unreachable, // always a race condition .INVAL => return error.Unseekable, @@ -5343,8 +5337,7 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { else => |err| return unexpectedErrno(err), } } - const lseek_sym = if (lfs64_abi) system.lseek64 else system.lseek; - const rc = lseek_sym(fd, 0, SEEK.CUR); + const rc = system.lseek(fd, 0, SEEK.CUR); switch (errno(rc)) { .SUCCESS => return @bitCast(rc), .BADF => unreachable, // always a race condition @@ -6286,10 +6279,9 @@ pub fn sendfile( // Here we match BSD behavior, making a zero count value send as many bytes as possible. const adjusted_count = if (in_len == 0) max_count else @min(in_len, max_count); - const sendfile_sym = if (lfs64_abi) system.sendfile64 else system.sendfile; while (true) { var offset: off_t = @bitCast(in_offset); - const rc = sendfile_sym(out_fd, in_fd, &offset, adjusted_count); + const rc = system.sendfile(out_fd, in_fd, &offset, adjusted_count); switch (errno(rc)) { .SUCCESS => { const amt: usize = @bitCast(rc); @@ -7104,10 +7096,8 @@ pub fn prctl(option: PR, args: anytype) PrctlError!u31 { pub const GetrlimitError = UnexpectedError; pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit { - const getrlimit_sym = if (lfs64_abi) system.getrlimit64 else system.getrlimit; - var limits: rlimit = undefined; - switch (errno(getrlimit_sym(resource, &limits))) { + switch (errno(system.getrlimit(resource, &limits))) { .SUCCESS => return limits, .FAULT => unreachable, // bogus pointer .INVAL => unreachable, @@ -7118,15 +7108,13 @@ pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit { pub const SetrlimitError = error{ PermissionDenied, LimitTooBig } || UnexpectedError; pub fn setrlimit(resource: rlimit_resource, limits: rlimit) SetrlimitError!void { - const setrlimit_sym = if (lfs64_abi) system.setrlimit64 else system.setrlimit; - - switch (errno(setrlimit_sym(resource, &limits))) { - .SUCCESS => return, + return switch (errno(system.setrlimit(resource, &limits))) { + .SUCCESS => {}, .FAULT => unreachable, // bogus pointer - .INVAL => return error.LimitTooBig, // this could also mean "invalid resource", but that would be unreachable - .PERM => return error.PermissionDenied, - else => |err| return unexpectedErrno(err), - } + .INVAL => error.LimitTooBig, // this could also mean "invalid resource", but that would be unreachable + .PERM => error.PermissionDenied, + else => |err| unexpectedErrno(err), + }; } pub const MincoreError = error{ @@ -7193,18 +7181,18 @@ pub const MadviseError = error{ /// Give advice about use of memory. /// This syscall is optional and is sometimes configured to be disabled. pub fn madvise(ptr: [*]align(mem.page_size) u8, length: usize, advice: u32) MadviseError!void { - switch (errno(system.madvise(ptr, length, advice))) { - .SUCCESS => return, - .PERM => return error.PermissionDenied, - .ACCES => return error.AccessDenied, - .AGAIN => return error.SystemResources, + return switch (errno(system.madvise(ptr, length, advice))) { + .SUCCESS => {}, + .PERM => error.PermissionDenied, + .ACCES => error.AccessDenied, + .AGAIN => error.SystemResources, .BADF => unreachable, // The map exists, but the area maps something that isn't a file. - .INVAL => return error.InvalidSyscall, - .IO => return error.WouldExceedMaximumResidentSetSize, - .NOMEM => return error.OutOfMemory, - .NOSYS => return error.MadviseUnavailable, - else => |err| return unexpectedErrno(err), - } + .INVAL => error.InvalidSyscall, + .IO => error.WouldExceedMaximumResidentSetSize, + .NOMEM => error.OutOfMemory, + .NOSYS => error.MadviseUnavailable, + else => |err| unexpectedErrno(err), + }; } pub const PerfEventOpenError = error{ @@ -7456,8 +7444,6 @@ pub fn ioctl_SIOCGIFINDEX(fd: fd_t, ifr: *ifreq) IoCtl_SIOCGIFINDEX_Error!void { } } -const lfs64_abi = native_os == .linux and builtin.link_libc and builtin.abi.isGnu(); - /// Whether or not `error.Unexpected` will print its value and a stack trace. /// /// If this happens the fix is to add the error code to the corresponding From f5567d5bcebbb300215816536517a488cc2b4534 Mon Sep 17 00:00:00 2001 From: Stephen Gregoratto Date: Tue, 29 Oct 2024 11:16:33 +1100 Subject: [PATCH 6/6] glibc_compat: Refer to lfs64 symbols --- test/link/glibc_compat/build.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/link/glibc_compat/build.zig b/test/link/glibc_compat/build.zig index 29df30151b49..d83f5d4e3f6c 100644 --- a/test/link/glibc_compat/build.zig +++ b/test/link/glibc_compat/build.zig @@ -178,16 +178,16 @@ pub fn build(b: *std.Build) void { // normal dynamic symbol if (glibc_ver.order(.{ .major = 2, .minor = 32, .patch = 0 }) == .lt) { check.checkInDynamicSymtab(); - check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __fxstatat"); + check.checkExact("0 0 UND FUNC GLOBAL DEFAULT __fxstatat64"); check.checkInSymtab(); check.checkContains("FUNC LOCAL HIDDEN fstatat"); } else { check.checkInDynamicSymtab(); - check.checkExact("0 0 UND FUNC GLOBAL DEFAULT fstatat"); + check.checkExact("0 0 UND FUNC GLOBAL DEFAULT fstatat64"); check.checkInSymtab(); - check.checkNotPresent("FUNC LOCAL HIDDEN fstatat"); + check.checkNotPresent("FUNC LOCAL HIDDEN fstatat64"); } // before v2.26 reallocarray is not supported