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.
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
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>
36 #include <minix/vfsif.h>
40 #define CORE_NAME "core"
41 #define CORE_MODE 0777 /* mode to use on core image files */
43 #if ENABLE_SYSCALL_STATS
44 unsigned long calls_stats
[NR_VFS_CALLS
];
47 static void free_proc(int flags
);
49 /*===========================================================================*
51 *===========================================================================*/
52 int do_getsysinfo(void)
55 struct fproc_light
*rfpl
;
57 vir_bytes src_addr
, dst_addr
;
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
;
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.
70 if (!super_user
) return(EPERM
);
74 src_addr
= (vir_bytes
) fproc
;
75 len
= sizeof(struct fproc
) * NR_PROCS
;
78 src_addr
= (vir_bytes
) dmap
;
79 len
= sizeof(struct dmap
) * NR_DEVICES
;
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
;
93 rfpl
->fpl_task
= NONE
;
95 src_addr
= (vir_bytes
) fproc_light
;
96 len
= sizeof(fproc_light
);
98 #if ENABLE_SYSCALL_STATS
100 src_addr
= (vir_bytes
) calls_stats
;
101 len
= sizeof(calls_stats
);
111 return sys_datacopy_wrapper(SELF
, src_addr
, who_e
, dst_addr
, len
);
114 /*===========================================================================*
116 *===========================================================================*/
119 /* Perform the fcntl(fd, cmd, ...) system call. */
121 int fd
, new_fd
, fl
, r
= OK
, fcntl_req
, fcntl_argx
;
123 tll_access_t locktype
;
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
;
130 /* Is the file descriptor valid? */
131 locktype
= (fcntl_req
== F_FREESP
) ? VNODE_WRITE
: VNODE_READ
;
132 if ((f
= get_filp(fd
, locktype
)) == NULL
)
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
) {
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
);
151 /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
153 if (FD_ISSET(fd
, &fp
->fp_cloexec_set
))
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
);
162 FD_CLR(fd
, &fp
->fp_cloexec_set
);
166 /* Get file status flags (O_NONBLOCK and O_APPEND). */
167 fl
= f
->filp_flags
& (O_NONBLOCK
| O_APPEND
| O_ACCMODE
);
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
);
180 /* Set or clear a file lock. */
181 r
= lock_op(fd
, fcntl_req
, addr
);
186 /* Free a section of a file */
187 off_t start
, end
, offset
;
188 struct flock flock_arg
;
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
;
194 /* Copy flock data from userspace. */
195 r
= sys_datacopy_wrapper(who_e
, addr
, SELF
,
196 (vir_bytes
)&flock_arg
, sizeof(flock_arg
));
201 /* Convert starting offset to signed. */
202 offset
= (off_t
) flock_arg
.l_start
;
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;
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
;
218 if (start
< 0) r
= EINVAL
;
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
;
231 r
= req_ftrunc(f
->filp_vno
->v_fs_e
, f
->filp_vno
->v_inode_nr
,start
,end
);
233 if (r
== OK
&& flock_arg
.l_len
== 0)
234 f
->filp_vno
->v_size
= start
;
239 r
= !!(f
->filp_flags
& O_NOSIGPIPE
);
243 f
->filp_flags
|= O_NOSIGPIPE
;
245 f
->filp_flags
&= ~O_NOSIGPIPE
;
247 case F_FLUSH_FS_CACHE
:
249 struct vnode
*vn
= f
->filp_vno
;
250 mode_t mode
= f
->filp_vno
->v_mode
;
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
);
260 /* Remaining cases.. Meaning unclear. */
273 /*===========================================================================*
275 *===========================================================================*/
281 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
282 if ((r
= lock_vmnt(vmp
, VMNT_READ
)) != OK
)
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
);
294 /*===========================================================================*
296 *===========================================================================*/
299 /* Perform the fsync() system call. */
305 fd
= job_m_in
.m_lc_vfs_fsync
.fd
;
307 if ((rfilp
= get_filp(fd
, VNODE_READ
)) == NULL
)
310 dev
= rfilp
->filp_vno
->v_dev
;
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
)
317 if (vmp
->m_dev
!= NO_DEV
&& vmp
->m_dev
== dev
&&
318 vmp
->m_fs_e
!= NONE
&& vmp
->m_root_node
!= NULL
) {
320 req_sync(vmp
->m_fs_e
);
328 int dupvm(struct fproc
*rfp
, int pfd
, int *vmfd
, struct filp
**newfilp
)
331 struct filp
*f
= NULL
;
332 struct fproc
*vmf
= fproc_addr(VM_PROC_NR
);
336 if ((f
= get_filp2(rfp
, pfd
, VNODE_READ
)) == NULL
) {
337 printf("VFS dupvm: get_filp2 failed\n");
341 if(!(f
->filp_vno
->v_vmnt
->m_fs_flags
& RES_HASPEEK
)) {
343 #if 0 /* Noisy diagnostic for mmap() by ld.so */
344 printf("VFS dupvm: no peek available\n");
350 assert(f
->filp_vno
->v_vmnt
);
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
);
359 /* get free FD in VM */
360 if((result
=get_fd(vmf
, 0, 0, &procfd
, NULL
)) != OK
) {
362 printf("VFS dupvm: getfd failed\n");
369 assert(f
->filp_count
> 0);
370 vmf
->fp_filp
[procfd
] = f
;
377 /*===========================================================================*
379 *===========================================================================*/
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.
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
;
398 #endif /* !defined(NDEBUG) */
399 struct filp
*f
= NULL
;
402 if(job_m_in
.m_source
!= VM_PROC_NR
)
405 if(isokendpt(ep
, &slot
) != OK
) rfp
= NULL
;
406 else rfp
= &fproc
[slot
];
409 vmf
= fproc_addr(VM_PROC_NR
);
410 #endif /* !defined(NDEBUG) */
415 case VMVFSREQ_FDLOOKUP
:
419 /* Lookup fd in referenced process. */
422 printf("VFS: why isn't ep %d here?!\n", ep
);
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");
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
;
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
;
447 job_m_out
.VMV_FD
= procfd
;
453 case VMVFSREQ_FDCLOSE
:
455 result
= close_fd(fp
, req_fd
, FALSE
/*may_suspend*/);
457 printf("VFS: VM fd close for fd %d, %d (%d)\n",
458 req_fd
, fp
->fp_endpoint
, result
);
464 result
= actual_lseek(fp
, req_fd
, SEEK_SET
, offset
,
468 result
= actual_read_write_peek(fp
, PEEKING
,
469 req_fd
, /* vir_bytes */ 0, length
);
475 panic("VFS: bad request code from VM\n");
483 /* fp is VM still. */
485 job_m_out
.VMV_ENDPOINT
= ep
;
486 job_m_out
.VMV_RESULT
= result
;
487 job_m_out
.VMV_REQID
= req_id
;
489 /* Reply asynchronously as VM may not be able to receive
490 * an ipc_sendnb() message.
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");
496 /* VFS does not reply any further */
500 /*===========================================================================*
502 *===========================================================================*/
506 /* Perform the VFS side of the reboot call. This call is performed from the PM
511 struct fproc
*rfp
, *pmfp
;
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).
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.
530 for (i
= 0; i
< NR_PROCS
; i
++) {
533 /* Don't just free the proc right away, but let it finish what it was
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 */
539 worker_set_proc(pmfp
); /* restore original process context */
541 if (rfp
!= fp
) unlock_proc(rfp
);
545 unmount_all(0 /* Don't force */);
547 /* Try to exit all processes again including File Servers */
548 for (i
= 0; i
< NR_PROCS
; i
++) {
551 /* Don't just free the proc right away, but let it finish what it was
553 if (rfp
!= fp
) lock_proc(rfp
);
554 if (rfp
->fp_endpoint
!= NONE
) {
555 worker_set_proc(rfp
); /* temporarily fake process context */
557 worker_set_proc(pmfp
); /* restore original process context */
559 if (rfp
!= fp
) unlock_proc(rfp
);
563 unmount_all(1 /* Force */);
565 /* Reply to PM for synchronization */
566 memset(&m_out
, 0, sizeof(m_out
));
568 m_out
.m_type
= VFS_PM_REBOOT_REPLY
;
570 if ((r
= ipc_send(PM_PROC_NR
, &m_out
)) != OK
)
571 panic("pm_reboot: ipc_send failed: %d", r
);
574 /*===========================================================================*
576 *===========================================================================*/
577 void pm_fork(endpoint_t pproc
, endpoint_t cproc
, pid_t cpid
)
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.
587 #endif /* !defined(NDEBUG) */
588 int i
, parentno
, childno
;
591 /* Check up-to-dateness of fproc. */
592 okendpt(pproc
, &parentno
);
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.
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
);
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
;
610 /* Increase the counters in the 'filp' table. */
611 cp
= &fproc
[childno
];
613 pp
= &fproc
[parentno
];
614 #endif /* !defined(NDEBUG) */
616 for (i
= 0; i
< OPEN_MAX
; i
++)
617 if (cp
->fp_filp
[i
] != NULL
) cp
->fp_filp
[i
]->filp_count
++;
619 /* Fill in new process and endpoint id. */
621 cp
->fp_endpoint
= cproc
;
624 /* A forking process cannot possibly be suspended on anything. */
625 assert(pp
->fp_blocked_on
== FP_BLOCKED_ON_NONE
);
626 #endif /* !defined(NDEBUG) */
628 /* A child is not a process leader, not being revived, etc. */
629 cp
->fp_flags
= FP_NOFLAGS
;
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
);
636 /*===========================================================================*
638 *===========================================================================*/
639 static void free_proc(int flags
)
642 register struct fproc
*rfp
;
643 register struct filp
*rfilp
;
644 register struct vnode
*vp
;
647 if (fp
->fp_endpoint
== NONE
)
648 panic("free_proc: already free");
650 if (fp_is_blocked(fp
))
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*/);
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
; }
662 /* The rest of these actions is only done when processes actually exit. */
663 if (!(flags
& FP_EXITING
)) return;
665 fp
->fp_flags
|= FP_EXITING
;
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.)
672 unsuspend_by_endpt(fp
->fp_endpoint
);
673 dmap_unmap_by_endpt(fp
->fp_endpoint
);
674 smap_unmap_by_endpt(fp
->fp_endpoint
);
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 */
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.
683 if ((fp
->fp_flags
& FP_SESLDR
) && fp
->fp_tty
!= 0) {
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;
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
;
704 /* Exit done. Mark slot as free. */
705 fp
->fp_endpoint
= NONE
;
706 fp
->fp_pid
= PID_FREE
;
707 fp
->fp_flags
= FP_NOFLAGS
;
710 /*===========================================================================*
712 *===========================================================================*/
715 /* Perform the file system portion of the exit(status) system call.
716 * This function is called from the context of the exiting process.
719 free_proc(FP_EXITING
);
722 /*===========================================================================*
724 *===========================================================================*/
726 pm_setgid(endpoint_t proc_e
, int egid
, int rgid
)
728 register struct fproc
*tfp
;
731 okendpt(proc_e
, &slot
);
734 tfp
->fp_effgid
= egid
;
735 tfp
->fp_realgid
= rgid
;
739 /*===========================================================================*
741 *===========================================================================*/
743 pm_setgroups(endpoint_t proc_e
, int ngroups
, gid_t
*groups
)
748 okendpt(proc_e
, &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
;
756 panic("VFS: pm_setgroups: datacopy failed");
760 /*===========================================================================*
762 *===========================================================================*/
764 pm_setuid(endpoint_t proc_e
, int euid
, int ruid
)
769 okendpt(proc_e
, &slot
);
772 tfp
->fp_effuid
= euid
;
773 tfp
->fp_realuid
= ruid
;
776 /*===========================================================================*
778 *===========================================================================*/
779 void pm_setsid(endpoint_t proc_e
)
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.
787 /* Make the process a session leader with no controlling tty. */
788 okendpt(proc_e
, &slot
);
790 rfp
->fp_flags
|= FP_SESLDR
;
794 /*===========================================================================*
796 *===========================================================================*/
799 unsigned long svrctl
;
802 svrctl
= job_m_in
.m_lc_svrctl
.request
;
803 ptr
= job_m_in
.m_lc_svrctl
.arg
;
805 if (IOCGROUP(svrctl
) != 'F') return(EINVAL
);
811 struct sysgetenv sysgetenv
;
816 /* Copy sysgetenv structure to VFS */
817 if (sys_datacopy_wrapper(who_e
, ptr
, SELF
, (vir_bytes
) &sysgetenv
,
818 sizeof(sysgetenv
)) != OK
)
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
)) {
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
)
836 search_key
[sysgetenv
.keylen
] = '\0'; /* Limit string */
838 /* Is it a parameter we know? */
839 if (svrctl
== VFSSETPARAM
) {
840 if (!strcmp(search_key
, "verbose")) {
842 if ((s
= sys_datacopy_wrapper(who_e
,
843 (vir_bytes
) sysgetenv
.val
, SELF
,
844 (vir_bytes
) &val
, sysgetenv
.vallen
)) != OK
)
846 val
[sysgetenv
.vallen
] = '\0'; /* Limit string */
847 verbose_val
= atoi(val
);
848 if (verbose_val
< 0 || verbose_val
> 4) {
851 verbose
= verbose_val
;
856 } else { /* VFSGETPARAM */
860 if (!strcmp(search_key
, "print_traces")) {
861 mthread_stacktraces();
863 sysgetenv
.vallen
= 0;
865 } else if (!strcmp(search_key
, "print_select")) {
868 sysgetenv
.vallen
= 0;
870 } else if (!strcmp(search_key
, "active_threads")) {
871 int active
= NR_WTHREADS
- worker_available();
872 snprintf(small_buf
, sizeof(small_buf
) - 1,
874 sysgetenv
.vallen
= strlen(small_buf
);
879 if ((s
= sys_datacopy_wrapper(SELF
,
880 (vir_bytes
) &sysgetenv
, who_e
, ptr
,
881 sizeof(sysgetenv
))) != OK
)
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
)
900 /*===========================================================================*
902 *===========================================================================*/
903 int pm_dumpcore(int csig
, vir_bytes exe_name
)
907 char core_path
[PATH_MAX
];
908 char proc_name
[PROC_NAME_LEN
];
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.
917 if (fp_is_blocked(fp
))
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
;
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';
932 /* write the core dump */
933 f
= get_filp(core_fd
, VNODE_WRITE
);
935 write_elf_core_file(f
, csig
, proc_name
);
939 /* The core file descriptor will be closed as part of the process exit. */
940 free_proc(FP_EXITING
);
945 /*===========================================================================*
947 *===========================================================================*/
951 char key
[DS_MAX_KEYLEN
];
952 char *blkdrv_prefix
= "drv.blk.";
953 char *chrdrv_prefix
= "drv.chr.";
954 char *sckdrv_prefix
= "drv.sck.";
957 endpoint_t owner_endpoint
;
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
))) {
964 } else if (!strncmp(key
, chrdrv_prefix
, strlen(chrdrv_prefix
))) {
966 } else if (!strncmp(key
, sckdrv_prefix
, strlen(sckdrv_prefix
))) {
972 if ((r
= ds_retrieve_u32(key
, &value
)) != OK
) {
973 printf("VFS: ds_event: ds_retrieve_u32 failed\n");
976 if (value
!= DS_DRIVER_UP
) continue;
979 if (ftype
== S_IFBLK
|| ftype
== S_IFCHR
)
980 dmap_endpt_up(owner_endpoint
, (ftype
== S_IFBLK
));
982 smap_endpt_up(owner_endpoint
);
985 if (r
!= ENOENT
) printf("VFS: ds_event: ds_check failed: %d\n", r
);
988 /* A function to be called on panic(). */
989 void panic_hook(void)
991 printf("VFS mthread stacktraces:\n");
992 mthread_stacktraces();
995 /*===========================================================================*
997 *===========================================================================*/
998 int do_getrusage(void)
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.