1 /* This file contains a collection of miscellaneous procedures. Some of them 2 * perform simple system calls. Some others do a little part of system calls 3 * that are mostly performed by the Memory Manager. 4 * 5 * The entry points into this file are 6 * do_fcntl: perform the FCNTL system call 7 * do_sync: perform the SYNC system call 8 * do_fsync: perform the FSYNC system call 9 * pm_setsid: perform VFS's side of setsid system call 10 * pm_reboot: sync disks and prepare for shutdown 11 * pm_fork: adjust the tables after PM has performed a FORK system call 12 * do_exec: handle files with FD_CLOEXEC on after PM has done an EXEC 13 * do_exit: a process has exited; note that in the tables 14 * do_set: set uid or gid for some process 15 * do_revive: revive a process that was waiting for something (e.g. TTY) 16 * do_svrctl: file system control 17 * do_getsysinfo: request copy of FS data structure 18 * pm_dumpcore: create a core dump 19 */ 20 21 #include "fs.h" 22 #include <fcntl.h> 23 #include <assert.h> 24 #include <unistd.h> 25 #include <string.h> 26 #include <minix/callnr.h> 27 #include <minix/safecopies.h> 28 #include <minix/endpoint.h> 29 #include <minix/com.h> 30 #include <minix/sysinfo.h> 31 #include <minix/u64.h> 32 #include <sys/ptrace.h> 33 #include <sys/svrctl.h> 34 #include <sys/resource.h> 35 #include "file.h" 36 #include <minix/vfsif.h> 37 #include "vnode.h" 38 #include "vmnt.h" 39 40 #define CORE_NAME "core" 41 #define CORE_MODE 0777 /* mode to use on core image files */ 42 43 #if ENABLE_SYSCALL_STATS 44 unsigned long calls_stats[NR_VFS_CALLS]; 45 #endif 46 47 static void free_proc(int flags); 48 49 /*===========================================================================* 50 * do_getsysinfo * 51 *===========================================================================*/ 52 int do_getsysinfo(void) 53 { 54 struct fproc *rfp; 55 struct fproc_light *rfpl; 56 struct smap *sp; 57 vir_bytes src_addr, dst_addr; 58 size_t len, buf_size; 59 int what; 60 61 what = job_m_in.m_lsys_getsysinfo.what; 62 dst_addr = job_m_in.m_lsys_getsysinfo.where; 63 buf_size = job_m_in.m_lsys_getsysinfo.size; 64 65 /* Only su may call do_getsysinfo. This call may leak information (and is not 66 * stable enough to be part of the API/ABI). In the future, requests from 67 * non-system processes should be denied. 68 */ 69 70 if (!super_user) return(EPERM); 71 72 switch(what) { 73 case SI_PROC_TAB: 74 src_addr = (vir_bytes) fproc; 75 len = sizeof(struct fproc) * NR_PROCS; 76 break; 77 case SI_DMAP_TAB: 78 src_addr = (vir_bytes) dmap; 79 len = sizeof(struct dmap) * NR_DEVICES; 80 break; 81 case SI_PROCLIGHT_TAB: 82 /* Fill the light process table for the MIB service upon request. */ 83 rfpl = &fproc_light[0]; 84 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++, rfpl++) { 85 rfpl->fpl_tty = rfp->fp_tty; 86 rfpl->fpl_blocked_on = rfp->fp_blocked_on; 87 if (rfp->fp_blocked_on == FP_BLOCKED_ON_CDEV) 88 rfpl->fpl_task = rfp->fp_cdev.endpt; 89 else if (rfp->fp_blocked_on == FP_BLOCKED_ON_SDEV && 90 (sp = get_smap_by_dev(rfp->fp_sdev.dev, NULL)) != NULL) 91 rfpl->fpl_task = sp->smap_endpt; 92 else 93 rfpl->fpl_task = NONE; 94 } 95 src_addr = (vir_bytes) fproc_light; 96 len = sizeof(fproc_light); 97 break; 98 #if ENABLE_SYSCALL_STATS 99 case SI_CALL_STATS: 100 src_addr = (vir_bytes) calls_stats; 101 len = sizeof(calls_stats); 102 break; 103 #endif 104 default: 105 return(EINVAL); 106 } 107 108 if (len != buf_size) 109 return(EINVAL); 110 111 return sys_datacopy_wrapper(SELF, src_addr, who_e, dst_addr, len); 112 } 113 114 /*===========================================================================* 115 * do_fcntl * 116 *===========================================================================*/ 117 int do_fcntl(void) 118 { 119 /* Perform the fcntl(fd, cmd, ...) system call. */ 120 struct filp *f; 121 int fd, new_fd, fl, r = OK, fcntl_req, fcntl_argx; 122 vir_bytes addr; 123 tll_access_t locktype; 124 125 fd = job_m_in.m_lc_vfs_fcntl.fd; 126 fcntl_req = job_m_in.m_lc_vfs_fcntl.cmd; 127 fcntl_argx = job_m_in.m_lc_vfs_fcntl.arg_int; 128 addr = job_m_in.m_lc_vfs_fcntl.arg_ptr; 129 130 /* Is the file descriptor valid? */ 131 locktype = (fcntl_req == F_FREESP) ? VNODE_WRITE : VNODE_READ; 132 if ((f = get_filp(fd, locktype)) == NULL) 133 return(err_code); 134 135 switch (fcntl_req) { 136 case F_DUPFD: 137 case F_DUPFD_CLOEXEC: 138 /* This replaces the old dup() system call. */ 139 if (fcntl_argx < 0 || fcntl_argx >= OPEN_MAX) r = EINVAL; 140 else if ((r = get_fd(fp, fcntl_argx, 0, &new_fd, NULL)) == OK) { 141 f->filp_count++; 142 fp->fp_filp[new_fd] = f; 143 assert(!FD_ISSET(new_fd, &fp->fp_cloexec_set)); 144 if (fcntl_req == F_DUPFD_CLOEXEC) 145 FD_SET(new_fd, &fp->fp_cloexec_set); 146 r = new_fd; 147 } 148 break; 149 150 case F_GETFD: 151 /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ 152 r = 0; 153 if (FD_ISSET(fd, &fp->fp_cloexec_set)) 154 r = FD_CLOEXEC; 155 break; 156 157 case F_SETFD: 158 /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */ 159 if (fcntl_argx & FD_CLOEXEC) 160 FD_SET(fd, &fp->fp_cloexec_set); 161 else 162 FD_CLR(fd, &fp->fp_cloexec_set); 163 break; 164 165 case F_GETFL: 166 /* Get file status flags (O_NONBLOCK and O_APPEND). */ 167 fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE); 168 r = fl; 169 break; 170 171 case F_SETFL: 172 /* Set file status flags (O_NONBLOCK and O_APPEND). */ 173 fl = O_NONBLOCK | O_APPEND; 174 f->filp_flags = (f->filp_flags & ~fl) | (fcntl_argx & fl); 175 break; 176 177 case F_GETLK: 178 case F_SETLK: 179 case F_SETLKW: 180 /* Set or clear a file lock. */ 181 r = lock_op(fd, fcntl_req, addr); 182 break; 183 184 case F_FREESP: 185 { 186 /* Free a section of a file */ 187 off_t start, end, offset; 188 struct flock flock_arg; 189 190 /* Check if it's a regular file. */ 191 if (!S_ISREG(f->filp_vno->v_mode)) r = EINVAL; 192 else if (!(f->filp_mode & W_BIT)) r = EBADF; 193 else { 194 /* Copy flock data from userspace. */ 195 r = sys_datacopy_wrapper(who_e, addr, SELF, 196 (vir_bytes)&flock_arg, sizeof(flock_arg)); 197 } 198 199 if (r != OK) break; 200 201 /* Convert starting offset to signed. */ 202 offset = (off_t) flock_arg.l_start; 203 204 /* Figure out starting position base. */ 205 switch(flock_arg.l_whence) { 206 case SEEK_SET: start = 0; break; 207 case SEEK_CUR: start = f->filp_pos; break; 208 case SEEK_END: start = f->filp_vno->v_size; break; 209 default: r = EINVAL; 210 } 211 if (r != OK) break; 212 213 /* Check for overflow or underflow. */ 214 if (offset > 0 && start + offset < start) r = EINVAL; 215 else if (offset < 0 && start + offset > start) r = EINVAL; 216 else { 217 start += offset; 218 if (start < 0) r = EINVAL; 219 } 220 if (r != OK) break; 221 222 if (flock_arg.l_len != 0) { 223 if (start >= f->filp_vno->v_size) r = EINVAL; 224 else if ((end = start + flock_arg.l_len) <= start) r = EINVAL; 225 else if (end > f->filp_vno->v_size) end = f->filp_vno->v_size; 226 } else { 227 end = 0; 228 } 229 if (r != OK) break; 230 231 r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr,start,end); 232 233 if (r == OK && flock_arg.l_len == 0) 234 f->filp_vno->v_size = start; 235 236 break; 237 } 238 case F_GETNOSIGPIPE: 239 r = !!(f->filp_flags & O_NOSIGPIPE); 240 break; 241 case F_SETNOSIGPIPE: 242 if (fcntl_argx) 243 f->filp_flags |= O_NOSIGPIPE; 244 else 245 f->filp_flags &= ~O_NOSIGPIPE; 246 break; 247 case F_FLUSH_FS_CACHE: 248 { 249 struct vnode *vn = f->filp_vno; 250 mode_t mode = f->filp_vno->v_mode; 251 if (!super_user) { 252 r = EPERM; 253 } else if (S_ISBLK(mode)) { 254 /* Block device; flush corresponding device blocks. */ 255 r = req_flush(vn->v_bfs_e, vn->v_sdev); 256 } else if (S_ISREG(mode) || S_ISDIR(mode)) { 257 /* Directory or regular file; flush hosting FS blocks. */ 258 r = req_flush(vn->v_fs_e, vn->v_dev); 259 } else { 260 /* Remaining cases.. Meaning unclear. */ 261 r = ENODEV; 262 } 263 break; 264 } 265 default: 266 r = EINVAL; 267 } 268 269 unlock_filp(f); 270 return(r); 271 } 272 273 /*===========================================================================* 274 * do_sync * 275 *===========================================================================*/ 276 int do_sync(void) 277 { 278 struct vmnt *vmp; 279 int r = OK; 280 281 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { 282 if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) 283 break; 284 if (vmp->m_dev != NO_DEV && vmp->m_fs_e != NONE && 285 vmp->m_root_node != NULL) { 286 req_sync(vmp->m_fs_e); 287 } 288 unlock_vmnt(vmp); 289 } 290 291 return(r); 292 } 293 294 /*===========================================================================* 295 * do_fsync * 296 *===========================================================================*/ 297 int do_fsync(void) 298 { 299 /* Perform the fsync() system call. */ 300 struct filp *rfilp; 301 struct vmnt *vmp; 302 dev_t dev; 303 int fd, r = OK; 304 305 fd = job_m_in.m_lc_vfs_fsync.fd; 306 307 if ((rfilp = get_filp(fd, VNODE_READ)) == NULL) 308 return(err_code); 309 310 dev = rfilp->filp_vno->v_dev; 311 unlock_filp(rfilp); 312 313 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) { 314 if (vmp->m_dev != dev) continue; 315 if ((r = lock_vmnt(vmp, VMNT_READ)) != OK) 316 break; 317 if (vmp->m_dev != NO_DEV && vmp->m_dev == dev && 318 vmp->m_fs_e != NONE && vmp->m_root_node != NULL) { 319 320 req_sync(vmp->m_fs_e); 321 } 322 unlock_vmnt(vmp); 323 } 324 325 return(r); 326 } 327 328 int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp) 329 { 330 int result, procfd; 331 struct filp *f = NULL; 332 struct fproc *vmf = fproc_addr(VM_PROC_NR); 333 334 *newfilp = NULL; 335 336 if ((f = get_filp2(rfp, pfd, VNODE_READ)) == NULL) { 337 printf("VFS dupvm: get_filp2 failed\n"); 338 return EBADF; 339 } 340 341 if(!(f->filp_vno->v_vmnt->m_fs_flags & RES_HASPEEK)) { 342 unlock_filp(f); 343 #if 0 /* Noisy diagnostic for mmap() by ld.so */ 344 printf("VFS dupvm: no peek available\n"); 345 #endif 346 return EINVAL; 347 } 348 349 assert(f->filp_vno); 350 assert(f->filp_vno->v_vmnt); 351 352 if (!S_ISREG(f->filp_vno->v_mode) && !S_ISBLK(f->filp_vno->v_mode)) { 353 printf("VFS: mmap regular/blockdev only; dev 0x%llx ino %llu has mode 0%o\n", 354 f->filp_vno->v_dev, f->filp_vno->v_inode_nr, f->filp_vno->v_mode); 355 unlock_filp(f); 356 return EINVAL; 357 } 358 359 /* get free FD in VM */ 360 if((result=get_fd(vmf, 0, 0, &procfd, NULL)) != OK) { 361 unlock_filp(f); 362 printf("VFS dupvm: getfd failed\n"); 363 return result; 364 } 365 366 *vmfd = procfd; 367 368 f->filp_count++; 369 assert(f->filp_count > 0); 370 vmf->fp_filp[procfd] = f; 371 372 *newfilp = f; 373 374 return OK; 375 } 376 377 /*===========================================================================* 378 * do_vm_call * 379 *===========================================================================*/ 380 int do_vm_call(void) 381 { 382 /* A call that VM does to VFS. 383 * We must reply with the fixed type VM_VFS_REPLY (and put our result info 384 * in the rest of the message) so VM can tell the difference between a 385 * request from VFS and a reply to this call. 386 */ 387 int req = job_m_in.VFS_VMCALL_REQ; 388 int req_fd = job_m_in.VFS_VMCALL_FD; 389 u32_t req_id = job_m_in.VFS_VMCALL_REQID; 390 endpoint_t ep = job_m_in.VFS_VMCALL_ENDPOINT; 391 u64_t offset = job_m_in.VFS_VMCALL_OFFSET; 392 u32_t length = job_m_in.VFS_VMCALL_LENGTH; 393 int result = OK; 394 int slot; 395 struct fproc *rfp; 396 #if !defined(NDEBUG) 397 struct fproc *vmf; 398 #endif /* !defined(NDEBUG) */ 399 struct filp *f = NULL; 400 int r; 401 402 if(job_m_in.m_source != VM_PROC_NR) 403 return ENOSYS; 404 405 if(isokendpt(ep, &slot) != OK) rfp = NULL; 406 else rfp = &fproc[slot]; 407 408 #if !defined(NDEBUG) 409 vmf = fproc_addr(VM_PROC_NR); 410 #endif /* !defined(NDEBUG) */ 411 assert(fp == vmf); 412 assert(rfp != vmf); 413 414 switch(req) { 415 case VMVFSREQ_FDLOOKUP: 416 { 417 int procfd; 418 419 /* Lookup fd in referenced process. */ 420 421 if(!rfp) { 422 printf("VFS: why isn't ep %d here?!\n", ep); 423 result = ESRCH; 424 goto reqdone; 425 } 426 427 if((result = dupvm(rfp, req_fd, &procfd, &f)) != OK) { 428 #if 0 /* Noisy diagnostic for mmap() by ld.so */ 429 printf("vfs: dupvm failed\n"); 430 #endif 431 goto reqdone; 432 } 433 434 if(S_ISBLK(f->filp_vno->v_mode)) { 435 assert(f->filp_vno->v_sdev != NO_DEV); 436 job_m_out.VMV_DEV = f->filp_vno->v_sdev; 437 job_m_out.VMV_INO = VMC_NO_INODE; 438 job_m_out.VMV_SIZE_PAGES = LONG_MAX; 439 } else { 440 job_m_out.VMV_DEV = f->filp_vno->v_dev; 441 job_m_out.VMV_INO = f->filp_vno->v_inode_nr; 442 job_m_out.VMV_SIZE_PAGES = 443 roundup(f->filp_vno->v_size, 444 PAGE_SIZE)/PAGE_SIZE; 445 } 446 447 job_m_out.VMV_FD = procfd; 448 449 result = OK; 450 451 break; 452 } 453 case VMVFSREQ_FDCLOSE: 454 { 455 result = close_fd(fp, req_fd, FALSE /*may_suspend*/); 456 if(result != OK) { 457 printf("VFS: VM fd close for fd %d, %d (%d)\n", 458 req_fd, fp->fp_endpoint, result); 459 } 460 break; 461 } 462 case VMVFSREQ_FDIO: 463 { 464 result = actual_lseek(fp, req_fd, SEEK_SET, offset, 465 NULL); 466 467 if(result == OK) { 468 result = actual_read_write_peek(fp, PEEKING, 469 req_fd, /* vir_bytes */ 0, length); 470 } 471 472 break; 473 } 474 default: 475 panic("VFS: bad request code from VM\n"); 476 break; 477 } 478 479 reqdone: 480 if(f) 481 unlock_filp(f); 482 483 /* fp is VM still. */ 484 assert(fp == vmf); 485 job_m_out.VMV_ENDPOINT = ep; 486 job_m_out.VMV_RESULT = result; 487 job_m_out.VMV_REQID = req_id; 488 489 /* Reply asynchronously as VM may not be able to receive 490 * an ipc_sendnb() message. 491 */ 492 job_m_out.m_type = VM_VFS_REPLY; 493 r = asynsend3(VM_PROC_NR, &job_m_out, 0); 494 if(r != OK) printf("VFS: couldn't asynsend3() to VM\n"); 495 496 /* VFS does not reply any further */ 497 return SUSPEND; 498 } 499 500 /*===========================================================================* 501 * pm_reboot * 502 *===========================================================================*/ 503 void 504 pm_reboot(void) 505 { 506 /* Perform the VFS side of the reboot call. This call is performed from the PM 507 * process context. 508 */ 509 message m_out; 510 int i, r; 511 struct fproc *rfp, *pmfp; 512 513 pmfp = fp; 514 515 do_sync(); 516 517 /* Do exit processing for all leftover processes and servers, but don't 518 * actually exit them (if they were really gone, PM will tell us about it). 519 * Skip processes that handle parts of the file system; we first need to give 520 * them the chance to unmount (which should be possible as all normal 521 * processes have no open files anymore). 522 */ 523 /* This is the only place where we allow special modification of "fp". The 524 * reboot procedure should really be implemented as a PM message broadcasted 525 * to all processes, so that each process will be shut down cleanly by a 526 * thread operating on its behalf. Doing everything here is simpler, but it 527 * requires an exception to the strict model of having "fp" be the process 528 * that owns the current worker thread. 529 */ 530 for (i = 0; i < NR_PROCS; i++) { 531 rfp = &fproc[i]; 532 533 /* Don't just free the proc right away, but let it finish what it was 534 * doing first */ 535 if (rfp != fp) lock_proc(rfp); 536 if (rfp->fp_endpoint != NONE && find_vmnt(rfp->fp_endpoint) == NULL) { 537 worker_set_proc(rfp); /* temporarily fake process context */ 538 free_proc(0); 539 worker_set_proc(pmfp); /* restore original process context */ 540 } 541 if (rfp != fp) unlock_proc(rfp); 542 } 543 544 do_sync(); 545 unmount_all(0 /* Don't force */); 546 547 /* Try to exit all processes again including File Servers */ 548 for (i = 0; i < NR_PROCS; i++) { 549 rfp = &fproc[i]; 550 551 /* Don't just free the proc right away, but let it finish what it was 552 * doing first */ 553 if (rfp != fp) lock_proc(rfp); 554 if (rfp->fp_endpoint != NONE) { 555 worker_set_proc(rfp); /* temporarily fake process context */ 556 free_proc(0); 557 worker_set_proc(pmfp); /* restore original process context */ 558 } 559 if (rfp != fp) unlock_proc(rfp); 560 } 561 562 do_sync(); 563 unmount_all(1 /* Force */); 564 565 /* Reply to PM for synchronization */ 566 memset(&m_out, 0, sizeof(m_out)); 567 568 m_out.m_type = VFS_PM_REBOOT_REPLY; 569 570 if ((r = ipc_send(PM_PROC_NR, &m_out)) != OK) 571 panic("pm_reboot: ipc_send failed: %d", r); 572 } 573 574 /*===========================================================================* 575 * pm_fork * 576 *===========================================================================*/ 577 void pm_fork(endpoint_t pproc, endpoint_t cproc, pid_t cpid) 578 { 579 /* Perform those aspects of the fork() system call that relate to files. 580 * In particular, let the child inherit its parent's file descriptors. 581 * The parent and child parameters tell who forked off whom. The file 582 * system uses the same slot numbers as the kernel. Only PM makes this call. 583 */ 584 struct fproc *cp; 585 #if !defined(NDEBUG) 586 struct fproc *pp; 587 #endif /* !defined(NDEBUG) */ 588 int i, parentno, childno; 589 mutex_t c_fp_lock; 590 591 /* Check up-to-dateness of fproc. */ 592 okendpt(pproc, &parentno); 593 594 /* PM gives child endpoint, which implies process slot information. 595 * Don't call isokendpt, because that will verify if the endpoint 596 * number is correct in fproc, which it won't be. 597 */ 598 childno = _ENDPOINT_P(cproc); 599 if (childno < 0 || childno >= NR_PROCS) 600 panic("VFS: bogus child for forking: %d", cproc); 601 if (fproc[childno].fp_pid != PID_FREE) 602 panic("VFS: forking on top of in-use child: %d", childno); 603 604 /* Copy the parent's fproc struct to the child. */ 605 /* However, the mutex variables belong to a slot and must stay the same. */ 606 c_fp_lock = fproc[childno].fp_lock; 607 fproc[childno] = fproc[parentno]; 608 fproc[childno].fp_lock = c_fp_lock; 609 610 /* Increase the counters in the 'filp' table. */ 611 cp = &fproc[childno]; 612 #if !defined(NDEBUG) 613 pp = &fproc[parentno]; 614 #endif /* !defined(NDEBUG) */ 615 616 for (i = 0; i < OPEN_MAX; i++) 617 if (cp->fp_filp[i] != NULL) cp->fp_filp[i]->filp_count++; 618 619 /* Fill in new process and endpoint id. */ 620 cp->fp_pid = cpid; 621 cp->fp_endpoint = cproc; 622 623 #if !defined(NDEBUG) 624 /* A forking process cannot possibly be suspended on anything. */ 625 assert(pp->fp_blocked_on == FP_BLOCKED_ON_NONE); 626 #endif /* !defined(NDEBUG) */ 627 628 /* A child is not a process leader, not being revived, etc. */ 629 cp->fp_flags = FP_NOFLAGS; 630 631 /* Record the fact that both root and working dir have another user. */ 632 if (cp->fp_rd) dup_vnode(cp->fp_rd); 633 if (cp->fp_wd) dup_vnode(cp->fp_wd); 634 } 635 636 /*===========================================================================* 637 * free_proc * 638 *===========================================================================*/ 639 static void free_proc(int flags) 640 { 641 int i; 642 register struct fproc *rfp; 643 register struct filp *rfilp; 644 register struct vnode *vp; 645 dev_t dev; 646 647 if (fp->fp_endpoint == NONE) 648 panic("free_proc: already free"); 649 650 if (fp_is_blocked(fp)) 651 unpause(); 652 653 /* Loop on file descriptors, closing any that are open. */ 654 for (i = 0; i < OPEN_MAX; i++) { 655 (void) close_fd(fp, i, FALSE /*may_suspend*/); 656 } 657 658 /* Release root and working directories. */ 659 if (fp->fp_rd) { put_vnode(fp->fp_rd); fp->fp_rd = NULL; } 660 if (fp->fp_wd) { put_vnode(fp->fp_wd); fp->fp_wd = NULL; } 661 662 /* The rest of these actions is only done when processes actually exit. */ 663 if (!(flags & FP_EXITING)) return; 664 665 fp->fp_flags |= FP_EXITING; 666 667 /* Check if any process is SUSPENDed on this driver. 668 * If a driver exits, unmap its entries in the dmap table. 669 * (unmapping has to be done after the first step, because the 670 * dmap/smap tables are used in the first step.) 671 */ 672 unsuspend_by_endpt(fp->fp_endpoint); 673 dmap_unmap_by_endpt(fp->fp_endpoint); 674 smap_unmap_by_endpt(fp->fp_endpoint); 675 676 worker_stop_by_endpt(fp->fp_endpoint); /* Unblock waiting threads */ 677 vmnt_unmap_by_endpt(fp->fp_endpoint); /* Invalidate open files if this 678 * was an active FS */ 679 680 /* If a session leader exits and it has a controlling tty, then revoke 681 * access to its controlling tty from all other processes using it. 682 */ 683 if ((fp->fp_flags & FP_SESLDR) && fp->fp_tty != 0) { 684 dev = fp->fp_tty; 685 for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { 686 if(rfp->fp_pid == PID_FREE) continue; 687 if (rfp->fp_tty == dev) rfp->fp_tty = 0; 688 689 for (i = 0; i < OPEN_MAX; i++) { 690 if ((rfilp = rfp->fp_filp[i]) == NULL) continue; 691 if (rfilp->filp_mode == FILP_CLOSED) continue; 692 vp = rfilp->filp_vno; 693 if (!S_ISCHR(vp->v_mode)) continue; 694 if (vp->v_sdev != dev) continue; 695 lock_filp(rfilp, VNODE_READ); 696 (void) cdev_close(dev); /* Ignore any errors. */ 697 /* FIXME: missing select check */ 698 rfilp->filp_mode = FILP_CLOSED; 699 unlock_filp(rfilp); 700 } 701 } 702 } 703 704 /* Exit done. Mark slot as free. */ 705 fp->fp_endpoint = NONE; 706 fp->fp_pid = PID_FREE; 707 fp->fp_flags = FP_NOFLAGS; 708 } 709 710 /*===========================================================================* 711 * pm_exit * 712 *===========================================================================*/ 713 void pm_exit(void) 714 { 715 /* Perform the file system portion of the exit(status) system call. 716 * This function is called from the context of the exiting process. 717 */ 718 719 free_proc(FP_EXITING); 720 } 721 722 /*===========================================================================* 723 * pm_setgid * 724 *===========================================================================*/ 725 void 726 pm_setgid(endpoint_t proc_e, int egid, int rgid) 727 { 728 register struct fproc *tfp; 729 int slot; 730 731 okendpt(proc_e, &slot); 732 tfp = &fproc[slot]; 733 734 tfp->fp_effgid = egid; 735 tfp->fp_realgid = rgid; 736 } 737 738 739 /*===========================================================================* 740 * pm_setgroups * 741 *===========================================================================*/ 742 void 743 pm_setgroups(endpoint_t proc_e, int ngroups, gid_t *groups) 744 { 745 struct fproc *rfp; 746 int slot; 747 748 okendpt(proc_e, &slot); 749 rfp = &fproc[slot]; 750 if (ngroups * sizeof(gid_t) > sizeof(rfp->fp_sgroups)) 751 panic("VFS: pm_setgroups: too much data to copy"); 752 if (sys_datacopy_wrapper(who_e, (vir_bytes) groups, SELF, (vir_bytes) rfp->fp_sgroups, 753 ngroups * sizeof(gid_t)) == OK) { 754 rfp->fp_ngroups = ngroups; 755 } else 756 panic("VFS: pm_setgroups: datacopy failed"); 757 } 758 759 760 /*===========================================================================* 761 * pm_setuid * 762 *===========================================================================*/ 763 void 764 pm_setuid(endpoint_t proc_e, int euid, int ruid) 765 { 766 struct fproc *tfp; 767 int slot; 768 769 okendpt(proc_e, &slot); 770 tfp = &fproc[slot]; 771 772 tfp->fp_effuid = euid; 773 tfp->fp_realuid = ruid; 774 } 775 776 /*===========================================================================* 777 * pm_setsid * 778 *===========================================================================*/ 779 void pm_setsid(endpoint_t proc_e) 780 { 781 /* Perform the VFS side of the SETSID call, i.e. get rid of the controlling 782 * terminal of a process, and make the process a session leader. 783 */ 784 struct fproc *rfp; 785 int slot; 786 787 /* Make the process a session leader with no controlling tty. */ 788 okendpt(proc_e, &slot); 789 rfp = &fproc[slot]; 790 rfp->fp_flags |= FP_SESLDR; 791 rfp->fp_tty = 0; 792 } 793 794 /*===========================================================================* 795 * do_svrctl * 796 *===========================================================================*/ 797 int do_svrctl(void) 798 { 799 unsigned long svrctl; 800 vir_bytes ptr; 801 802 svrctl = job_m_in.m_lc_svrctl.request; 803 ptr = job_m_in.m_lc_svrctl.arg; 804 805 if (IOCGROUP(svrctl) != 'F') return(EINVAL); 806 807 switch (svrctl) { 808 case VFSSETPARAM: 809 case VFSGETPARAM: 810 { 811 struct sysgetenv sysgetenv; 812 char search_key[64]; 813 char val[64]; 814 int r, s; 815 816 /* Copy sysgetenv structure to VFS */ 817 if (sys_datacopy_wrapper(who_e, ptr, SELF, (vir_bytes) &sysgetenv, 818 sizeof(sysgetenv)) != OK) 819 return(EFAULT); 820 821 /* Basic sanity checking */ 822 if (svrctl == VFSSETPARAM) { 823 if (sysgetenv.keylen <= 0 || 824 sysgetenv.keylen > (sizeof(search_key) - 1) || 825 sysgetenv.vallen <= 0 || 826 sysgetenv.vallen >= sizeof(val)) { 827 return(EINVAL); 828 } 829 } 830 831 /* Copy parameter "key" */ 832 if ((s = sys_datacopy_wrapper(who_e, (vir_bytes) sysgetenv.key, 833 SELF, (vir_bytes) search_key, 834 sysgetenv.keylen)) != OK) 835 return(s); 836 search_key[sysgetenv.keylen] = '\0'; /* Limit string */ 837 838 /* Is it a parameter we know? */ 839 if (svrctl == VFSSETPARAM) { 840 if (!strcmp(search_key, "verbose")) { 841 int verbose_val; 842 if ((s = sys_datacopy_wrapper(who_e, 843 (vir_bytes) sysgetenv.val, SELF, 844 (vir_bytes) &val, sysgetenv.vallen)) != OK) 845 return(s); 846 val[sysgetenv.vallen] = '\0'; /* Limit string */ 847 verbose_val = atoi(val); 848 if (verbose_val < 0 || verbose_val > 4) { 849 return(EINVAL); 850 } 851 verbose = verbose_val; 852 r = OK; 853 } else { 854 r = ESRCH; 855 } 856 } else { /* VFSGETPARAM */ 857 char small_buf[60]; 858 859 r = ESRCH; 860 if (!strcmp(search_key, "print_traces")) { 861 mthread_stacktraces(); 862 sysgetenv.val = 0; 863 sysgetenv.vallen = 0; 864 r = OK; 865 } else if (!strcmp(search_key, "print_select")) { 866 select_dump(); 867 sysgetenv.val = 0; 868 sysgetenv.vallen = 0; 869 r = OK; 870 } else if (!strcmp(search_key, "active_threads")) { 871 int active = NR_WTHREADS - worker_available(); 872 snprintf(small_buf, sizeof(small_buf) - 1, 873 "%d", active); 874 sysgetenv.vallen = strlen(small_buf); 875 r = OK; 876 } 877 878 if (r == OK) { 879 if ((s = sys_datacopy_wrapper(SELF, 880 (vir_bytes) &sysgetenv, who_e, ptr, 881 sizeof(sysgetenv))) != OK) 882 return(s); 883 if (sysgetenv.val != 0) { 884 if ((s = sys_datacopy_wrapper(SELF, 885 (vir_bytes) small_buf, who_e, 886 (vir_bytes) sysgetenv.val, 887 sysgetenv.vallen)) != OK) 888 return(s); 889 } 890 } 891 } 892 893 return(r); 894 } 895 default: 896 return(EINVAL); 897 } 898 } 899 900 /*===========================================================================* 901 * pm_dumpcore * 902 *===========================================================================*/ 903 int pm_dumpcore(int csig, vir_bytes exe_name) 904 { 905 int r, core_fd; 906 struct filp *f; 907 char core_path[PATH_MAX]; 908 char proc_name[PROC_NAME_LEN]; 909 910 /* In effect, the coredump is generated through the use of calls as if made 911 * by the process itself. As such, the process must not be doing anything 912 * else. Therefore, if the process was blocked on anything, unblock it 913 * first. This step is the reason we cannot use this function to generate a 914 * core dump of a process while it is still running (i.e., without 915 * terminating it), as it changes the state of the process. 916 */ 917 if (fp_is_blocked(fp)) 918 unpause(); 919 920 /* open core file */ 921 snprintf(core_path, PATH_MAX, "%s.%d", CORE_NAME, fp->fp_pid); 922 r = core_fd = common_open(core_path, O_WRONLY | O_CREAT | O_TRUNC, 923 CORE_MODE, FALSE /*for_exec*/); 924 if (r < 0) goto core_exit; 925 926 /* get process name */ 927 r = sys_datacopy_wrapper(PM_PROC_NR, exe_name, VFS_PROC_NR, 928 (vir_bytes) proc_name, PROC_NAME_LEN); 929 if (r != OK) goto core_exit; 930 proc_name[PROC_NAME_LEN - 1] = '\0'; 931 932 /* write the core dump */ 933 f = get_filp(core_fd, VNODE_WRITE); 934 assert(f != NULL); 935 write_elf_core_file(f, csig, proc_name); 936 unlock_filp(f); 937 938 core_exit: 939 /* The core file descriptor will be closed as part of the process exit. */ 940 free_proc(FP_EXITING); 941 942 return(r); 943 } 944 945 /*===========================================================================* 946 * ds_event * 947 *===========================================================================*/ 948 void 949 ds_event(void) 950 { 951 char key[DS_MAX_KEYLEN]; 952 char *blkdrv_prefix = "drv.blk."; 953 char *chrdrv_prefix = "drv.chr."; 954 char *sckdrv_prefix = "drv.sck."; 955 u32_t value; 956 int type, ftype, r; 957 endpoint_t owner_endpoint; 958 959 /* Get the event and the owner from DS. */ 960 while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { 961 /* Only check for block, character, socket driver up events. */ 962 if (!strncmp(key, blkdrv_prefix, strlen(blkdrv_prefix))) { 963 ftype = S_IFBLK; 964 } else if (!strncmp(key, chrdrv_prefix, strlen(chrdrv_prefix))) { 965 ftype = S_IFCHR; 966 } else if (!strncmp(key, sckdrv_prefix, strlen(sckdrv_prefix))) { 967 ftype = S_IFSOCK; 968 } else { 969 continue; 970 } 971 972 if ((r = ds_retrieve_u32(key, &value)) != OK) { 973 printf("VFS: ds_event: ds_retrieve_u32 failed\n"); 974 break; 975 } 976 if (value != DS_DRIVER_UP) continue; 977 978 /* Perform up. */ 979 if (ftype == S_IFBLK || ftype == S_IFCHR) 980 dmap_endpt_up(owner_endpoint, (ftype == S_IFBLK)); 981 else 982 smap_endpt_up(owner_endpoint); 983 } 984 985 if (r != ENOENT) printf("VFS: ds_event: ds_check failed: %d\n", r); 986 } 987 988 /* A function to be called on panic(). */ 989 void panic_hook(void) 990 { 991 printf("VFS mthread stacktraces:\n"); 992 mthread_stacktraces(); 993 } 994 995 /*===========================================================================* 996 * do_getrusage * 997 *===========================================================================*/ 998 int do_getrusage(void) 999 { 1000 /* Obsolete vfs_getrusage(2) call from userland. The getrusage call is 1001 * now fully handled by PM, and for any future fields that should be 1002 * supplied by VFS, VFS should be queried by PM rather than by the user 1003 * program directly. TODO: remove this call after the next release. 1004 */ 1005 return OK; 1006 } 1007