1433d6423SLionel Sambuc /* This file contains a collection of miscellaneous procedures. Some of them 2433d6423SLionel Sambuc * perform simple system calls. Some others do a little part of system calls 3433d6423SLionel Sambuc * that are mostly performed by the Memory Manager. 4433d6423SLionel Sambuc * 5433d6423SLionel Sambuc * The entry points into this file are 6433d6423SLionel Sambuc * do_fcntl: perform the FCNTL system call 7433d6423SLionel Sambuc * do_sync: perform the SYNC system call 8433d6423SLionel Sambuc * do_fsync: perform the FSYNC system call 9433d6423SLionel Sambuc * pm_setsid: perform VFS's side of setsid system call 10433d6423SLionel Sambuc * pm_reboot: sync disks and prepare for shutdown 11433d6423SLionel Sambuc * pm_fork: adjust the tables after PM has performed a FORK system call 12433d6423SLionel Sambuc * do_exec: handle files with FD_CLOEXEC on after PM has done an EXEC 13433d6423SLionel Sambuc * do_exit: a process has exited; note that in the tables 14433d6423SLionel Sambuc * do_set: set uid or gid for some process 15433d6423SLionel Sambuc * do_revive: revive a process that was waiting for something (e.g. TTY) 16433d6423SLionel Sambuc * do_svrctl: file system control 17433d6423SLionel Sambuc * do_getsysinfo: request copy of FS data structure 18433d6423SLionel Sambuc * pm_dumpcore: create a core dump 19433d6423SLionel Sambuc */ 20433d6423SLionel Sambuc 21433d6423SLionel Sambuc #include "fs.h" 22433d6423SLionel Sambuc #include <fcntl.h> 23433d6423SLionel Sambuc #include <assert.h> 24433d6423SLionel Sambuc #include <unistd.h> 25433d6423SLionel Sambuc #include <string.h> 26433d6423SLionel Sambuc #include <minix/callnr.h> 27433d6423SLionel Sambuc #include <minix/safecopies.h> 28433d6423SLionel Sambuc #include <minix/endpoint.h> 29433d6423SLionel Sambuc #include <minix/com.h> 30433d6423SLionel Sambuc #include <minix/sysinfo.h> 31433d6423SLionel Sambuc #include <minix/u64.h> 32433d6423SLionel Sambuc #include <sys/ptrace.h> 33433d6423SLionel Sambuc #include <sys/svrctl.h> 34433d6423SLionel Sambuc #include <sys/resource.h> 35433d6423SLionel Sambuc #include "file.h" 36433d6423SLionel Sambuc #include <minix/vfsif.h> 37433d6423SLionel Sambuc #include "vnode.h" 38433d6423SLionel Sambuc #include "vmnt.h" 39433d6423SLionel Sambuc 40433d6423SLionel Sambuc #define CORE_NAME "core" 41433d6423SLionel Sambuc #define CORE_MODE 0777 /* mode to use on core image files */ 42433d6423SLionel Sambuc 43433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS 44433d6423SLionel Sambuc unsigned long calls_stats[NR_VFS_CALLS]; 45433d6423SLionel Sambuc #endif 46433d6423SLionel Sambuc 47433d6423SLionel Sambuc static void free_proc(int flags); 48433d6423SLionel Sambuc 49433d6423SLionel Sambuc /*===========================================================================* 50433d6423SLionel Sambuc * do_getsysinfo * 51433d6423SLionel Sambuc *===========================================================================*/ 52433d6423SLionel Sambuc int do_getsysinfo(void) 53433d6423SLionel Sambuc { 546ad322a9SDavid van Moolenbroek struct fproc *rfp; 556ad322a9SDavid van Moolenbroek struct fproc_light *rfpl; 56433d6423SLionel Sambuc vir_bytes src_addr, dst_addr; 57433d6423SLionel Sambuc size_t len, buf_size; 58433d6423SLionel Sambuc int what; 59433d6423SLionel Sambuc 60433d6423SLionel Sambuc what = job_m_in.m_lsys_getsysinfo.what; 61433d6423SLionel Sambuc dst_addr = job_m_in.m_lsys_getsysinfo.where; 62433d6423SLionel Sambuc buf_size = job_m_in.m_lsys_getsysinfo.size; 63433d6423SLionel Sambuc 64433d6423SLionel Sambuc /* Only su may call do_getsysinfo. This call may leak information (and is not 65433d6423SLionel Sambuc * stable enough to be part of the API/ABI). In the future, requests from 66433d6423SLionel Sambuc * non-system processes should be denied. 67433d6423SLionel Sambuc */ 68433d6423SLionel Sambuc 69433d6423SLionel Sambuc if (!super_user) return(EPERM); 70433d6423SLionel Sambuc 71433d6423SLionel Sambuc switch(what) { 72433d6423SLionel Sambuc case SI_PROC_TAB: 73433d6423SLionel Sambuc src_addr = (vir_bytes) fproc; 74433d6423SLionel Sambuc len = sizeof(struct fproc) * NR_PROCS; 75433d6423SLionel Sambuc break; 76433d6423SLionel Sambuc case SI_DMAP_TAB: 77433d6423SLionel Sambuc src_addr = (vir_bytes) dmap; 78433d6423SLionel Sambuc len = sizeof(struct dmap) * NR_DEVICES; 79433d6423SLionel Sambuc break; 806ad322a9SDavid van Moolenbroek case SI_PROCLIGHT_TAB: 816ad322a9SDavid van Moolenbroek /* Fill the light process table for the MIB service upon request. */ 826ad322a9SDavid van Moolenbroek rfpl = &fproc_light[0]; 836ad322a9SDavid van Moolenbroek for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++, rfpl++) { 846ad322a9SDavid van Moolenbroek rfpl->fpl_tty = rfp->fp_tty; 856ad322a9SDavid van Moolenbroek rfpl->fpl_blocked_on = rfp->fp_blocked_on; 866ad322a9SDavid van Moolenbroek rfpl->fpl_task = rfp->fp_task; 876ad322a9SDavid van Moolenbroek } 886ad322a9SDavid van Moolenbroek src_addr = (vir_bytes) fproc_light; 896ad322a9SDavid van Moolenbroek len = sizeof(fproc_light); 906ad322a9SDavid van Moolenbroek break; 91433d6423SLionel Sambuc #if ENABLE_SYSCALL_STATS 92433d6423SLionel Sambuc case SI_CALL_STATS: 93433d6423SLionel Sambuc src_addr = (vir_bytes) calls_stats; 94433d6423SLionel Sambuc len = sizeof(calls_stats); 95433d6423SLionel Sambuc break; 96433d6423SLionel Sambuc #endif 97433d6423SLionel Sambuc default: 98433d6423SLionel Sambuc return(EINVAL); 99433d6423SLionel Sambuc } 100433d6423SLionel Sambuc 101433d6423SLionel Sambuc if (len != buf_size) 102433d6423SLionel Sambuc return(EINVAL); 103433d6423SLionel Sambuc 104433d6423SLionel Sambuc return sys_datacopy_wrapper(SELF, src_addr, who_e, dst_addr, len); 105433d6423SLionel Sambuc } 106433d6423SLionel Sambuc 107433d6423SLionel Sambuc /*===========================================================================* 108433d6423SLionel Sambuc * do_fcntl * 109433d6423SLionel Sambuc *===========================================================================*/ 110433d6423SLionel Sambuc int do_fcntl(void) 111433d6423SLionel Sambuc { 112433d6423SLionel Sambuc /* Perform the fcntl(fd, cmd, ...) system call. */ 113433d6423SLionel Sambuc 114433d6423SLionel Sambuc register struct filp *f; 115433d6423SLionel Sambuc int new_fd, fl, r = OK, fcntl_req, fcntl_argx; 116433d6423SLionel Sambuc tll_access_t locktype; 117433d6423SLionel Sambuc 118bd851af4SDavid van Moolenbroek fp->fp_fd = job_m_in.m_lc_vfs_fcntl.fd; 119bd851af4SDavid van Moolenbroek fp->fp_io_buffer = job_m_in.m_lc_vfs_fcntl.arg_ptr; 120bd851af4SDavid van Moolenbroek fp->fp_io_nbytes = job_m_in.m_lc_vfs_fcntl.cmd; 121433d6423SLionel Sambuc fcntl_req = job_m_in.m_lc_vfs_fcntl.cmd; 122433d6423SLionel Sambuc fcntl_argx = job_m_in.m_lc_vfs_fcntl.arg_int; 123433d6423SLionel Sambuc 124433d6423SLionel Sambuc /* Is the file descriptor valid? */ 125433d6423SLionel Sambuc locktype = (fcntl_req == F_FREESP) ? VNODE_WRITE : VNODE_READ; 126bd851af4SDavid van Moolenbroek if ((f = get_filp(fp->fp_fd, locktype)) == NULL) 127433d6423SLionel Sambuc return(err_code); 128433d6423SLionel Sambuc 129433d6423SLionel Sambuc switch (fcntl_req) { 130433d6423SLionel Sambuc case F_DUPFD: 131424cad2cSDavid van Moolenbroek case F_DUPFD_CLOEXEC: 132433d6423SLionel Sambuc /* This replaces the old dup() system call. */ 133433d6423SLionel Sambuc if (fcntl_argx < 0 || fcntl_argx >= OPEN_MAX) r = EINVAL; 134433d6423SLionel Sambuc else if ((r = get_fd(fp, fcntl_argx, 0, &new_fd, NULL)) == OK) { 135433d6423SLionel Sambuc f->filp_count++; 136433d6423SLionel Sambuc fp->fp_filp[new_fd] = f; 137424cad2cSDavid van Moolenbroek assert(!FD_ISSET(new_fd, &fp->fp_cloexec_set)); 138424cad2cSDavid van Moolenbroek if (fcntl_req == F_DUPFD_CLOEXEC) 139424cad2cSDavid van Moolenbroek FD_SET(new_fd, &fp->fp_cloexec_set); 140433d6423SLionel Sambuc r = new_fd; 141433d6423SLionel Sambuc } 142433d6423SLionel Sambuc break; 143433d6423SLionel Sambuc 144433d6423SLionel Sambuc case F_GETFD: 145433d6423SLionel Sambuc /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ 146433d6423SLionel Sambuc r = 0; 147bd851af4SDavid van Moolenbroek if (FD_ISSET(fp->fp_fd, &fp->fp_cloexec_set)) 148433d6423SLionel Sambuc r = FD_CLOEXEC; 149433d6423SLionel Sambuc break; 150433d6423SLionel Sambuc 151433d6423SLionel Sambuc case F_SETFD: 152433d6423SLionel Sambuc /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ 153433d6423SLionel Sambuc if (fcntl_argx & FD_CLOEXEC) 154bd851af4SDavid van Moolenbroek FD_SET(fp->fp_fd, &fp->fp_cloexec_set); 155433d6423SLionel Sambuc else 156bd851af4SDavid van Moolenbroek FD_CLR(fp->fp_fd, &fp->fp_cloexec_set); 157433d6423SLionel Sambuc break; 158433d6423SLionel Sambuc 159433d6423SLionel Sambuc case F_GETFL: 160433d6423SLionel Sambuc /* Get file status flags (O_NONBLOCK and O_APPEND). */ 161433d6423SLionel Sambuc fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE); 162433d6423SLionel Sambuc r = fl; 163433d6423SLionel Sambuc break; 164433d6423SLionel Sambuc 165433d6423SLionel Sambuc case F_SETFL: 166433d6423SLionel Sambuc /* Set file status flags (O_NONBLOCK and O_APPEND). */ 167433d6423SLionel Sambuc fl = O_NONBLOCK | O_APPEND; 168433d6423SLionel Sambuc f->filp_flags = (f->filp_flags & ~fl) | (fcntl_argx & fl); 169433d6423SLionel Sambuc break; 170433d6423SLionel Sambuc 171433d6423SLionel Sambuc case F_GETLK: 172433d6423SLionel Sambuc case F_SETLK: 173433d6423SLionel Sambuc case F_SETLKW: 174433d6423SLionel Sambuc /* Set or clear a file lock. */ 175433d6423SLionel Sambuc r = lock_op(f, fcntl_req); 176433d6423SLionel Sambuc break; 177433d6423SLionel Sambuc 178433d6423SLionel Sambuc case F_FREESP: 179433d6423SLionel Sambuc { 180433d6423SLionel Sambuc /* Free a section of a file */ 181433d6423SLionel Sambuc off_t start, end, offset; 182433d6423SLionel Sambuc struct flock flock_arg; 183433d6423SLionel Sambuc 184433d6423SLionel Sambuc /* Check if it's a regular file. */ 185433d6423SLionel Sambuc if (!S_ISREG(f->filp_vno->v_mode)) r = EINVAL; 186433d6423SLionel Sambuc else if (!(f->filp_mode & W_BIT)) r = EBADF; 187433d6423SLionel Sambuc else { 188433d6423SLionel Sambuc /* Copy flock data from userspace. */ 189bd851af4SDavid van Moolenbroek r = sys_datacopy_wrapper(who_e, fp->fp_io_buffer, 190433d6423SLionel Sambuc SELF, (vir_bytes) &flock_arg, sizeof(flock_arg)); 191433d6423SLionel Sambuc } 192433d6423SLionel Sambuc 193433d6423SLionel Sambuc if (r != OK) break; 194433d6423SLionel Sambuc 195433d6423SLionel Sambuc /* Convert starting offset to signed. */ 196433d6423SLionel Sambuc offset = (off_t) flock_arg.l_start; 197433d6423SLionel Sambuc 198433d6423SLionel Sambuc /* Figure out starting position base. */ 199433d6423SLionel Sambuc switch(flock_arg.l_whence) { 200433d6423SLionel Sambuc case SEEK_SET: start = 0; break; 201433d6423SLionel Sambuc case SEEK_CUR: start = f->filp_pos; break; 202433d6423SLionel Sambuc case SEEK_END: start = f->filp_vno->v_size; break; 203433d6423SLionel Sambuc default: r = EINVAL; 204433d6423SLionel Sambuc } 205433d6423SLionel Sambuc if (r != OK) break; 206433d6423SLionel Sambuc 207433d6423SLionel Sambuc /* Check for overflow or underflow. */ 208433d6423SLionel Sambuc if (offset > 0 && start + offset < start) r = EINVAL; 209433d6423SLionel Sambuc else if (offset < 0 && start + offset > start) r = EINVAL; 210433d6423SLionel Sambuc else { 211433d6423SLionel Sambuc start += offset; 212433d6423SLionel Sambuc if (start < 0) r = EINVAL; 213433d6423SLionel Sambuc } 214433d6423SLionel Sambuc if (r != OK) break; 215433d6423SLionel Sambuc 216433d6423SLionel Sambuc if (flock_arg.l_len != 0) { 217433d6423SLionel Sambuc if (start >= f->filp_vno->v_size) r = EINVAL; 218433d6423SLionel Sambuc else if ((end = start + flock_arg.l_len) <= start) r = EINVAL; 219433d6423SLionel Sambuc else if (end > f->filp_vno->v_size) end = f->filp_vno->v_size; 220433d6423SLionel Sambuc } else { 221433d6423SLionel Sambuc end = 0; 222433d6423SLionel Sambuc } 223433d6423SLionel Sambuc if (r != OK) break; 224433d6423SLionel Sambuc 225433d6423SLionel Sambuc r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr,start,end); 226433d6423SLionel Sambuc 227433d6423SLionel Sambuc if (r == OK && flock_arg.l_len == 0) 228433d6423SLionel Sambuc f->filp_vno->v_size = start; 229433d6423SLionel Sambuc 230433d6423SLionel Sambuc break; 231433d6423SLionel Sambuc } 232433d6423SLionel Sambuc case F_GETNOSIGPIPE: 2331f945e80SDavid van Moolenbroek r = !!(f->filp_flags & O_NOSIGPIPE); 234433d6423SLionel Sambuc break; 235433d6423SLionel Sambuc case F_SETNOSIGPIPE: 2361f945e80SDavid van Moolenbroek if (fcntl_argx) 2371f945e80SDavid van Moolenbroek f->filp_flags |= O_NOSIGPIPE; 2381f945e80SDavid van Moolenbroek else 2391f945e80SDavid van Moolenbroek f->filp_flags &= ~O_NOSIGPIPE; 240433d6423SLionel Sambuc break; 241433d6423SLionel Sambuc case F_FLUSH_FS_CACHE: 242433d6423SLionel Sambuc { 243433d6423SLionel Sambuc struct vnode *vn = f->filp_vno; 244433d6423SLionel Sambuc mode_t mode = f->filp_vno->v_mode; 245433d6423SLionel Sambuc if (!super_user) { 246433d6423SLionel Sambuc r = EPERM; 247433d6423SLionel Sambuc } else if (S_ISBLK(mode)) { 248433d6423SLionel Sambuc /* Block device; flush corresponding device blocks. */ 249433d6423SLionel Sambuc r = req_flush(vn->v_bfs_e, vn->v_sdev); 250433d6423SLionel Sambuc } else if (S_ISREG(mode) || S_ISDIR(mode)) { 251433d6423SLionel Sambuc /* Directory or regular file; flush hosting FS blocks. */ 252433d6423SLionel Sambuc r = req_flush(vn->v_fs_e, vn->v_dev); 253433d6423SLionel Sambuc } else { 254433d6423SLionel Sambuc /* Remaining cases.. Meaning unclear. */ 255433d6423SLionel Sambuc r = ENODEV; 256433d6423SLionel Sambuc } 257433d6423SLionel Sambuc break; 258433d6423SLionel Sambuc } 259433d6423SLionel Sambuc default: 260433d6423SLionel Sambuc r = EINVAL; 261433d6423SLionel Sambuc } 262433d6423SLionel Sambuc 263433d6423SLionel Sambuc unlock_filp(f); 264433d6423SLionel Sambuc return(r); 265433d6423SLionel Sambuc } 266433d6423SLionel Sambuc 267433d6423SLionel Sambuc /*===========================================================================* 268433d6423SLionel Sambuc * do_sync * 269433d6423SLionel Sambuc *===========================================================================*/ 270433d6423SLionel Sambuc int do_sync(void) 271433d6423SLionel Sambuc { 272433d6423SLionel Sambuc struct vmnt *vmp; 273433d6423SLionel Sambuc int r = OK; 274433d6423SLionel Sambuc 275433d6423SLionel Sambuc for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { 276433d6423SLionel Sambuc if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) 277433d6423SLionel Sambuc break; 278433d6423SLionel Sambuc if (vmp->m_dev != NO_DEV && vmp->m_fs_e != NONE && 279433d6423SLionel Sambuc vmp->m_root_node != NULL) { 280433d6423SLionel Sambuc req_sync(vmp->m_fs_e); 281433d6423SLionel Sambuc } 282433d6423SLionel Sambuc unlock_vmnt(vmp); 283433d6423SLionel Sambuc } 284433d6423SLionel Sambuc 285433d6423SLionel Sambuc return(r); 286433d6423SLionel Sambuc } 287433d6423SLionel Sambuc 288433d6423SLionel Sambuc /*===========================================================================* 289433d6423SLionel Sambuc * do_fsync * 290433d6423SLionel Sambuc *===========================================================================*/ 291433d6423SLionel Sambuc int do_fsync(void) 292433d6423SLionel Sambuc { 293433d6423SLionel Sambuc /* Perform the fsync() system call. */ 294433d6423SLionel Sambuc struct filp *rfilp; 295433d6423SLionel Sambuc struct vmnt *vmp; 296433d6423SLionel Sambuc dev_t dev; 297433d6423SLionel Sambuc int r = OK; 298433d6423SLionel Sambuc 299bd851af4SDavid van Moolenbroek fp->fp_fd = job_m_in.m_lc_vfs_fsync.fd; 300433d6423SLionel Sambuc 301bd851af4SDavid van Moolenbroek if ((rfilp = get_filp(fp->fp_fd, VNODE_READ)) == NULL) 302433d6423SLionel Sambuc return(err_code); 303433d6423SLionel Sambuc 304433d6423SLionel Sambuc dev = rfilp->filp_vno->v_dev; 305433d6423SLionel Sambuc unlock_filp(rfilp); 306433d6423SLionel Sambuc 307433d6423SLionel Sambuc for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { 308433d6423SLionel Sambuc if (vmp->m_dev != dev) continue; 309433d6423SLionel Sambuc if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) 310433d6423SLionel Sambuc break; 311433d6423SLionel Sambuc if (vmp->m_dev != NO_DEV && vmp->m_dev == dev && 312433d6423SLionel Sambuc vmp->m_fs_e != NONE && vmp->m_root_node != NULL) { 313433d6423SLionel Sambuc 314433d6423SLionel Sambuc req_sync(vmp->m_fs_e); 315433d6423SLionel Sambuc } 316433d6423SLionel Sambuc unlock_vmnt(vmp); 317433d6423SLionel Sambuc } 318433d6423SLionel Sambuc 319433d6423SLionel Sambuc return(r); 320433d6423SLionel Sambuc } 321433d6423SLionel Sambuc 322433d6423SLionel Sambuc int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp) 323433d6423SLionel Sambuc { 324433d6423SLionel Sambuc int result, procfd; 325433d6423SLionel Sambuc struct filp *f = NULL; 326433d6423SLionel Sambuc struct fproc *vmf = fproc_addr(VM_PROC_NR); 327433d6423SLionel Sambuc 328433d6423SLionel Sambuc *newfilp = NULL; 329433d6423SLionel Sambuc 330433d6423SLionel Sambuc if ((f = get_filp2(rfp, pfd, VNODE_READ)) == NULL) { 331433d6423SLionel Sambuc printf("VFS dupvm: get_filp2 failed\n"); 332433d6423SLionel Sambuc return EBADF; 333433d6423SLionel Sambuc } 334433d6423SLionel Sambuc 335433d6423SLionel Sambuc if(!(f->filp_vno->v_vmnt->m_fs_flags & RES_HASPEEK)) { 336433d6423SLionel Sambuc unlock_filp(f); 337433d6423SLionel Sambuc #if 0 /* Noisy diagnostic for mmap() by ld.so */ 338433d6423SLionel Sambuc printf("VFS dupvm: no peek available\n"); 339433d6423SLionel Sambuc #endif 340433d6423SLionel Sambuc return EINVAL; 341433d6423SLionel Sambuc } 342433d6423SLionel Sambuc 343433d6423SLionel Sambuc assert(f->filp_vno); 344433d6423SLionel Sambuc assert(f->filp_vno->v_vmnt); 345433d6423SLionel Sambuc 346433d6423SLionel Sambuc if (!S_ISREG(f->filp_vno->v_mode) && !S_ISBLK(f->filp_vno->v_mode)) { 347433d6423SLionel Sambuc printf("VFS: mmap regular/blockdev only; dev 0x%llx ino %llu has mode 0%o\n", 348433d6423SLionel Sambuc f->filp_vno->v_dev, f->filp_vno->v_inode_nr, f->filp_vno->v_mode); 349433d6423SLionel Sambuc unlock_filp(f); 350433d6423SLionel Sambuc return EINVAL; 351433d6423SLionel Sambuc } 352433d6423SLionel Sambuc 353433d6423SLionel Sambuc /* get free FD in VM */ 354433d6423SLionel Sambuc if((result=get_fd(vmf, 0, 0, &procfd, NULL)) != OK) { 355433d6423SLionel Sambuc unlock_filp(f); 356433d6423SLionel Sambuc printf("VFS dupvm: getfd failed\n"); 357433d6423SLionel Sambuc return result; 358433d6423SLionel Sambuc } 359433d6423SLionel Sambuc 360433d6423SLionel Sambuc *vmfd = procfd; 361433d6423SLionel Sambuc 362433d6423SLionel Sambuc f->filp_count++; 363433d6423SLionel Sambuc assert(f->filp_count > 0); 364433d6423SLionel Sambuc vmf->fp_filp[procfd] = f; 365433d6423SLionel Sambuc 366433d6423SLionel Sambuc *newfilp = f; 367433d6423SLionel Sambuc 368433d6423SLionel Sambuc return OK; 369433d6423SLionel Sambuc } 370433d6423SLionel Sambuc 371433d6423SLionel Sambuc /*===========================================================================* 372433d6423SLionel Sambuc * do_vm_call * 373433d6423SLionel Sambuc *===========================================================================*/ 374433d6423SLionel Sambuc int do_vm_call(void) 375433d6423SLionel Sambuc { 376433d6423SLionel Sambuc /* A call that VM does to VFS. 377433d6423SLionel Sambuc * We must reply with the fixed type VM_VFS_REPLY (and put our result info 378433d6423SLionel Sambuc * in the rest of the message) so VM can tell the difference between a 379433d6423SLionel Sambuc * request from VFS and a reply to this call. 380433d6423SLionel Sambuc */ 381433d6423SLionel Sambuc int req = job_m_in.VFS_VMCALL_REQ; 382433d6423SLionel Sambuc int req_fd = job_m_in.VFS_VMCALL_FD; 383433d6423SLionel Sambuc u32_t req_id = job_m_in.VFS_VMCALL_REQID; 384433d6423SLionel Sambuc endpoint_t ep = job_m_in.VFS_VMCALL_ENDPOINT; 385433d6423SLionel Sambuc u64_t offset = job_m_in.VFS_VMCALL_OFFSET; 386433d6423SLionel Sambuc u32_t length = job_m_in.VFS_VMCALL_LENGTH; 387433d6423SLionel Sambuc int result = OK; 388433d6423SLionel Sambuc int slot; 389*e1cdaee1SLionel Sambuc struct fproc *rfp; 390*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) 391*e1cdaee1SLionel Sambuc struct fproc *vmf; 392*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) */ 393433d6423SLionel Sambuc struct filp *f = NULL; 394433d6423SLionel Sambuc int r; 395433d6423SLionel Sambuc 396433d6423SLionel Sambuc if(job_m_in.m_source != VM_PROC_NR) 397433d6423SLionel Sambuc return ENOSYS; 398433d6423SLionel Sambuc 399433d6423SLionel Sambuc if(isokendpt(ep, &slot) != OK) rfp = NULL; 400433d6423SLionel Sambuc else rfp = &fproc[slot]; 401433d6423SLionel Sambuc 402*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) 403433d6423SLionel Sambuc vmf = fproc_addr(VM_PROC_NR); 404*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) */ 405433d6423SLionel Sambuc assert(fp == vmf); 406433d6423SLionel Sambuc assert(rfp != vmf); 407433d6423SLionel Sambuc 408433d6423SLionel Sambuc switch(req) { 409433d6423SLionel Sambuc case VMVFSREQ_FDLOOKUP: 410433d6423SLionel Sambuc { 411433d6423SLionel Sambuc int procfd; 412433d6423SLionel Sambuc 413433d6423SLionel Sambuc /* Lookup fd in referenced process. */ 414433d6423SLionel Sambuc 415433d6423SLionel Sambuc if(!rfp) { 416433d6423SLionel Sambuc printf("VFS: why isn't ep %d here?!\n", ep); 417433d6423SLionel Sambuc result = ESRCH; 418433d6423SLionel Sambuc goto reqdone; 419433d6423SLionel Sambuc } 420433d6423SLionel Sambuc 421433d6423SLionel Sambuc if((result = dupvm(rfp, req_fd, &procfd, &f)) != OK) { 422433d6423SLionel Sambuc #if 0 /* Noisy diagnostic for mmap() by ld.so */ 423433d6423SLionel Sambuc printf("vfs: dupvm failed\n"); 424433d6423SLionel Sambuc #endif 425433d6423SLionel Sambuc goto reqdone; 426433d6423SLionel Sambuc } 427433d6423SLionel Sambuc 428433d6423SLionel Sambuc if(S_ISBLK(f->filp_vno->v_mode)) { 429433d6423SLionel Sambuc assert(f->filp_vno->v_sdev != NO_DEV); 430433d6423SLionel Sambuc job_m_out.VMV_DEV = f->filp_vno->v_sdev; 431433d6423SLionel Sambuc job_m_out.VMV_INO = VMC_NO_INODE; 432433d6423SLionel Sambuc job_m_out.VMV_SIZE_PAGES = LONG_MAX; 433433d6423SLionel Sambuc } else { 434433d6423SLionel Sambuc job_m_out.VMV_DEV = f->filp_vno->v_dev; 435433d6423SLionel Sambuc job_m_out.VMV_INO = f->filp_vno->v_inode_nr; 436433d6423SLionel Sambuc job_m_out.VMV_SIZE_PAGES = 437433d6423SLionel Sambuc roundup(f->filp_vno->v_size, 438433d6423SLionel Sambuc PAGE_SIZE)/PAGE_SIZE; 439433d6423SLionel Sambuc } 440433d6423SLionel Sambuc 441433d6423SLionel Sambuc job_m_out.VMV_FD = procfd; 442433d6423SLionel Sambuc 443433d6423SLionel Sambuc result = OK; 444433d6423SLionel Sambuc 445433d6423SLionel Sambuc break; 446433d6423SLionel Sambuc } 447433d6423SLionel Sambuc case VMVFSREQ_FDCLOSE: 448433d6423SLionel Sambuc { 449433d6423SLionel Sambuc result = close_fd(fp, req_fd); 450433d6423SLionel Sambuc if(result != OK) { 451433d6423SLionel Sambuc printf("VFS: VM fd close for fd %d, %d (%d)\n", 452433d6423SLionel Sambuc req_fd, fp->fp_endpoint, result); 453433d6423SLionel Sambuc } 454433d6423SLionel Sambuc break; 455433d6423SLionel Sambuc } 456433d6423SLionel Sambuc case VMVFSREQ_FDIO: 457433d6423SLionel Sambuc { 458433d6423SLionel Sambuc result = actual_lseek(fp, req_fd, SEEK_SET, offset, 459433d6423SLionel Sambuc NULL); 460433d6423SLionel Sambuc 461433d6423SLionel Sambuc if(result == OK) { 462433d6423SLionel Sambuc result = actual_read_write_peek(fp, PEEKING, 463433d6423SLionel Sambuc req_fd, /* vir_bytes */ 0, length); 464433d6423SLionel Sambuc } 465433d6423SLionel Sambuc 466433d6423SLionel Sambuc break; 467433d6423SLionel Sambuc } 468433d6423SLionel Sambuc default: 469433d6423SLionel Sambuc panic("VFS: bad request code from VM\n"); 470433d6423SLionel Sambuc break; 471433d6423SLionel Sambuc } 472433d6423SLionel Sambuc 473433d6423SLionel Sambuc reqdone: 474433d6423SLionel Sambuc if(f) 475433d6423SLionel Sambuc unlock_filp(f); 476433d6423SLionel Sambuc 477433d6423SLionel Sambuc /* fp is VM still. */ 478433d6423SLionel Sambuc assert(fp == vmf); 479433d6423SLionel Sambuc job_m_out.VMV_ENDPOINT = ep; 480433d6423SLionel Sambuc job_m_out.VMV_RESULT = result; 481433d6423SLionel Sambuc job_m_out.VMV_REQID = req_id; 482433d6423SLionel Sambuc 483433d6423SLionel Sambuc /* Reply asynchronously as VM may not be able to receive 484433d6423SLionel Sambuc * an ipc_sendnb() message. 485433d6423SLionel Sambuc */ 486433d6423SLionel Sambuc job_m_out.m_type = VM_VFS_REPLY; 487433d6423SLionel Sambuc r = asynsend3(VM_PROC_NR, &job_m_out, 0); 488433d6423SLionel Sambuc if(r != OK) printf("VFS: couldn't asynsend3() to VM\n"); 489433d6423SLionel Sambuc 490433d6423SLionel Sambuc /* VFS does not reply any further */ 491433d6423SLionel Sambuc return SUSPEND; 492433d6423SLionel Sambuc } 493433d6423SLionel Sambuc 494433d6423SLionel Sambuc /*===========================================================================* 495433d6423SLionel Sambuc * pm_reboot * 496433d6423SLionel Sambuc *===========================================================================*/ 497433d6423SLionel Sambuc void pm_reboot() 498433d6423SLionel Sambuc { 499433d6423SLionel Sambuc /* Perform the VFS side of the reboot call. This call is performed from the PM 500433d6423SLionel Sambuc * process context. 501433d6423SLionel Sambuc */ 502433d6423SLionel Sambuc message m_out; 503433d6423SLionel Sambuc int i, r; 504433d6423SLionel Sambuc struct fproc *rfp, *pmfp; 505433d6423SLionel Sambuc 506433d6423SLionel Sambuc pmfp = fp; 507433d6423SLionel Sambuc 508433d6423SLionel Sambuc do_sync(); 509433d6423SLionel Sambuc 510433d6423SLionel Sambuc /* Do exit processing for all leftover processes and servers, but don't 511433d6423SLionel Sambuc * actually exit them (if they were really gone, PM will tell us about it). 512433d6423SLionel Sambuc * Skip processes that handle parts of the file system; we first need to give 513433d6423SLionel Sambuc * them the chance to unmount (which should be possible as all normal 514433d6423SLionel Sambuc * processes have no open files anymore). 515433d6423SLionel Sambuc */ 516433d6423SLionel Sambuc /* This is the only place where we allow special modification of "fp". The 517433d6423SLionel Sambuc * reboot procedure should really be implemented as a PM message broadcasted 518433d6423SLionel Sambuc * to all processes, so that each process will be shut down cleanly by a 519433d6423SLionel Sambuc * thread operating on its behalf. Doing everything here is simpler, but it 520433d6423SLionel Sambuc * requires an exception to the strict model of having "fp" be the process 521433d6423SLionel Sambuc * that owns the current worker thread. 522433d6423SLionel Sambuc */ 523433d6423SLionel Sambuc for (i = 0; i < NR_PROCS; i++) { 524433d6423SLionel Sambuc rfp = &fproc[i]; 525433d6423SLionel Sambuc 526433d6423SLionel Sambuc /* Don't just free the proc right away, but let it finish what it was 527433d6423SLionel Sambuc * doing first */ 528433d6423SLionel Sambuc if (rfp != fp) lock_proc(rfp); 529433d6423SLionel Sambuc if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL) { 530433d6423SLionel Sambuc worker_set_proc(rfp); /* temporarily fake process context */ 531433d6423SLionel Sambuc free_proc(0); 532433d6423SLionel Sambuc worker_set_proc(pmfp); /* restore original process context */ 533433d6423SLionel Sambuc } 534433d6423SLionel Sambuc if (rfp != fp) unlock_proc(rfp); 535433d6423SLionel Sambuc } 536433d6423SLionel Sambuc 537433d6423SLionel Sambuc do_sync(); 538433d6423SLionel Sambuc unmount_all(0 /* Don't force */); 539433d6423SLionel Sambuc 540433d6423SLionel Sambuc /* Try to exit all processes again including File Servers */ 541433d6423SLionel Sambuc for (i = 0; i < NR_PROCS; i++) { 542433d6423SLionel Sambuc rfp = &fproc[i]; 543433d6423SLionel Sambuc 544433d6423SLionel Sambuc /* Don't just free the proc right away, but let it finish what it was 545433d6423SLionel Sambuc * doing first */ 546433d6423SLionel Sambuc if (rfp != fp) lock_proc(rfp); 547433d6423SLionel Sambuc if (rfp->fp_endpoint != NONE) { 548433d6423SLionel Sambuc worker_set_proc(rfp); /* temporarily fake process context */ 549433d6423SLionel Sambuc free_proc(0); 550433d6423SLionel Sambuc worker_set_proc(pmfp); /* restore original process context */ 551433d6423SLionel Sambuc } 552433d6423SLionel Sambuc if (rfp != fp) unlock_proc(rfp); 553433d6423SLionel Sambuc } 554433d6423SLionel Sambuc 555433d6423SLionel Sambuc do_sync(); 556433d6423SLionel Sambuc unmount_all(1 /* Force */); 557433d6423SLionel Sambuc 558433d6423SLionel Sambuc /* Reply to PM for synchronization */ 559433d6423SLionel Sambuc memset(&m_out, 0, sizeof(m_out)); 560433d6423SLionel Sambuc 561433d6423SLionel Sambuc m_out.m_type = VFS_PM_REBOOT_REPLY; 562433d6423SLionel Sambuc 563433d6423SLionel Sambuc if ((r = ipc_send(PM_PROC_NR, &m_out)) != OK) 564433d6423SLionel Sambuc panic("pm_reboot: ipc_send failed: %d", r); 565433d6423SLionel Sambuc } 566433d6423SLionel Sambuc 567433d6423SLionel Sambuc /*===========================================================================* 568433d6423SLionel Sambuc * pm_fork * 569433d6423SLionel Sambuc *===========================================================================*/ 570433d6423SLionel Sambuc void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid) 571433d6423SLionel Sambuc { 572433d6423SLionel Sambuc /* Perform those aspects of the fork() system call that relate to files. 573433d6423SLionel Sambuc * In particular, let the child inherit its parent's file descriptors. 574433d6423SLionel Sambuc * The parent and child parameters tell who forked off whom. The file 575433d6423SLionel Sambuc * system uses the same slot numbers as the kernel. Only PM makes this call. 576433d6423SLionel Sambuc */ 577433d6423SLionel Sambuc 578433d6423SLionel Sambuc struct fproc *cp, *pp; 579433d6423SLionel Sambuc int i, parentno, childno; 580433d6423SLionel Sambuc mutex_t c_fp_lock; 581433d6423SLionel Sambuc 582433d6423SLionel Sambuc /* Check up-to-dateness of fproc. */ 583433d6423SLionel Sambuc okendpt(pproc, &parentno); 584433d6423SLionel Sambuc 585433d6423SLionel Sambuc /* PM gives child endpoint, which implies process slot information. 586433d6423SLionel Sambuc * Don't call isokendpt, because that will verify if the endpoint 587433d6423SLionel Sambuc * number is correct in fproc, which it won't be. 588433d6423SLionel Sambuc */ 589433d6423SLionel Sambuc childno = _ENDPOINT_P(cproc); 590433d6423SLionel Sambuc if (childno < 0 || childno >= NR_PROCS) 591433d6423SLionel Sambuc panic("VFS: bogus child for forking: %d", cproc); 592433d6423SLionel Sambuc if (fproc[childno].fp_pid != PID_FREE) 593433d6423SLionel Sambuc panic("VFS: forking on top of in-use child: %d", childno); 594433d6423SLionel Sambuc 595433d6423SLionel Sambuc /* Copy the parent's fproc struct to the child. */ 596433d6423SLionel Sambuc /* However, the mutex variables belong to a slot and must stay the same. */ 597433d6423SLionel Sambuc c_fp_lock = fproc[childno].fp_lock; 598433d6423SLionel Sambuc fproc[childno] = fproc[parentno]; 599433d6423SLionel Sambuc fproc[childno].fp_lock = c_fp_lock; 600433d6423SLionel Sambuc 601433d6423SLionel Sambuc /* Increase the counters in the 'filp' table. */ 602433d6423SLionel Sambuc cp = &fproc[childno]; 603433d6423SLionel Sambuc pp = &fproc[parentno]; 604433d6423SLionel Sambuc 605433d6423SLionel Sambuc for (i = 0; i < OPEN_MAX; i++) 606433d6423SLionel Sambuc if (cp->fp_filp[i] != NULL) cp->fp_filp[i]->filp_count++; 607433d6423SLionel Sambuc 608433d6423SLionel Sambuc /* Fill in new process and endpoint id. */ 609433d6423SLionel Sambuc cp->fp_pid = cpid; 610433d6423SLionel Sambuc cp->fp_endpoint = cproc; 611433d6423SLionel Sambuc 612433d6423SLionel Sambuc /* A forking process never has an outstanding grant, as it isn't blocking on 613433d6423SLionel Sambuc * I/O. */ 614433d6423SLionel Sambuc if (GRANT_VALID(pp->fp_grant)) { 615433d6423SLionel Sambuc panic("VFS: fork: pp (endpoint %d) has grant %d\n", pp->fp_endpoint, 616433d6423SLionel Sambuc pp->fp_grant); 617433d6423SLionel Sambuc } 618433d6423SLionel Sambuc if (GRANT_VALID(cp->fp_grant)) { 619433d6423SLionel Sambuc panic("VFS: fork: cp (endpoint %d) has grant %d\n", cp->fp_endpoint, 620433d6423SLionel Sambuc cp->fp_grant); 621433d6423SLionel Sambuc } 622433d6423SLionel Sambuc 623433d6423SLionel Sambuc /* A child is not a process leader, not being revived, etc. */ 624433d6423SLionel Sambuc cp->fp_flags = FP_NOFLAGS; 625433d6423SLionel Sambuc 626433d6423SLionel Sambuc /* Record the fact that both root and working dir have another user. */ 627433d6423SLionel Sambuc if (cp->fp_rd) dup_vnode(cp->fp_rd); 628433d6423SLionel Sambuc if (cp->fp_wd) dup_vnode(cp->fp_wd); 629433d6423SLionel Sambuc } 630433d6423SLionel Sambuc 631433d6423SLionel Sambuc /*===========================================================================* 632433d6423SLionel Sambuc * free_proc * 633433d6423SLionel Sambuc *===========================================================================*/ 634433d6423SLionel Sambuc static void free_proc(int flags) 635433d6423SLionel Sambuc { 636433d6423SLionel Sambuc int i; 637433d6423SLionel Sambuc register struct fproc *rfp; 638433d6423SLionel Sambuc register struct filp *rfilp; 639433d6423SLionel Sambuc register struct vnode *vp; 640433d6423SLionel Sambuc dev_t dev; 641433d6423SLionel Sambuc 642433d6423SLionel Sambuc if (fp->fp_endpoint == NONE) 643433d6423SLionel Sambuc panic("free_proc: already free"); 644433d6423SLionel Sambuc 645433d6423SLionel Sambuc if (fp_is_blocked(fp)) 646433d6423SLionel Sambuc unpause(); 647433d6423SLionel Sambuc 648433d6423SLionel Sambuc /* Loop on file descriptors, closing any that are open. */ 649433d6423SLionel Sambuc for (i = 0; i < OPEN_MAX; i++) { 650433d6423SLionel Sambuc (void) close_fd(fp, i); 651433d6423SLionel Sambuc } 652433d6423SLionel Sambuc 653433d6423SLionel Sambuc /* Release root and working directories. */ 654433d6423SLionel Sambuc if (fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NULL; } 655433d6423SLionel Sambuc if (fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NULL; } 656433d6423SLionel Sambuc 657433d6423SLionel Sambuc /* The rest of these actions is only done when processes actually exit. */ 658433d6423SLionel Sambuc if (!(flags & FP_EXITING)) return; 659433d6423SLionel Sambuc 660433d6423SLionel Sambuc fp->fp_flags |= FP_EXITING; 661433d6423SLionel Sambuc 662433d6423SLionel Sambuc /* Check if any process is SUSPENDed on this driver. 663433d6423SLionel Sambuc * If a driver exits, unmap its entries in the dmap table. 664433d6423SLionel Sambuc * (unmapping has to be done after the first step, because the 665433d6423SLionel Sambuc * dmap table is used in the first step.) 666433d6423SLionel Sambuc */ 667433d6423SLionel Sambuc unsuspend_by_endpt(fp->fp_endpoint); 668433d6423SLionel Sambuc dmap_unmap_by_endpt(fp->fp_endpoint); 669433d6423SLionel Sambuc 670433d6423SLionel Sambuc worker_stop_by_endpt(fp->fp_endpoint); /* Unblock waiting threads */ 671433d6423SLionel Sambuc vmnt_unmap_by_endpt(fp->fp_endpoint); /* Invalidate open files if this 672433d6423SLionel Sambuc * was an active FS */ 673433d6423SLionel Sambuc 674433d6423SLionel Sambuc /* If a session leader exits and it has a controlling tty, then revoke 675433d6423SLionel Sambuc * access to its controlling tty from all other processes using it. 676433d6423SLionel Sambuc */ 677433d6423SLionel Sambuc if ((fp->fp_flags & FP_SESLDR) && fp->fp_tty != 0) { 678433d6423SLionel Sambuc dev = fp->fp_tty; 679433d6423SLionel Sambuc for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { 680433d6423SLionel Sambuc if(rfp->fp_pid == PID_FREE) continue; 681433d6423SLionel Sambuc if (rfp->fp_tty == dev) rfp->fp_tty = 0; 682433d6423SLionel Sambuc 683433d6423SLionel Sambuc for (i = 0; i < OPEN_MAX; i++) { 684433d6423SLionel Sambuc if ((rfilp = rfp->fp_filp[i]) == NULL) continue; 685433d6423SLionel Sambuc if (rfilp->filp_mode == FILP_CLOSED) continue; 686433d6423SLionel Sambuc vp = rfilp->filp_vno; 687433d6423SLionel Sambuc if (!S_ISCHR(vp->v_mode)) continue; 688433d6423SLionel Sambuc if (vp->v_sdev != dev) continue; 689433d6423SLionel Sambuc lock_filp(rfilp, VNODE_READ); 690433d6423SLionel Sambuc (void) cdev_close(dev); /* Ignore any errors. */ 69127d0ecdbSDavid van Moolenbroek /* FIXME: missing select check */ 692433d6423SLionel Sambuc rfilp->filp_mode = FILP_CLOSED; 693433d6423SLionel Sambuc unlock_filp(rfilp); 694433d6423SLionel Sambuc } 695433d6423SLionel Sambuc } 696433d6423SLionel Sambuc } 697433d6423SLionel Sambuc 698433d6423SLionel Sambuc /* Exit done. Mark slot as free. */ 699433d6423SLionel Sambuc fp->fp_endpoint = NONE; 700433d6423SLionel Sambuc fp->fp_pid = PID_FREE; 701433d6423SLionel Sambuc fp->fp_flags = FP_NOFLAGS; 702433d6423SLionel Sambuc } 703433d6423SLionel Sambuc 704433d6423SLionel Sambuc /*===========================================================================* 705433d6423SLionel Sambuc * pm_exit * 706433d6423SLionel Sambuc *===========================================================================*/ 707433d6423SLionel Sambuc void pm_exit(void) 708433d6423SLionel Sambuc { 709433d6423SLionel Sambuc /* Perform the file system portion of the exit(status) system call. 710433d6423SLionel Sambuc * This function is called from the context of the exiting process. 711433d6423SLionel Sambuc */ 712433d6423SLionel Sambuc 713433d6423SLionel Sambuc free_proc(FP_EXITING); 714433d6423SLionel Sambuc } 715433d6423SLionel Sambuc 716433d6423SLionel Sambuc /*===========================================================================* 717433d6423SLionel Sambuc * pm_setgid * 718433d6423SLionel Sambuc *===========================================================================*/ 719433d6423SLionel Sambuc void pm_setgid(proc_e, egid, rgid) 720433d6423SLionel Sambuc endpoint_t proc_e; 721433d6423SLionel Sambuc int egid; 722433d6423SLionel Sambuc int rgid; 723433d6423SLionel Sambuc { 724433d6423SLionel Sambuc register struct fproc *tfp; 725433d6423SLionel Sambuc int slot; 726433d6423SLionel Sambuc 727433d6423SLionel Sambuc okendpt(proc_e, &slot); 728433d6423SLionel Sambuc tfp = &fproc[slot]; 729433d6423SLionel Sambuc 730433d6423SLionel Sambuc tfp->fp_effgid = egid; 731433d6423SLionel Sambuc tfp->fp_realgid = rgid; 732433d6423SLionel Sambuc } 733433d6423SLionel Sambuc 734433d6423SLionel Sambuc 735433d6423SLionel Sambuc /*===========================================================================* 736433d6423SLionel Sambuc * pm_setgroups * 737433d6423SLionel Sambuc *===========================================================================*/ 738433d6423SLionel Sambuc void pm_setgroups(proc_e, ngroups, groups) 739433d6423SLionel Sambuc endpoint_t proc_e; 740433d6423SLionel Sambuc int ngroups; 741433d6423SLionel Sambuc gid_t *groups; 742433d6423SLionel Sambuc { 743433d6423SLionel Sambuc struct fproc *rfp; 744433d6423SLionel Sambuc int slot; 745433d6423SLionel Sambuc 746433d6423SLionel Sambuc okendpt(proc_e, &slot); 747433d6423SLionel Sambuc rfp = &fproc[slot]; 748433d6423SLionel Sambuc if (ngroups * sizeof(gid_t) > sizeof(rfp->fp_sgroups)) 749433d6423SLionel Sambuc panic("VFS: pm_setgroups: too much data to copy"); 750433d6423SLionel Sambuc if (sys_datacopy_wrapper(who_e, (vir_bytes) groups, SELF, (vir_bytes) rfp->fp_sgroups, 751433d6423SLionel Sambuc ngroups * sizeof(gid_t)) == OK) { 752433d6423SLionel Sambuc rfp->fp_ngroups = ngroups; 753433d6423SLionel Sambuc } else 754433d6423SLionel Sambuc panic("VFS: pm_setgroups: datacopy failed"); 755433d6423SLionel Sambuc } 756433d6423SLionel Sambuc 757433d6423SLionel Sambuc 758433d6423SLionel Sambuc /*===========================================================================* 759433d6423SLionel Sambuc * pm_setuid * 760433d6423SLionel Sambuc *===========================================================================*/ 761433d6423SLionel Sambuc void pm_setuid(proc_e, euid, ruid) 762433d6423SLionel Sambuc endpoint_t proc_e; 763433d6423SLionel Sambuc int euid; 764433d6423SLionel Sambuc int ruid; 765433d6423SLionel Sambuc { 766433d6423SLionel Sambuc struct fproc *tfp; 767433d6423SLionel Sambuc int slot; 768433d6423SLionel Sambuc 769433d6423SLionel Sambuc okendpt(proc_e, &slot); 770433d6423SLionel Sambuc tfp = &fproc[slot]; 771433d6423SLionel Sambuc 772433d6423SLionel Sambuc tfp->fp_effuid = euid; 773433d6423SLionel Sambuc tfp->fp_realuid = ruid; 774433d6423SLionel Sambuc } 775433d6423SLionel Sambuc 776433d6423SLionel Sambuc /*===========================================================================* 777433d6423SLionel Sambuc * pm_setsid * 778433d6423SLionel Sambuc *===========================================================================*/ 779433d6423SLionel Sambuc void pm_setsid(endpoint_t proc_e) 780433d6423SLionel Sambuc { 781433d6423SLionel Sambuc /* Perform the VFS side of the SETSID call, i.e. get rid of the controlling 782433d6423SLionel Sambuc * terminal of a process, and make the process a session leader. 783433d6423SLionel Sambuc */ 784433d6423SLionel Sambuc struct fproc *rfp; 785433d6423SLionel Sambuc int slot; 786433d6423SLionel Sambuc 787433d6423SLionel Sambuc /* Make the process a session leader with no controlling tty. */ 788433d6423SLionel Sambuc okendpt(proc_e, &slot); 789433d6423SLionel Sambuc rfp = &fproc[slot]; 790433d6423SLionel Sambuc rfp->fp_flags |= FP_SESLDR; 791433d6423SLionel Sambuc rfp->fp_tty = 0; 792433d6423SLionel Sambuc } 793433d6423SLionel Sambuc 794433d6423SLionel Sambuc /*===========================================================================* 795433d6423SLionel Sambuc * do_svrctl * 796433d6423SLionel Sambuc *===========================================================================*/ 797433d6423SLionel Sambuc int do_svrctl(void) 798433d6423SLionel Sambuc { 799f737eea6SDavid van Moolenbroek unsigned long svrctl; 800433d6423SLionel Sambuc vir_bytes ptr; 801433d6423SLionel Sambuc 802f737eea6SDavid van Moolenbroek svrctl = job_m_in.m_lc_svrctl.request; 803f737eea6SDavid van Moolenbroek ptr = job_m_in.m_lc_svrctl.arg; 804f737eea6SDavid van Moolenbroek 805f737eea6SDavid van Moolenbroek if (IOCGROUP(svrctl) != 'F') return(EINVAL); 806433d6423SLionel Sambuc 807433d6423SLionel Sambuc switch (svrctl) { 808433d6423SLionel Sambuc case VFSSETPARAM: 809433d6423SLionel Sambuc case VFSGETPARAM: 810433d6423SLionel Sambuc { 811433d6423SLionel Sambuc struct sysgetenv sysgetenv; 812433d6423SLionel Sambuc char search_key[64]; 813433d6423SLionel Sambuc char val[64]; 814433d6423SLionel Sambuc int r, s; 815433d6423SLionel Sambuc 816433d6423SLionel Sambuc /* Copy sysgetenv structure to VFS */ 817433d6423SLionel Sambuc if (sys_datacopy_wrapper(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 818433d6423SLionel Sambuc sizeof(sysgetenv)) != OK) 819433d6423SLionel Sambuc return(EFAULT); 820433d6423SLionel Sambuc 821433d6423SLionel Sambuc /* Basic sanity checking */ 822433d6423SLionel Sambuc if (svrctl == VFSSETPARAM) { 823433d6423SLionel Sambuc if (sysgetenv.keylen <= 0 || 824433d6423SLionel Sambuc sysgetenv.keylen > (sizeof(search_key) - 1) || 825433d6423SLionel Sambuc sysgetenv.vallen <= 0 || 826433d6423SLionel Sambuc sysgetenv.vallen >= sizeof(val)) { 827433d6423SLionel Sambuc return(EINVAL); 828433d6423SLionel Sambuc } 829433d6423SLionel Sambuc } 830433d6423SLionel Sambuc 831433d6423SLionel Sambuc /* Copy parameter "key" */ 832433d6423SLionel Sambuc if ((s = sys_datacopy_wrapper(who_e, (vir_bytes) sysgetenv.key, 833433d6423SLionel Sambuc SELF, (vir_bytes) search_key, 834433d6423SLionel Sambuc sysgetenv.keylen)) != OK) 835433d6423SLionel Sambuc return(s); 836433d6423SLionel Sambuc search_key[sysgetenv.keylen] = '\0'; /* Limit string */ 837433d6423SLionel Sambuc 838433d6423SLionel Sambuc /* Is it a parameter we know? */ 839433d6423SLionel Sambuc if (svrctl == VFSSETPARAM) { 840433d6423SLionel Sambuc if (!strcmp(search_key, "verbose")) { 841433d6423SLionel Sambuc int verbose_val; 842433d6423SLionel Sambuc if ((s = sys_datacopy_wrapper(who_e, 843433d6423SLionel Sambuc (vir_bytes) sysgetenv.val, SELF, 844433d6423SLionel Sambuc (vir_bytes) &val, sysgetenv.vallen)) != OK) 845433d6423SLionel Sambuc return(s); 846433d6423SLionel Sambuc val[sysgetenv.vallen] = '\0'; /* Limit string */ 847433d6423SLionel Sambuc verbose_val = atoi(val); 848433d6423SLionel Sambuc if (verbose_val < 0 || verbose_val > 4) { 849433d6423SLionel Sambuc return(EINVAL); 850433d6423SLionel Sambuc } 851433d6423SLionel Sambuc verbose = verbose_val; 852433d6423SLionel Sambuc r = OK; 853433d6423SLionel Sambuc } else { 854433d6423SLionel Sambuc r = ESRCH; 855433d6423SLionel Sambuc } 856433d6423SLionel Sambuc } else { /* VFSGETPARAM */ 857433d6423SLionel Sambuc char small_buf[60]; 858433d6423SLionel Sambuc 859433d6423SLionel Sambuc r = ESRCH; 860433d6423SLionel Sambuc if (!strcmp(search_key, "print_traces")) { 861433d6423SLionel Sambuc mthread_stacktraces(); 862433d6423SLionel Sambuc sysgetenv.val = 0; 863433d6423SLionel Sambuc sysgetenv.vallen = 0; 864433d6423SLionel Sambuc r = OK; 865433d6423SLionel Sambuc } else if (!strcmp(search_key, "active_threads")) { 866433d6423SLionel Sambuc int active = NR_WTHREADS - worker_available(); 867433d6423SLionel Sambuc snprintf(small_buf, sizeof(small_buf) - 1, 868433d6423SLionel Sambuc "%d", active); 869433d6423SLionel Sambuc sysgetenv.vallen = strlen(small_buf); 870433d6423SLionel Sambuc r = OK; 871433d6423SLionel Sambuc } 872433d6423SLionel Sambuc 873433d6423SLionel Sambuc if (r == OK) { 874433d6423SLionel Sambuc if ((s = sys_datacopy_wrapper(SELF, 875433d6423SLionel Sambuc (vir_bytes) &sysgetenv, who_e, ptr, 876433d6423SLionel Sambuc sizeof(sysgetenv))) != OK) 877433d6423SLionel Sambuc return(s); 878433d6423SLionel Sambuc if (sysgetenv.val != 0) { 879433d6423SLionel Sambuc if ((s = sys_datacopy_wrapper(SELF, 880433d6423SLionel Sambuc (vir_bytes) small_buf, who_e, 881433d6423SLionel Sambuc (vir_bytes) sysgetenv.val, 882433d6423SLionel Sambuc sysgetenv.vallen)) != OK) 883433d6423SLionel Sambuc return(s); 884433d6423SLionel Sambuc } 885433d6423SLionel Sambuc } 886433d6423SLionel Sambuc } 887433d6423SLionel Sambuc 888433d6423SLionel Sambuc return(r); 889433d6423SLionel Sambuc } 890433d6423SLionel Sambuc default: 891433d6423SLionel Sambuc return(EINVAL); 892433d6423SLionel Sambuc } 893433d6423SLionel Sambuc } 894433d6423SLionel Sambuc 895433d6423SLionel Sambuc /*===========================================================================* 896433d6423SLionel Sambuc * pm_dumpcore * 897433d6423SLionel Sambuc *===========================================================================*/ 898433d6423SLionel Sambuc int pm_dumpcore(int csig, vir_bytes exe_name) 899433d6423SLionel Sambuc { 9009f15e7b3SDavid van Moolenbroek int r, core_fd; 901433d6423SLionel Sambuc struct filp *f; 902433d6423SLionel Sambuc char core_path[PATH_MAX]; 903433d6423SLionel Sambuc char proc_name[PROC_NAME_LEN]; 904433d6423SLionel Sambuc 9059f15e7b3SDavid van Moolenbroek /* If a process is blocked, fp->fp_fd holds the fd it's blocked on. Free it 9069f15e7b3SDavid van Moolenbroek * up for use by common_open(). This step is the reason we cannot use this 9079f15e7b3SDavid van Moolenbroek * function to generate a core dump of a process while it is still running 9089f15e7b3SDavid van Moolenbroek * (i.e., without terminating it), as it changes the state of the process. 909433d6423SLionel Sambuc */ 910433d6423SLionel Sambuc if (fp_is_blocked(fp)) 911433d6423SLionel Sambuc unpause(); 912433d6423SLionel Sambuc 913433d6423SLionel Sambuc /* open core file */ 914433d6423SLionel Sambuc snprintf(core_path, PATH_MAX, "%s.%d", CORE_NAME, fp->fp_pid); 9159f15e7b3SDavid van Moolenbroek r = core_fd = common_open(core_path, O_WRONLY | O_CREAT | O_TRUNC, 91656ac45c1SDavid van Moolenbroek CORE_MODE, FALSE /*for_exec*/); 9179f15e7b3SDavid van Moolenbroek if (r < 0) goto core_exit; 918433d6423SLionel Sambuc 9199f15e7b3SDavid van Moolenbroek /* get process name */ 9209f15e7b3SDavid van Moolenbroek r = sys_datacopy_wrapper(PM_PROC_NR, exe_name, VFS_PROC_NR, 9219f15e7b3SDavid van Moolenbroek (vir_bytes) proc_name, PROC_NAME_LEN); 922433d6423SLionel Sambuc if (r != OK) goto core_exit; 923433d6423SLionel Sambuc proc_name[PROC_NAME_LEN - 1] = '\0'; 924433d6423SLionel Sambuc 9259f15e7b3SDavid van Moolenbroek /* write the core dump */ 9269f15e7b3SDavid van Moolenbroek f = get_filp(core_fd, VNODE_WRITE); 9279f15e7b3SDavid van Moolenbroek assert(f != NULL); 928433d6423SLionel Sambuc write_elf_core_file(f, csig, proc_name); 929433d6423SLionel Sambuc unlock_filp(f); 930433d6423SLionel Sambuc 931433d6423SLionel Sambuc core_exit: 9329f15e7b3SDavid van Moolenbroek /* The core file descriptor will be closed as part of the process exit. */ 933433d6423SLionel Sambuc free_proc(FP_EXITING); 9349f15e7b3SDavid van Moolenbroek 935433d6423SLionel Sambuc return(r); 936433d6423SLionel Sambuc } 937433d6423SLionel Sambuc 938433d6423SLionel Sambuc /*===========================================================================* 939433d6423SLionel Sambuc * ds_event * 940433d6423SLionel Sambuc *===========================================================================*/ 941433d6423SLionel Sambuc void 942433d6423SLionel Sambuc ds_event(void) 943433d6423SLionel Sambuc { 944433d6423SLionel Sambuc char key[DS_MAX_KEYLEN]; 945433d6423SLionel Sambuc char *blkdrv_prefix = "drv.blk."; 946433d6423SLionel Sambuc char *chrdrv_prefix = "drv.chr."; 947433d6423SLionel Sambuc u32_t value; 948433d6423SLionel Sambuc int type, r, is_blk; 949433d6423SLionel Sambuc endpoint_t owner_endpoint; 950433d6423SLionel Sambuc 951433d6423SLionel Sambuc /* Get the event and the owner from DS. */ 952433d6423SLionel Sambuc while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { 953433d6423SLionel Sambuc /* Only check for block and character driver up events. */ 954433d6423SLionel Sambuc if (!strncmp(key, blkdrv_prefix, strlen(blkdrv_prefix))) { 955433d6423SLionel Sambuc is_blk = TRUE; 956433d6423SLionel Sambuc } else if (!strncmp(key, chrdrv_prefix, strlen(chrdrv_prefix))) { 957433d6423SLionel Sambuc is_blk = FALSE; 958433d6423SLionel Sambuc } else { 959433d6423SLionel Sambuc continue; 960433d6423SLionel Sambuc } 961433d6423SLionel Sambuc 962433d6423SLionel Sambuc if ((r = ds_retrieve_u32(key, &value)) != OK) { 963433d6423SLionel Sambuc printf("VFS: ds_event: ds_retrieve_u32 failed\n"); 964433d6423SLionel Sambuc break; 965433d6423SLionel Sambuc } 966433d6423SLionel Sambuc if (value != DS_DRIVER_UP) continue; 967433d6423SLionel Sambuc 968433d6423SLionel Sambuc /* Perform up. */ 969433d6423SLionel Sambuc dmap_endpt_up(owner_endpoint, is_blk); 970433d6423SLionel Sambuc } 971433d6423SLionel Sambuc 972433d6423SLionel Sambuc if (r != ENOENT) printf("VFS: ds_event: ds_check failed: %d\n", r); 973433d6423SLionel Sambuc } 974433d6423SLionel Sambuc 975433d6423SLionel Sambuc /* A function to be called on panic(). */ 976433d6423SLionel Sambuc void panic_hook(void) 977433d6423SLionel Sambuc { 978433d6423SLionel Sambuc printf("VFS mthread stacktraces:\n"); 979433d6423SLionel Sambuc mthread_stacktraces(); 980433d6423SLionel Sambuc } 981433d6423SLionel Sambuc 982433d6423SLionel Sambuc /*===========================================================================* 983433d6423SLionel Sambuc * do_getrusage * 984433d6423SLionel Sambuc *===========================================================================*/ 985433d6423SLionel Sambuc int do_getrusage(void) 986433d6423SLionel Sambuc { 987bc2d75faSDavid van Moolenbroek /* Obsolete vfs_getrusage(2) call from userland. The getrusage call is 988bc2d75faSDavid van Moolenbroek * now fully handled by PM, and for any future fields that should be 989bc2d75faSDavid van Moolenbroek * supplied by VFS, VFS should be queried by PM rather than by the user 990bc2d75faSDavid van Moolenbroek * program directly. TODO: remove this call after the next release. 991bc2d75faSDavid van Moolenbroek */ 992bc2d75faSDavid van Moolenbroek return OK; 993433d6423SLionel Sambuc } 994