authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-08 23:35:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-12 00:14:07-07:00
log6c64090e7af56ccbf374e1a927fe232b340ed681
tree46a825bfc9f0c2aee9d57e1b89dcff4a30ac2418
parent26d506c0f8b5249fe29186506b82e5f515fcc56f

std.os.linux: fanotify_init, fanotify_mark, name_to_handle_at

* Delete existing `FAN` struct in favor of a `fanotify` struct which has type-safe bindings (breaking). * Add name_to_handle_at syscall wrapper. * Add file_handle * Add kernel_fsid_t * Add fsid_t * Add and update std.posix wrappers.

2 files changed, 235 insertions(+), 57 deletions(-)

lib/std/os/linux.zig+180-52
...@@ -698,12 +698,42 @@ pub fn inotify_rm_watch(fd: i32, wd: i32) usize {...@@ -698,12 +698,42 @@ pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
698 return syscall2(.inotify_rm_watch, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, wd))));698 return syscall2(.inotify_rm_watch, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, wd))));
699}699}
700700
701pub fn fanotify_init(flags: u32, event_f_flags: u32) usize {701pub fn fanotify_init(flags: fanotify.InitFlags, event_f_flags: u32) usize {
702 return syscall2(.fanotify_init, flags, event_f_flags);702 return syscall2(.fanotify_init, @as(u32, @bitCast(flags)), event_f_flags);
703}703}
704704
705pub fn fanotify_mark(fd: i32, flags: u32, mask: u64, dirfd: i32, pathname: ?[*:0]const u8) usize {705pub fn fanotify_mark(
706 return syscall5(.fanotify_mark, @as(usize, @bitCast(@as(isize, fd))), flags, mask, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(pathname));706 fd: fd_t,
707 flags: fanotify.MarkFlags,
708 mask: fanotify.MarkMask,
709 dirfd: fd_t,
710 pathname: ?[*:0]const u8,
711) usize {
712 return syscall5(
713 .fanotify_mark,
714 @bitCast(@as(isize, fd)),
715 @as(u32, @bitCast(flags)),
716 @bitCast(mask),
717 @bitCast(@as(isize, dirfd)),
718 @intFromPtr(pathname),
719 );
720}
721
722pub fn name_to_handle_at(
723 dirfd: fd_t,
724 pathname: [*:0]const u8,
725 handle: *std.os.linux.file_handle,
726 mount_id: *i32,
727 flags: u32,
728) usize {
729 return syscall5(
730 .name_to_handle_at,
731 @as(u32, @bitCast(dirfd)),
732 @intFromPtr(pathname),
733 @intFromPtr(handle),
734 @intFromPtr(mount_id),
735 flags,
736 );
707}737}
708738
709pub fn readlink(noalias path: [*:0]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {739pub fn readlink(noalias path: [*:0]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
...@@ -4135,58 +4165,156 @@ pub const IN = struct {...@@ -4135,58 +4165,156 @@ pub const IN = struct {
4135 pub const ONESHOT = 0x80000000;4165 pub const ONESHOT = 0x80000000;
4136};4166};
41374167
4138pub const FAN = struct {4168pub const fanotify = struct {
4139 pub const ACCESS = 0x00000001;4169 pub const InitFlags = packed struct(u32) {
4140 pub const MODIFY = 0x00000002;4170 CLOEXEC: bool = false,
4141 pub const CLOSE_WRITE = 0x00000008;4171 NONBLOCK: bool = false,
4142 pub const CLOSE_NOWRITE = 0x00000010;4172 CLASS: enum(u2) {
4143 pub const OPEN = 0x00000020;4173 NOTIF = 0,
4144 pub const Q_OVERFLOW = 0x00004000;4174 CONTENT = 1,
4145 pub const OPEN_PERM = 0x00010000;4175 PRE_CONTENT = 2,
4146 pub const ACCESS_PERM = 0x00020000;4176 } = .NOTIF,
4147 pub const ONDIR = 0x40000000;4177 UNLIMITED_QUEUE: bool = false,
4148 pub const EVENT_ON_CHILD = 0x08000000;4178 UNLIMITED_MARKS: bool = false,
4149 pub const CLOSE = CLOSE_WRITE | CLOSE_NOWRITE;4179 ENABLE_AUDIT: bool = false,
4150 pub const CLOEXEC = 0x00000001;4180 REPORT_PIDFD: bool = false,
4151 pub const NONBLOCK = 0x00000002;4181 REPORT_TID: bool = false,
4152 pub const CLASS_NOTIF = 0x00000000;4182 REPORT_FID: bool = false,
4153 pub const CLASS_CONTENT = 0x00000004;4183 REPORT_DIR_FID: bool = false,
4154 pub const CLASS_PRE_CONTENT = 0x00000008;4184 REPORT_NAME: bool = false,
4155 pub const ALL_CLASS_BITS = CLASS_NOTIF | CLASS_CONTENT | CLASS_PRE_CONTENT;4185 REPORT_TARGET_FID: bool = false,
4156 pub const UNLIMITED_QUEUE = 0x00000010;4186 _: u19 = 0,
4157 pub const UNLIMITED_MARKS = 0x00000020;4187 };
4158 pub const ALL_INIT_FLAGS = CLOEXEC | NONBLOCK | ALL_CLASS_BITS | UNLIMITED_QUEUE | UNLIMITED_MARKS;4188
4159 pub const MARK_ADD = 0x00000001;4189 pub const MarkFlags = packed struct(u32) {
4160 pub const MARK_REMOVE = 0x00000002;4190 ADD: bool = false,
4161 pub const MARK_DONT_FOLLOW = 0x00000004;4191 REMOVE: bool = false,
4162 pub const MARK_ONLYDIR = 0x00000008;4192 DONT_FOLLOW: bool = false,
4163 pub const MARK_MOUNT = 0x00000010;4193 ONLYDIR: bool = false,
4164 pub const MARK_IGNORED_MASK = 0x00000020;4194 MOUNT: bool = false,
4165 pub const MARK_IGNORED_SURV_MODIFY = 0x00000040;4195 /// Mutually exclusive with `IGNORE`
4166 pub const MARK_FLUSH = 0x00000080;4196 IGNORED_MASK: bool = false,
4167 pub const ALL_MARK_FLAGS = MARK_ADD | MARK_REMOVE | MARK_DONT_FOLLOW | MARK_ONLYDIR | MARK_MOUNT | MARK_IGNORED_MASK | MARK_IGNORED_SURV_MODIFY | MARK_FLUSH;4197 IGNORED_SURV_MODIFY: bool = false,
4168 pub const ALL_EVENTS = ACCESS | MODIFY | CLOSE | OPEN;4198 FLUSH: bool = false,
4169 pub const ALL_PERM_EVENTS = OPEN_PERM | ACCESS_PERM;4199 FILESYSTEM: bool = false,
4170 pub const ALL_OUTGOING_EVENTS = ALL_EVENTS | ALL_PERM_EVENTS | Q_OVERFLOW;4200 EVICTABLE: bool = false,
4171 pub const ALLOW = 0x01;4201 /// Mutually exclusive with `IGNORED_MASK`
4172 pub const DENY = 0x02;4202 IGNORE: bool = false,
4173};4203 _: u21 = 0,
41744204 };
4175pub const fanotify_event_metadata = extern struct {4205
4176 event_len: u32,4206 pub const MarkMask = packed struct(u64) {
4177 vers: u8,4207 /// File was accessed
4178 reserved: u8,4208 ACCESS: bool = false,
4179 metadata_len: u16,4209 /// File was modified
4180 mask: u64 align(8),4210 MODIFY: bool = false,
4181 fd: i32,4211 /// Metadata changed
4182 pid: i32,4212 ATTRIB: bool = false,
4213 /// Writtable file closed
4214 CLOSE_WRITE: bool = false,
4215 /// Unwrittable file closed
4216 CLOSE_NOWRITE: bool = false,
4217 /// File was opened
4218 OPEN: bool = false,
4219 /// File was moved from X
4220 MOVED_FROM: bool = false,
4221 /// File was moved to Y
4222 MOVED_TO: bool = false,
4223
4224 /// Subfile was created
4225 CREATE: bool = false,
4226 /// Subfile was deleted
4227 DELETE: bool = false,
4228 /// Self was deleted
4229 DELETE_SELF: bool = false,
4230 /// Self was moved
4231 MOVE_SELF: bool = false,
4232 /// File was opened for exec
4233 OPEN_EXEC: bool = false,
4234 reserved13: u1 = 0,
4235 /// Event queued overflowed
4236 Q_OVERFLOW: bool = false,
4237 /// Filesystem error
4238 FS_ERROR: bool = false,
4239
4240 /// File open in perm check
4241 OPEN_PERM: bool = false,
4242 /// File accessed in perm check
4243 ACCESS_PERM: bool = false,
4244 /// File open/exec in perm check
4245 OPEN_EXEC_PERM: bool = false,
4246 reserved19: u8 = 0,
4247 /// Interested in child events
4248 EVENT_ON_CHILD: bool = false,
4249 /// File was renamed
4250 RENAME: bool = false,
4251 reserved30: u1 = 0,
4252 /// Event occurred against dir
4253 ONDIR: bool = false,
4254 reserved31: u33 = 0,
4255 };
4256
4257 pub const event_metadata = extern struct {
4258 event_len: u32,
4259 vers: u8,
4260 reserved: u8,
4261 metadata_len: u16,
4262 mask: u64 align(8),
4263 fd: i32,
4264 pid: i32,
4265
4266 pub const VERSION = 3;
4267 };
4268
4269 pub const response = extern struct {
4270 fd: i32,
4271 response: u32,
4272 };
4273
4274 /// Unique file identifier info record.
4275 ///
4276 /// This structure is used for records of types `EVENT_INFO_TYPE.FID`.
4277 /// `EVENT_INFO_TYPE.DFID` and `EVENT_INFO_TYPE.DFID_NAME`.
4278 ///
4279 /// For `EVENT_INFO_TYPE.DFID_NAME` there is additionally a null terminated
4280 /// name immediately after the file handle.
4281 pub const event_info_fid = extern struct {
4282 hdr: event_info_header,
4283 fsid: kernel_fsid_t,
4284 /// Following is an opaque struct file_handle that can be passed as
4285 /// an argument to open_by_handle_at(2).
4286 handle: [0]u8,
4287 };
4288
4289 /// Variable length info record following event metadata.
4290 pub const event_info_header = extern struct {
4291 info_type: EVENT_INFO_TYPE,
4292 pad: u8,
4293 len: u16,
4294 };
4295
4296 pub const EVENT_INFO_TYPE = enum(u8) {
4297 FID = 1,
4298 DFID_NAME = 2,
4299 DFID = 3,
4300 PIDFD = 4,
4301 ERROR = 5,
4302 OLD_DFID_NAME = 10,
4303 OLD_DFID = 11,
4304 NEW_DFID_NAME = 12,
4305 NEW_DFID = 13,
4306 };
4183};4307};
41844308
4185pub const fanotify_response = extern struct {4309pub const file_handle = extern struct {
4186 fd: i32,4310 handle_bytes: u32,
4187 response: u32,4311 handle_type: i32,
4312 f_handle: [0]u8,
4188};4313};
41894314
4315pub const kernel_fsid_t = fsid_t;
4316pub const fsid_t = [2]i32;
4317
4190pub const S = struct {4318pub const S = struct {
4191 pub const IFMT = 0o170000;4319 pub const IFMT = 0o170000;
41924320
lib/std/posix.zig+55-5
...@@ -4501,7 +4501,7 @@ pub const FanotifyInitError = error{...@@ -4501,7 +4501,7 @@ pub const FanotifyInitError = error{
4501 PermissionDenied,4501 PermissionDenied,
4502} || UnexpectedError;4502} || UnexpectedError;
45034503
4504pub fn fanotify_init(flags: u32, event_f_flags: u32) FanotifyInitError!i32 {4504pub fn fanotify_init(flags: std.os.linux.fanotify.InitFlags, event_f_flags: u32) FanotifyInitError!i32 {
4505 const rc = system.fanotify_init(flags, event_f_flags);4505 const rc = system.fanotify_init(flags, event_f_flags);
4506 switch (errno(rc)) {4506 switch (errno(rc)) {
4507 .SUCCESS => return @intCast(rc),4507 .SUCCESS => return @intCast(rc),
...@@ -4530,16 +4530,28 @@ pub const FanotifyMarkError = error{...@@ -4530,16 +4530,28 @@ pub const FanotifyMarkError = error{
4530 NameTooLong,4530 NameTooLong,
4531} || UnexpectedError;4531} || UnexpectedError;
45324532
4533pub fn fanotify_mark(fanotify_fd: i32, flags: u32, mask: u64, dirfd: i32, pathname: ?[]const u8) FanotifyMarkError!void {4533pub fn fanotify_mark(
4534 fanotify_fd: fd_t,
4535 flags: std.os.linux.fanotify.MarkFlags,
4536 mask: std.os.linux.fanotify.MarkMask,
4537 dirfd: fd_t,
4538 pathname: ?[]const u8,
4539) FanotifyMarkError!void {
4534 if (pathname) |path| {4540 if (pathname) |path| {
4535 const path_c = try toPosixPath(path);4541 const path_c = try toPosixPath(path);
4536 return fanotify_markZ(fanotify_fd, flags, mask, dirfd, &path_c);4542 return fanotify_markZ(fanotify_fd, flags, mask, dirfd, &path_c);
4543 } else {
4544 return fanotify_markZ(fanotify_fd, flags, mask, dirfd, null);
4537 }4545 }
4538
4539 return fanotify_markZ(fanotify_fd, flags, mask, dirfd, null);
4540}4546}
45414547
4542pub fn fanotify_markZ(fanotify_fd: i32, flags: u32, mask: u64, dirfd: i32, pathname: ?[*:0]const u8) FanotifyMarkError!void {4548pub fn fanotify_markZ(
4549 fanotify_fd: fd_t,
4550 flags: std.os.linux.fanotify.MarkFlags,
4551 mask: std.os.linux.fanotify.MarkMask,
4552 dirfd: fd_t,
4553 pathname: ?[*:0]const u8,
4554) FanotifyMarkError!void {
4543 const rc = system.fanotify_mark(fanotify_fd, flags, mask, dirfd, pathname);4555 const rc = system.fanotify_mark(fanotify_fd, flags, mask, dirfd, pathname);
4544 switch (errno(rc)) {4556 switch (errno(rc)) {
4545 .SUCCESS => return,4557 .SUCCESS => return,
...@@ -7274,6 +7286,44 @@ pub fn ptrace(request: u32, pid: pid_t, addr: usize, signal: usize) PtraceError!...@@ -7274,6 +7286,44 @@ pub fn ptrace(request: u32, pid: pid_t, addr: usize, signal: usize) PtraceError!
7274 };7286 };
7275}7287}
72767288
7289pub const NameToFileHandleAtError = error{
7290 FileNotFound,
7291 NotDir,
7292 OperationNotSupported,
7293 NameTooLong,
7294 Unexpected,
7295};
7296
7297pub fn name_to_handle_at(
7298 dirfd: fd_t,
7299 pathname: []const u8,
7300 handle: *std.os.linux.file_handle,
7301 mount_id: *i32,
7302 flags: u32,
7303) NameToFileHandleAtError!void {
7304 const pathname_c = try toPosixPath(pathname);
7305 return name_to_handle_atZ(dirfd, &pathname_c, handle, mount_id, flags);
7306}
7307
7308pub fn name_to_handle_atZ(
7309 dirfd: fd_t,
7310 pathname_z: [*:0]const u8,
7311 handle: *std.os.linux.file_handle,
7312 mount_id: *i32,
7313 flags: u32,
7314) NameToFileHandleAtError!void {
7315 switch (errno(system.name_to_handle_at(dirfd, pathname_z, handle, mount_id, flags))) {
7316 .SUCCESS => {},
7317 .FAULT => unreachable, // pathname, mount_id, or handle outside accessible address space
7318 .INVAL => unreachable, // bad flags, or handle_bytes too big
7319 .NOENT => return error.FileNotFound,
7320 .NOTDIR => return error.NotDir,
7321 .OPNOTSUPP => return error.OperationNotSupported,
7322 .OVERFLOW => return error.NameTooLong,
7323 else => |err| return unexpectedErrno(err),
7324 }
7325}
7326
7277pub const IoCtl_SIOCGIFINDEX_Error = error{7327pub const IoCtl_SIOCGIFINDEX_Error = error{
7278 FileSystem,7328 FileSystem,
7279 InterfaceNotFound,7329 InterfaceNotFound,