Preparatory refactor, almost no functional change, splitting the
per-process configuration operations that pdsetpgid(2), pdchdir(2)
and pdchroot(2) will need to perform on an *embryonic* process --- one
named by a process descriptor rather than being curproc --- out of the
syscall paths that today perform them only on the running process.
- do_setpgid() (kern_prot.c): the core of setpgid(2) --- the session and group-leader checks and the enter/create-group logic --- lifted out of sys_setpgid(), taking the target proc explicitly.
As a side effect, this reorders two independent error cases in setpgid(2): a target that is both a session member of a different session *and* already exec'd now reports EACCES (the P_EXEC check, still done in sys_setpgid()) before EPERM (the session check, now in do_setpgid()), where before the EPERM came first. Both are permission failures for the same call and either is permitted by POSIX.
This is the only behavioral change. - pwd_chroot(), pwd_chdir() and pwd_ensure_dirs() (kern_descrip.c) now take a struct proc * instead of a struct thread * (or, for pwd_ensure_dirs(), instead of no argument); their callers pass td->td_proc or curproc.
- chdir_getvp(), chroot_getvp() and kern_chroot_validate() (vfs_syscalls.c): directory-descriptor-to-vnode resolution and (for root) validation, split out of sys_fchdir() / sys_fchroot() / sys_chroot(). These resolve a real descriptor; the magic AT_FDCWD / AT_FDROOT "the caller's own cwd / root" handling that an unprivileged caller uses to propagate its own directories to an embryo comes with the process-descriptor syscalls that need it.
do_setpgid(), chdir_getvp() and chroot_getvp() are static here:
only their own translation unit uses them so far. The process-descriptor
syscalls that will be introduced later will export (or not) them as needed.
Assisted-by: Claude Code (Claude Opus 5)