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
;
156 /* Is the file descriptor valid? */
157 if ((f
= get_filp(m_in
.fd
)) == NIL_FILP
) return(err_code
);
159 switch (m_in
.request
) {
161 /* This replaces the old dup() system call. */
162 if (m_in
.addr
< 0 || m_in
.addr
>= OPEN_MAX
) return(EINVAL
);
163 if ((r
= get_fd(m_in
.addr
, 0, &new_fd
, &dummy
)) != OK
) return(r
);
165 fp
->fp_filp
[new_fd
] = f
;
169 /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
170 return( FD_ISSET(m_in
.fd
, &fp
->fp_cloexec_set
) ? FD_CLOEXEC
: 0);
173 /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
174 if(m_in
.addr
& FD_CLOEXEC
)
175 FD_SET(m_in
.fd
, &fp
->fp_cloexec_set
);
177 FD_CLR(m_in
.fd
, &fp
->fp_cloexec_set
);
181 /* Get file status flags (O_NONBLOCK and O_APPEND). */
182 fl
= f
->filp_flags
& (O_NONBLOCK
| O_APPEND
| O_ACCMODE
);
186 /* Set file status flags (O_NONBLOCK and O_APPEND). */
187 fl
= O_NONBLOCK
| O_APPEND
| O_REOPEN
;
188 f
->filp_flags
= (f
->filp_flags
& ~fl
) | (m_in
.addr
& fl
);
194 /* Set or clear a file lock. */
195 r
= lock_op(f
, m_in
.request
);
200 /* Free a section of a file. Preparation is done here, actual freeing
204 struct flock flock_arg
;
207 /* Check if it's a regular file. */
208 if((f
->filp_vno
->v_mode
& I_TYPE
) != I_REGULAR
) return(EINVAL
);
209 if (!(f
->filp_mode
& W_BIT
)) return(EBADF
);
211 /* Copy flock data from userspace. */
212 if((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.name1
, SELF
,
213 (vir_bytes
) &flock_arg
, (phys_bytes
) sizeof(flock_arg
))) != OK
)
216 /* Convert starting offset to signed. */
217 offset
= (signed long) flock_arg
.l_start
;
219 /* Figure out starting position base. */
220 switch(flock_arg
.l_whence
) {
221 case SEEK_SET
: start
= 0; break;
223 if (ex64hi(f
->filp_pos
) != 0)
224 panic("do_fcntl: position in file too high");
225 start
= ex64lo(f
->filp_pos
);
227 case SEEK_END
: start
= f
->filp_vno
->v_size
; break;
228 default: return EINVAL
;
231 /* Check for overflow or underflow. */
232 if(offset
> 0 && start
+ offset
< start
) return EINVAL
;
233 if(offset
< 0 && start
+ offset
> start
) return EINVAL
;
235 if(start
< 0) return EINVAL
;
237 if(flock_arg
.l_len
!= 0) {
238 if(start
>= f
->filp_vno
->v_size
) return EINVAL
;
239 end
= start
+ flock_arg
.l_len
;
240 if(end
<= start
) return EINVAL
;
241 if(end
> f
->filp_vno
->v_size
) end
= f
->filp_vno
->v_size
;
246 r
= req_ftrunc(f
->filp_vno
->v_fs_e
, f
->filp_vno
->v_inode_nr
, start
,
249 if(r
== OK
&& flock_arg
.l_len
== 0)
250 f
->filp_vno
->v_size
= start
;
261 /*===========================================================================*
263 *===========================================================================*/
267 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
268 if (vmp
->m_dev
!= NO_DEV
)
269 req_sync(vmp
->m_fs_e
);
274 /*===========================================================================*
276 *===========================================================================*/
277 PUBLIC
int do_fsync()
279 /* Perform the fsync() system call. For now, don't be unnecessarily smart. */
285 /*===========================================================================*
287 *===========================================================================*/
288 PRIVATE
void unmount_all(void)
290 /* Unmount all filesystems. File systems are mounted on other file systems,
291 * so you have to pull off the loose bits repeatedly to get it all undone.
295 for (i
= 0; i
< NR_MNTS
; i
++) {
298 /* Unmount at least one. */
299 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
300 if (vmp
->m_dev
!= NO_DEV
)
301 unmount(vmp
->m_dev
, NULL
);
306 /*===========================================================================*
308 *===========================================================================*/
309 PUBLIC
void pm_reboot()
311 /* Perform the FS side of the reboot call. */
318 /* Do exit processing for all leftover processes and servers,
319 * but don't actually exit them (if they were really gone, PM
320 * will tell us about it).
322 for (i
= 0; i
< NR_PROCS
; i
++)
323 if((m_in
.endpt1
= fproc
[i
].fp_endpoint
) != NONE
) {
324 /* No FP_EXITING, just free the resources, otherwise
325 * consistency check for fp_endpoint (set to NONE) will
326 * fail if process wants to do something in the (short)
329 free_proc(&fproc
[i
], 0);
339 /*===========================================================================*
341 *===========================================================================*/
342 PUBLIC
void pm_fork(pproc
, cproc
, cpid
)
343 int pproc
; /* Parent process */
344 int cproc
; /* Child process */
345 int cpid
; /* Child process id */
347 /* Perform those aspects of the fork() system call that relate to files.
348 * In particular, let the child inherit its parent's file descriptors.
349 * The parent and child parameters tell who forked off whom. The file
350 * system uses the same slot numbers as the kernel. Only PM makes this call.
353 register struct fproc
*cp
;
354 int i
, parentno
, childno
;
356 /* Check up-to-dateness of fproc. */
357 okendpt(pproc
, &parentno
);
359 /* PM gives child endpoint, which implies process slot information.
360 * Don't call isokendpt, because that will verify if the endpoint
361 * number is correct in fproc, which it won't be.
363 childno
= _ENDPOINT_P(cproc
);
364 if(childno
< 0 || childno
>= NR_PROCS
)
365 panic("FS: bogus child for forking: %d", m_in
.child_endpt
);
366 if(fproc
[childno
].fp_pid
!= PID_FREE
)
367 panic("FS: forking on top of in-use child: %d", childno
);
369 /* Copy the parent's fproc struct to the child. */
370 fproc
[childno
] = fproc
[parentno
];
372 /* Increase the counters in the 'filp' table. */
373 cp
= &fproc
[childno
];
374 fp
= &fproc
[parentno
];
376 for (i
= 0; i
< OPEN_MAX
; i
++)
377 if (cp
->fp_filp
[i
] != NIL_FILP
) cp
->fp_filp
[i
]->filp_count
++;
379 /* Fill in new process and endpoint id. */
381 cp
->fp_endpoint
= cproc
;
383 /* A forking process never has an outstanding grant,
384 * as it isn't blocking on i/o.
386 if(GRANT_VALID(fp
->fp_grant
)) {
387 printf("vfs: fork: fp (endpoint %d) has grant %d\n", fp
->fp_endpoint
, fp
->fp_grant
);
388 panic("fp contains valid grant");
390 if(GRANT_VALID(cp
->fp_grant
)) {
391 printf("vfs: fork: cp (endpoint %d) has grant %d\n", cp
->fp_endpoint
, cp
->fp_grant
);
392 panic("cp contains valid grant");
395 /* A child is not a process leader. */
398 /* This child has not exec()ced yet. */
401 /* Record the fact that both root and working dir have another user. */
402 if(cp
->fp_rd
) dup_vnode(cp
->fp_rd
);
403 if(cp
->fp_wd
) dup_vnode(cp
->fp_wd
);
406 /*===========================================================================*
408 *===========================================================================*/
409 PRIVATE
void free_proc(struct fproc
*exiter
, int flags
)
412 register struct fproc
*rfp
;
413 register struct filp
*rfilp
;
414 register struct vnode
*vp
;
419 fp
= exiter
; /* get_filp() needs 'fp' */
421 if(fp
->fp_endpoint
== NONE
) {
422 panic("free_proc: already free");
425 if (fp_is_blocked(fp
)) {
427 unpause(fp
->fp_endpoint
);
433 /* Loop on file descriptors, closing any that are open. */
434 for (i
= 0; i
< OPEN_MAX
; i
++) {
435 (void) close_fd(fp
, i
);
438 /* Check if any process is SUSPENDed on this driver.
439 * If a driver exits, unmap its entries in the dmap table.
440 * (unmapping has to be done after the first step, because the
441 * dmap table is used in the first step.)
443 unsuspend_by_endpt(fp
->fp_endpoint
);
445 /* Release root and working directories. */
446 if(fp
->fp_rd
) { put_vnode(fp
->fp_rd
); fp
->fp_rd
= NIL_VNODE
; }
447 if(fp
->fp_wd
) { put_vnode(fp
->fp_wd
); fp
->fp_wd
= NIL_VNODE
; }
449 /* The rest of these actions is only done when processes actually
452 if(!(flags
& FP_EXITING
)) {
457 /* Invalidate endpoint number for error and sanity checks. */
458 fp
->fp_endpoint
= NONE
;
460 /* If a session leader exits and it has a controlling tty, then revoke
461 * access to its controlling tty from all other processes using it.
463 if (fp
->fp_sesldr
&& fp
->fp_tty
!= 0) {
467 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
468 if(rfp
->fp_pid
== PID_FREE
) continue;
469 if (rfp
->fp_tty
== dev
) rfp
->fp_tty
= 0;
471 for (i
= 0; i
< OPEN_MAX
; i
++) {
472 if ((rfilp
= rfp
->fp_filp
[i
]) == NIL_FILP
) continue;
473 if (rfilp
->filp_mode
== FILP_CLOSED
) continue;
474 vp
= rfilp
->filp_vno
;
475 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
476 if ((dev_t
) vp
->v_sdev
!= dev
) continue;
478 (void) dev_close(dev
, rfilp
-filp
);
479 /* Ignore any errors, even SUSPEND. */
481 rfilp
->filp_mode
= FILP_CLOSED
;
486 /* Exit done. Mark slot as free. */
487 fp
->fp_pid
= PID_FREE
;
492 /*===========================================================================*
494 *===========================================================================*/
495 PUBLIC
void pm_exit(proc
)
499 /* Perform the file system portion of the exit(status) system call. */
501 /* Nevertheless, pretend that the call came from the user. */
502 okendpt(proc
, &exitee_p
);
503 free_proc(&fproc
[exitee_p
], FP_EXITING
);
506 /*===========================================================================*
508 *===========================================================================*/
509 PUBLIC
void pm_setgid(proc_e
, egid
, rgid
)
514 register struct fproc
*tfp
;
517 okendpt(proc_e
, &slot
);
520 tfp
->fp_effgid
= egid
;
521 tfp
->fp_realgid
= rgid
;
525 /*===========================================================================*
527 *===========================================================================*/
528 PUBLIC
void pm_setgroups(proc_e
, ngroups
, groups
)
536 okendpt(proc_e
, &slot
);
538 if (ngroups
* sizeof(gid_t
) > sizeof(rfp
->fp_sgroups
))
539 panic("VFS: pm_setgroups: too much data to copy");
540 if(sys_datacopy(who_e
, (vir_bytes
) groups
, SELF
, (vir_bytes
) rfp
->fp_sgroups
,
541 ngroups
* sizeof(gid_t
)) == OK
) {
542 rfp
->fp_ngroups
= ngroups
;
544 panic("VFS: pm_setgroups: datacopy failed");
548 /*===========================================================================*
550 *===========================================================================*/
551 PUBLIC
void pm_setuid(proc_e
, euid
, ruid
)
556 register struct fproc
*tfp
;
559 okendpt(proc_e
, &slot
);
562 tfp
->fp_effuid
= euid
;
563 tfp
->fp_realuid
= ruid
;
566 /*===========================================================================*
568 *===========================================================================*/
569 PUBLIC
int do_svrctl()
571 switch (m_in
.svrctl_req
) {
572 /* No control request implemented yet. */
578 /*===========================================================================*
580 *===========================================================================*/
581 PUBLIC
int pm_dumpcore(proc_e
, seg_ptr
)
583 struct mem_map
*seg_ptr
;
587 /* Terminate the process */
588 okendpt(proc_e
, &proc_s
);
589 free_proc(&fproc
[proc_s
], FP_EXITING
);
594 /*===========================================================================*
596 *===========================================================================*/
597 PUBLIC
void ds_event()
599 char key
[DS_MAX_KEYLEN
];
600 char *driver_prefix
= "drv.vfs.";
603 endpoint_t owner_endpoint
;
606 /* Get the event and the owner from DS. */
607 r
= ds_check(key
, &type
, &owner_endpoint
);
610 printf("vfs: ds_event: ds_check failed: %d\n", r
);
613 r
= ds_retrieve_u32(key
, &value
);
615 printf("vfs: ds_event: ds_retrieve_u32 failed\n");
619 /* Only check for VFS driver up events. */
620 if(strncmp(key
, driver_prefix
, sizeof(driver_prefix
))
621 || value
!= DS_DRIVER_UP
) {
626 dmap_endpt_up(owner_endpoint
);