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