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_dup: perform the DUP system call
7 * do_fcntl: perform the FCNTL system call
8 * do_sync: perform the SYNC system call
9 * do_fsync: perform the FSYNC system call
10 * do_reboot: sync disks and prepare for shutdown
11 * do_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
24 #include <unistd.h> /* cc runs out of memory with unistd.h :-( */
25 #include <minix/callnr.h>
26 #include <minix/safecopies.h>
27 #include <minix/endpoint.h>
28 #include <minix/com.h>
29 #include <minix/u64.h>
30 #include <sys/ptrace.h>
31 #include <sys/svrctl.h>
35 #include <minix/vfsif.h>
39 #define CORE_NAME "core"
40 #define CORE_MODE 0777 /* mode to use on core image files */
42 #if ENABLE_SYSCALL_STATS
43 PUBLIC
unsigned long calls_stats
[NCALLS
];
46 FORWARD
_PROTOTYPE( void free_proc
, (struct fproc
*freed
, int flags
) );
47 FORWARD
_PROTOTYPE( void unmount_all
, (void) );
49 FORWARD _PROTOTYPE( int dumpcore, (int proc_e, struct mem_map *seg_ptr) );
50 FORWARD _PROTOTYPE( int write_bytes, (struct inode *rip, off_t off,
51 char *buf, size_t bytes) );
52 FORWARD _PROTOTYPE( int write_seg, (struct inode *rip, off_t off, int proc_e,
53 int seg, off_t seg_off, phys_bytes seg_bytes) );
59 /*===========================================================================*
61 *===========================================================================*/
62 PUBLIC
int do_getsysinfo()
64 struct fproc
*proc_addr
;
65 vir_bytes src_addr
, dst_addr
;
69 /* Only su may call do_getsysinfo. This call may leak information (and is not
70 * stable enough to be part of the API/ABI).
73 if (!super_user
) return(EPERM
);
75 switch(m_in
.info_what
) {
77 proc_addr
= &fproc
[0];
78 src_addr
= (vir_bytes
) &proc_addr
;
79 len
= sizeof(struct fproc
*);
82 src_addr
= (vir_bytes
) fproc
;
83 len
= sizeof(struct fproc
) * NR_PROCS
;
86 src_addr
= (vir_bytes
) dmap
;
87 len
= sizeof(struct dmap
) * NR_DEVICES
;
89 #if ENABLE_SYSCALL_STATS
91 src_addr
= (vir_bytes
) calls_stats
;
92 len
= sizeof(calls_stats
);
99 dst_addr
= (vir_bytes
) m_in
.info_where
;
100 if (OK
!= (s
= sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
))) return(s
);
105 /*===========================================================================*
107 *===========================================================================*/
110 /* Perform the dup(fd) or dup2(fd,fd2) system call. These system calls are
111 * obsolete. In fact, it is not even possible to invoke them using the
112 * current library because the library routines call fcntl(). They are
113 * provided to permit old binary programs to continue to run.
117 register struct filp
*f
;
121 /* Is the file descriptor valid? */
122 rfd
= m_in
.fd
& ~DUP_MASK
; /* kill off dup2 bit, if on */
123 if ((f
= get_filp(rfd
)) == NIL_FILP
) return(err_code
);
125 /* Distinguish between dup and dup2. */
126 if (m_in
.fd
== rfd
) { /* bit not on */
128 if ((r
= get_fd(0, 0, &m_in
.fd2
, &dummy
)) != OK
) return(r
);
131 if (m_in
.fd2
< 0 || m_in
.fd2
>= OPEN_MAX
) return(EBADF
);
132 if (rfd
== m_in
.fd2
) return(m_in
.fd2
); /* ignore the call: dup2(x, x) */
133 m_in
.fd
= m_in
.fd2
; /* prepare to close fd2 */
134 (void) do_close(); /* cannot fail */
137 /* Success. Set up new file descriptors. */
139 fp
->fp_filp
[m_in
.fd2
] = f
;
140 FD_SET(m_in
.fd2
, &fp
->fp_filp_inuse
);
145 /*===========================================================================*
147 *===========================================================================*/
148 PUBLIC
int do_fcntl()
150 /* Perform the fcntl(fd, request, ...) system call. */
152 register struct filp
*f
;
154 long cloexec_mask
; /* bit map for the FD_CLOEXEC flag */
155 long clo_value
; /* FD_CLOEXEC flag in proper position */
158 /* Is the file descriptor valid? */
159 if ((f
= get_filp(m_in
.fd
)) == NIL_FILP
) return(err_code
);
161 switch (m_in
.request
) {
163 /* This replaces the old dup() system call. */
164 if (m_in
.addr
< 0 || m_in
.addr
>= OPEN_MAX
) return(EINVAL
);
165 if ((r
= get_fd(m_in
.addr
, 0, &new_fd
, &dummy
)) != OK
) return(r
);
167 fp
->fp_filp
[new_fd
] = f
;
171 /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
172 return( FD_ISSET(m_in
.fd
, &fp
->fp_cloexec_set
) ? FD_CLOEXEC
: 0);
175 /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
176 if(m_in
.addr
& FD_CLOEXEC
)
177 FD_SET(m_in
.fd
, &fp
->fp_cloexec_set
);
179 FD_CLR(m_in
.fd
, &fp
->fp_cloexec_set
);
183 /* Get file status flags (O_NONBLOCK and O_APPEND). */
184 fl
= f
->filp_flags
& (O_NONBLOCK
| O_APPEND
| O_ACCMODE
);
188 /* Set file status flags (O_NONBLOCK and O_APPEND). */
189 fl
= O_NONBLOCK
| O_APPEND
| O_REOPEN
;
190 f
->filp_flags
= (f
->filp_flags
& ~fl
) | (m_in
.addr
& fl
);
196 /* Set or clear a file lock. */
197 r
= lock_op(f
, m_in
.request
);
202 /* Free a section of a file. Preparation is done here, actual freeing
206 struct flock flock_arg
;
209 /* Check if it's a regular file. */
210 if((f
->filp_vno
->v_mode
& I_TYPE
) != I_REGULAR
) return(EINVAL
);
211 if (!(f
->filp_mode
& W_BIT
)) return(EBADF
);
213 /* Copy flock data from userspace. */
214 if((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.name1
, SELF
,
215 (vir_bytes
) &flock_arg
, (phys_bytes
) sizeof(flock_arg
))) != OK
)
218 /* Convert starting offset to signed. */
219 offset
= (signed long) flock_arg
.l_start
;
221 /* Figure out starting position base. */
222 switch(flock_arg
.l_whence
) {
223 case SEEK_SET
: start
= 0; if(offset
< 0) return EINVAL
; break;
225 if (ex64hi(f
->filp_pos
) != 0)
226 panic(__FILE__
, "do_fcntl: position in file too high",
229 start
= ex64lo(f
->filp_pos
);
231 case SEEK_END
: start
= f
->filp_vno
->v_size
; break;
232 default: return EINVAL
;
235 /* Check for overflow or underflow. */
236 if(offset
> 0 && start
+ offset
< start
) return EINVAL
;
237 if(offset
< 0 && start
+ offset
> start
) return EINVAL
;
239 if(flock_arg
.l_len
> 0) {
240 end
= start
+ flock_arg
.l_len
;
241 if(end
<= start
) return EINVAL
;
246 return req_ftrunc(f
->filp_vno
->v_fs_e
, f
->filp_vno
->v_inode_nr
, start
,
256 /*===========================================================================*
258 *===========================================================================*/
262 for (vmp
= &vmnt
[1]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
263 if (vmp
->m_dev
!= NO_DEV
)
264 req_sync(vmp
->m_fs_e
);
269 /*===========================================================================*
271 *===========================================================================*/
272 PUBLIC
int do_fsync()
274 /* Perform the fsync() system call. For now, don't be unnecessarily smart. */
280 /*===========================================================================*
282 *===========================================================================*/
283 PRIVATE
void unmount_all(void)
285 /* Unmount all filesystems. File systems are mounted on other file systems,
286 * so you have to pull off the loose bits repeatedly to get it all undone.
290 for (i
= 0; i
< NR_MNTS
; i
++) {
293 /* Unmount at least one. */
294 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
295 if (vmp
->m_dev
!= NO_DEV
)
296 unmount(vmp
->m_dev
, NULL
);
301 /*===========================================================================*
303 *===========================================================================*/
304 PUBLIC
void pm_reboot()
306 /* Perform the FS side of the reboot call. */
313 /* Do exit processing for all leftover processes and servers,
314 * but don't actually exit them (if they were really gone, PM
315 * will tell us about it).
317 for (i
= 0; i
< NR_PROCS
; i
++)
318 if((m_in
.endpt1
= fproc
[i
].fp_endpoint
) != NONE
) {
319 /* No FP_EXITING, just free the resources, otherwise
320 * consistency check for fp_endpoint (set to NONE) will
321 * fail if process wants to do something in the (short)
324 free_proc(&fproc
[i
], 0);
334 /*===========================================================================*
336 *===========================================================================*/
337 PUBLIC
void pm_fork(pproc
, cproc
, cpid
)
338 int pproc
; /* Parent process */
339 int cproc
; /* Child process */
340 int cpid
; /* Child process id */
342 /* Perform those aspects of the fork() system call that relate to files.
343 * In particular, let the child inherit its parent's file descriptors.
344 * The parent and child parameters tell who forked off whom. The file
345 * system uses the same slot numbers as the kernel. Only PM makes this call.
348 register struct fproc
*cp
;
349 int i
, parentno
, childno
;
351 /* Check up-to-dateness of fproc. */
352 okendpt(pproc
, &parentno
);
354 /* PM gives child endpoint, which implies process slot information.
355 * Don't call isokendpt, because that will verify if the endpoint
356 * number is correct in fproc, which it won't be.
358 childno
= _ENDPOINT_P(cproc
);
359 if(childno
< 0 || childno
>= NR_PROCS
)
360 panic(__FILE__
, "FS: bogus child for forking", m_in
.child_endpt
);
361 if(fproc
[childno
].fp_pid
!= PID_FREE
)
362 panic(__FILE__
, "FS: forking on top of in-use child", childno
);
364 /* Copy the parent's fproc struct to the child. */
365 fproc
[childno
] = fproc
[parentno
];
367 /* Increase the counters in the 'filp' table. */
368 cp
= &fproc
[childno
];
369 fp
= &fproc
[parentno
];
371 for (i
= 0; i
< OPEN_MAX
; i
++)
372 if (cp
->fp_filp
[i
] != NIL_FILP
) cp
->fp_filp
[i
]->filp_count
++;
374 /* Fill in new process and endpoint id. */
376 cp
->fp_endpoint
= cproc
;
378 /* A forking process never has an outstanding grant,
379 * as it isn't blocking on i/o.
381 if(GRANT_VALID(fp
->fp_grant
)) {
382 printf("vfs: fork: fp (endpoint %d) has grant %d\n", fp
->fp_endpoint
, fp
->fp_grant
);
383 panic(__FILE__
, "fp contains valid grant", NO_NUM
);
385 if(GRANT_VALID(cp
->fp_grant
)) {
386 printf("vfs: fork: cp (endpoint %d) has grant %d\n", cp
->fp_endpoint
, cp
->fp_grant
);
387 panic(__FILE__
, "cp contains valid grant", NO_NUM
);
390 /* A child is not a process leader. */
393 /* This child has not exec()ced yet. */
396 /* Record the fact that both root and working dir have another user. */
397 if(cp
->fp_rd
) dup_vnode(cp
->fp_rd
);
398 if(cp
->fp_wd
) dup_vnode(cp
->fp_wd
);
401 /*===========================================================================*
403 *===========================================================================*/
404 PRIVATE
void free_proc(struct fproc
*exiter
, int flags
)
407 register struct fproc
*rfp
;
408 register struct filp
*rfilp
;
409 register struct vnode
*vp
;
414 fp
= exiter
; /* get_filp() needs 'fp' */
416 if(fp
->fp_endpoint
== NONE
) {
417 panic(__FILE__
, "free_proc: already free", NO_NUM
);
420 if (fp_is_blocked(fp
)) {
422 unpause(fp
->fp_endpoint
);
428 /* Loop on file descriptors, closing any that are open. */
429 for (i
= 0; i
< OPEN_MAX
; i
++) {
430 (void) close_fd(fp
, i
);
433 /* Check if any process is SUSPENDed on this driver.
434 * If a driver exits, unmap its entries in the dmap table.
435 * (unmapping has to be done after the first step, because the
436 * dmap table is used in the first step.)
438 unsuspend_by_endpt(fp
->fp_endpoint
);
440 /* Release root and working directories. */
441 if(fp
->fp_rd
) { put_vnode(fp
->fp_rd
); fp
->fp_rd
= NIL_VNODE
; }
442 if(fp
->fp_wd
) { put_vnode(fp
->fp_wd
); fp
->fp_wd
= NIL_VNODE
; }
444 /* The rest of these actions is only done when processes actually
447 if(!(flags
& FP_EXITING
)) {
452 /* Invalidate endpoint number for error and sanity checks. */
453 fp
->fp_endpoint
= NONE
;
455 /* If a session leader exits and it has a controlling tty, then revoke
456 * access to its controlling tty from all other processes using it.
458 if (fp
->fp_sesldr
&& fp
->fp_tty
!= 0) {
462 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
463 if(rfp
->fp_pid
== PID_FREE
) continue;
464 if (rfp
->fp_tty
== dev
) rfp
->fp_tty
= 0;
466 for (i
= 0; i
< OPEN_MAX
; i
++) {
467 if ((rfilp
= rfp
->fp_filp
[i
]) == NIL_FILP
) continue;
468 if (rfilp
->filp_mode
== FILP_CLOSED
) continue;
469 vp
= rfilp
->filp_vno
;
470 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
471 if ((dev_t
) vp
->v_sdev
!= dev
) continue;
473 (void) dev_close(dev
, rfilp
-filp
);
474 /* Ignore any errors, even SUSPEND. */
476 rfilp
->filp_mode
= FILP_CLOSED
;
481 /* Exit done. Mark slot as free. */
482 fp
->fp_pid
= PID_FREE
;
487 /*===========================================================================*
489 *===========================================================================*/
490 PUBLIC
void pm_exit(proc
)
494 /* Perform the file system portion of the exit(status) system call. */
496 /* Nevertheless, pretend that the call came from the user. */
497 okendpt(proc
, &exitee_p
);
498 free_proc(&fproc
[exitee_p
], FP_EXITING
);
501 /*===========================================================================*
503 *===========================================================================*/
504 PUBLIC
void pm_setgid(proc_e
, egid
, rgid
)
509 register struct fproc
*tfp
;
512 okendpt(proc_e
, &slot
);
515 tfp
->fp_effgid
= egid
;
516 tfp
->fp_realgid
= rgid
;
520 /*===========================================================================*
522 *===========================================================================*/
523 PUBLIC
void pm_setgroups(proc_e
, ngroups
, groups
)
531 okendpt(proc_e
, &slot
);
533 if (ngroups
* sizeof(gid_t
) > sizeof(rfp
->fp_sgroups
))
534 panic(__FILE__
, "VFS: pm_setgroups: too much data to copy\n", NO_NUM
);
535 if(sys_datacopy(who_e
, (vir_bytes
) groups
, SELF
, (vir_bytes
) rfp
->fp_sgroups
,
536 ngroups
* sizeof(gid_t
)) == OK
) {
537 rfp
->fp_ngroups
= ngroups
;
539 panic(__FILE__
, "VFS: pm_setgroups: datacopy failed\n", NO_NUM
);
543 /*===========================================================================*
545 *===========================================================================*/
546 PUBLIC
void pm_setuid(proc_e
, euid
, ruid
)
551 register struct fproc
*tfp
;
554 okendpt(proc_e
, &slot
);
557 tfp
->fp_effuid
= euid
;
558 tfp
->fp_realuid
= ruid
;
561 /*===========================================================================*
563 *===========================================================================*/
564 PUBLIC
int do_svrctl()
566 switch (m_in
.svrctl_req
) {
568 /* A server in user space calls in to manage a device. */
569 struct fssignon device
;
570 int r
, major
, proc_nr_n
;
572 if (fp
->fp_effuid
!= SU_UID
&& fp
->fp_effuid
!= SERVERS_UID
)
575 /* Try to copy request structure to FS. */
576 if ((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.svrctl_argp
,
577 FS_PROC_NR
, (vir_bytes
) &device
,
578 (phys_bytes
) sizeof(device
))) != OK
)
581 if (isokendpt(who_e
, &proc_nr_n
) != OK
)
584 /* Try to update device mapping. */
585 major
= (device
.dev
>> MAJOR
) & BYTE
;
586 r
=map_driver(NULL
, major
, who_e
, device
.style
, 0 /* !force */);
589 /* If a driver has completed its exec(), it can be announced
592 if(fproc
[proc_nr_n
].fp_execced
) {
593 /* Reply before calling dev_up */
595 printf("do_svrctl: replying before dev_up\n");
601 dmap
[major
].dmap_flags
|= DMAP_BABY
;
612 /*===========================================================================*
614 *===========================================================================*/
615 PUBLIC
int pm_dumpcore(proc_e
, seg_ptr
)
617 struct mem_map
*seg_ptr
;
621 /* Terminate the process */
622 okendpt(proc_e
, &proc_s
);
623 free_proc(&fproc
[proc_s
], FP_EXITING
);