diff --git a/lib/std/c.zig b/lib/std/c.zig index d2501b735512..ac891d3256e8 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -9167,6 +9167,7 @@ pub extern "c" fn setreuid(ruid: uid_t, euid: uid_t) c_int; pub extern "c" fn setregid(rgid: gid_t, egid: gid_t) c_int; pub extern "c" fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) c_int; pub extern "c" fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) c_int; +pub extern "c" fn setpgid(pid: pid_t, pgid: pid_t) c_int; pub extern "c" fn malloc(usize) ?*anyopaque; pub extern "c" fn realloc(?*anyopaque, usize) ?*anyopaque; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index c6b53d6f0dab..9ceaaaad817d 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1551,6 +1551,10 @@ pub fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) usize { } } +pub fn setpgid(pid: pid_t, pgid: pid_t) usize { + return syscall2(.setpgid, @intCast(pid), @intCast(pgid)); +} + pub fn getgroups(size: usize, list: *gid_t) usize { if (@hasField(SYS, "getgroups32")) { return syscall2(.getgroups32, size, @intFromPtr(list)); diff --git a/lib/std/posix.zig b/lib/std/posix.zig index facb4b8cd664..51ec4628210e 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -3415,6 +3415,24 @@ pub fn setregid(rgid: gid_t, egid: gid_t) SetIdError!void { } } +pub const SetPgidError = error{ + ProcessAlreadyExec, + InvalidProcessGroupId, + PermissionDenied, + ProcessNotFound, +} || UnexpectedError; + +pub fn setpgid(pid: pid_t, pgid: pid_t) SetPgidError!void { + switch (errno(system.setpgid(pid, pgid))) { + .SUCCESS => return, + .ACCES => return error.ProcessAlreadyExec, + .INVAL => return error.InvalidProcessGroupId, + .PERM => return error.PermissionDenied, + .SRCH => return error.ProcessNotFound, + else => |err| return unexpectedErrno(err), + } +} + /// Test whether a file descriptor refers to a terminal. pub fn isatty(handle: fd_t) bool { if (native_os == .windows) { diff --git a/lib/std/process/Child.zig b/lib/std/process/Child.zig index c4a7911e21c9..dfe0c6578eb5 100644 --- a/lib/std/process/Child.zig +++ b/lib/std/process/Child.zig @@ -63,6 +63,9 @@ uid: if (native_os == .windows or native_os == .wasi) void else ?posix.uid_t, /// Set to change the group id when spawning the child process. gid: if (native_os == .windows or native_os == .wasi) void else ?posix.gid_t, +/// Set to change the process group id when spawning the child process. +pgid: if (native_os == .windows or native_os == .wasi) void else ?posix.pid_t, + /// Set to change the current working directory when spawning the child process. cwd: ?[]const u8, /// Set to change the current working directory when spawning the child process. @@ -168,6 +171,7 @@ pub const SpawnError = error{ } || posix.ExecveError || posix.SetIdError || + posix.SetPgidError || posix.ChangeCurDirError || windows.CreateProcessError || windows.GetProcessMemoryInfoError || @@ -213,6 +217,7 @@ pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess { .cwd = null, .uid = if (native_os == .windows or native_os == .wasi) {} else null, .gid = if (native_os == .windows or native_os == .wasi) {} else null, + .pgid = if (native_os == .windows or native_os == .wasi) {} else null, .stdin = null, .stdout = null, .stderr = null, @@ -675,6 +680,10 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void { posix.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err); } + if (self.pgid) |pid| { + posix.setpgid(0, pid) catch |err| forkChildErrReport(err_pipe[1], err); + } + const err = switch (self.expand_arg0) { .expand => posix.execvpeZ_expandArg0(.expand, argv_buf.ptr[0].?, argv_buf.ptr, envp), .no_expand => posix.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),