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 MM has performed a FORK system call
12 * do_exec: handle files with FD_CLOEXEC on after MM 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>
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 PUBLIC
unsigned long calls_stats
[NCALLS
];
47 FORWARD
_PROTOTYPE( void free_proc
, (struct fproc
*freed
, int flags
));
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
;
71 printf("FS: unauthorized call of do_getsysinfo by proc %d\n", who_e
);
72 return(EPERM
); /* only su may call do_getsysinfo. This call may leak
73 * information (and is not stable enough to be part
78 switch(m_in
.info_what
) {
80 proc_addr
= &fproc
[0];
81 src_addr
= (vir_bytes
) &proc_addr
;
82 len
= sizeof(struct fproc
*);
85 src_addr
= (vir_bytes
) fproc
;
86 len
= sizeof(struct fproc
) * NR_PROCS
;
89 src_addr
= (vir_bytes
) dmap
;
90 len
= sizeof(struct dmap
) * NR_DEVICES
;
92 #if ENABLE_SYSCALL_STATS
94 src_addr
= (vir_bytes
) calls_stats
;
95 len
= sizeof(calls_stats
);
102 dst_addr
= (vir_bytes
) m_in
.info_where
;
103 if (OK
!= (s
=sys_datacopy(SELF
, src_addr
, who_e
, dst_addr
, len
)))
109 /*===========================================================================*
111 *===========================================================================*/
114 /* Perform the dup(fd) or dup2(fd,fd2) system call. These system calls are
115 * obsolete. In fact, it is not even possible to invoke them using the
116 * current library because the library routines call fcntl(). They are
117 * provided to permit old binary programs to continue to run.
121 register struct filp
*f
;
125 /* Is the file descriptor valid? */
126 rfd
= m_in
.fd
& ~DUP_MASK
; /* kill off dup2 bit, if on */
127 if ((f
= get_filp(rfd
)) == NIL_FILP
) return(err_code
);
129 /* Distinguish between dup and dup2. */
130 if (m_in
.fd
== rfd
) { /* bit not on */
132 if ( (r
= get_fd(0, 0, &m_in
.fd2
, &dummy
)) != OK
) return(r
);
135 if (m_in
.fd2
< 0 || m_in
.fd2
>= OPEN_MAX
) return(EBADF
);
136 if (rfd
== m_in
.fd2
) return(m_in
.fd2
); /* ignore the call: dup2(x, x) */
137 m_in
.fd
= m_in
.fd2
; /* prepare to close fd2 */
138 (void) do_close(); /* cannot fail */
141 /* Success. Set up new file descriptors. */
143 fp
->fp_filp
[m_in
.fd2
] = f
;
144 FD_SET(m_in
.fd2
, &fp
->fp_filp_inuse
);
150 /*===========================================================================*
152 *===========================================================================*/
153 PUBLIC
int do_fcntl()
155 /* Perform the fcntl(fd, request, ...) system call. */
157 register struct filp
*f
;
159 long cloexec_mask
; /* bit map for the FD_CLOEXEC flag */
160 long clo_value
; /* FD_CLOEXEC flag in proper position */
162 struct ftrunc_req req
;
164 /* Is the file descriptor valid? */
165 if ((f
= get_filp(m_in
.fd
)) == NIL_FILP
) {
166 /*printf("VFSfcntl: invalid filedesc %d\n", m_in.fd); */
170 switch (m_in
.request
) {
172 /* This replaces the old dup() system call. */
173 if (m_in
.addr
< 0 || m_in
.addr
>= OPEN_MAX
) return(EINVAL
);
174 if ((r
= get_fd(m_in
.addr
, 0, &new_fd
, &dummy
)) != OK
) return(r
);
176 fp
->fp_filp
[new_fd
] = f
;
180 /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
181 return( FD_ISSET(m_in
.fd
, &fp
->fp_cloexec_set
) ? FD_CLOEXEC
: 0);
184 /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
185 if(m_in
.addr
& FD_CLOEXEC
)
186 FD_SET(m_in
.fd
, &fp
->fp_cloexec_set
);
188 FD_CLR(m_in
.fd
, &fp
->fp_cloexec_set
);
192 /* Get file status flags (O_NONBLOCK and O_APPEND). */
193 fl
= f
->filp_flags
& (O_NONBLOCK
| O_APPEND
| O_ACCMODE
);
197 /* Set file status flags (O_NONBLOCK and O_APPEND). */
198 fl
= O_NONBLOCK
| O_APPEND
;
199 f
->filp_flags
= (f
->filp_flags
& ~fl
) | (m_in
.addr
& fl
);
205 /* Set or clear a file lock. */
206 r
= lock_op(f
, m_in
.request
);
211 /* Free a section of a file. Preparation is done here,
212 * actual freeing in freesp_inode().
215 struct flock flock_arg
;
218 /* Check if it's a regular file. */
219 if((f
->filp_vno
->v_mode
& I_TYPE
) != I_REGULAR
) {
223 /* Copy flock data from userspace. */
224 if((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.name1
,
225 SELF
, (vir_bytes
) &flock_arg
,
226 (phys_bytes
) sizeof(flock_arg
))) != OK
)
229 /* Convert starting offset to signed. */
230 offset
= (signed long) flock_arg
.l_start
;
232 /* Figure out starting position base. */
233 switch(flock_arg
.l_whence
) {
234 case SEEK_SET
: start
= 0; if(offset
< 0) return EINVAL
; break;
236 if (ex64hi(f
->filp_pos
) != 0)
239 "do_fcntl: position in file too high",
242 start
= ex64lo(f
->filp_pos
); break;
243 case SEEK_END
: start
= f
->filp_vno
->v_size
; break;
244 default: return EINVAL
;
247 /* Check for overflow or underflow. */
248 if(offset
> 0 && start
+ offset
< start
) { return EINVAL
; }
249 if(offset
< 0 && start
+ offset
> start
) { return EINVAL
; }
251 if(flock_arg
.l_len
> 0) {
252 end
= start
+ flock_arg
.l_len
;
261 /* Fill in FS request */
262 req
.fs_e
= f
->filp_vno
->v_fs_e
;
263 req
.inode_nr
= f
->filp_vno
->v_inode_nr
;
268 return req_ftrunc(&req
);
277 /*===========================================================================*
279 *===========================================================================*/
283 for (vmp
= &vmnt
[1]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
284 if (vmp
->m_dev
!= NO_DEV
) {
285 /* Send sync request */
286 req_sync(vmp
->m_fs_e
);
292 /*===========================================================================*
294 *===========================================================================*/
295 PUBLIC
int do_fsync()
297 /* Perform the fsync() system call. For now, don't be unnecessarily smart. */
304 /*===========================================================================*
306 *===========================================================================*/
307 PUBLIC
void pm_reboot()
309 /* Perform the FS side of the reboot call. */
314 /* Do exit processing for all leftover processes and servers,
315 * but don't actually exit them (if they were really gone, PM
316 * will tell us about it).
318 for (i
= 0; i
< NR_PROCS
; i
++)
319 if((m_in
.endpt1
= fproc
[i
].fp_endpoint
) != NONE
)
320 free_proc(&fproc
[i
], 0);
322 /* The root file system is mounted onto itself, which keeps it from being
323 * unmounted. Pull an inode out of thin air and put the root on it.
326 put_vnode(vmnt
[0].m_mounted_on
);
327 vmnt
[0].m_mounted_on
= &vdummy
;
328 vmnt
[0].m_root_node
= &vdummy
;
329 vdummy
.v_fs_count
= 0; /* Is this right? */
330 vdummy
.v_ref_count
= 1;
332 /* Unmount all filesystems. File systems are mounted on other file systems,
333 * so you have to pull off the loose bits repeatedly to get it all undone.
335 for (i
= 0; i
< NR_SUPERS
; i
++) {
336 /* Unmount at least one. */
337 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
338 if (vmp
->m_dev
!= NO_DEV
) (void) unmount(vmp
->m_dev
);
343 /*===========================================================================*
345 *===========================================================================*/
346 PUBLIC
void pm_fork(pproc
, cproc
, cpid
)
347 int pproc
; /* Parent process */
348 int cproc
; /* Child process */
349 int cpid
; /* Child process id */
351 /* Perform those aspects of the fork() system call that relate to files.
352 * In particular, let the child inherit its parent's file descriptors.
353 * The parent and child parameters tell who forked off whom. The file
354 * system uses the same slot numbers as the kernel. Only MM makes this call.
357 register struct fproc
*cp
;
358 int i
, parentno
, childno
;
360 /* Check up-to-dateness of fproc. */
361 okendpt(pproc
, &parentno
);
363 /* PM gives child endpoint, which implies process slot information.
364 * Don't call isokendpt, because that will verify if the endpoint
365 * number is correct in fproc, which it won't be.
367 childno
= _ENDPOINT_P(cproc
);
368 if(childno
< 0 || childno
>= NR_PROCS
)
369 panic(__FILE__
, "FS: bogus child for forking", m_in
.child_endpt
);
370 if(fproc
[childno
].fp_pid
!= PID_FREE
)
371 panic(__FILE__
, "FS: forking on top of in-use child", childno
);
373 /* Copy the parent's fproc struct to the child. */
374 fproc
[childno
] = fproc
[parentno
];
376 /* Increase the counters in the 'filp' table. */
377 cp
= &fproc
[childno
];
378 for (i
= 0; i
< OPEN_MAX
; i
++)
379 if (cp
->fp_filp
[i
] != NIL_FILP
) cp
->fp_filp
[i
]->filp_count
++;
381 /* Fill in new process and endpoint id. */
383 cp
->fp_endpoint
= cproc
;
385 /* A forking process never has an outstanding grant,
386 * as it isn't blocking on i/o.
388 assert(!GRANT_VALID(fp
->fp_grant
));
389 assert(!GRANT_VALID(cp
->fp_grant
));
391 /* A child is not a process leader. */
394 /* This child has not exec()ced yet. */
397 /* Record the fact that both root and working dir have another user. */
398 dup_vnode(cp
->fp_rd
);
399 dup_vnode(cp
->fp_wd
);
402 /*===========================================================================*
404 *===========================================================================*/
405 PRIVATE
void free_proc(struct fproc
*exiter
, int flags
)
408 register struct fproc
*rfp
;
409 register struct filp
*rfilp
;
410 register struct vnode
*vp
;
413 fp
= exiter
; /* get_filp() needs 'fp' */
415 if (fp
->fp_suspended
== SUSPENDED
) {
417 if (task
== XPIPE
|| task
== XPOPEN
) susp_count
--;
418 unpause(fp
->fp_endpoint
);
419 fp
->fp_suspended
= NOT_SUSPENDED
;
422 /* Loop on file descriptors, closing any that are open. */
423 for (i
= 0; i
< OPEN_MAX
; i
++) {
424 (void) close_fd(fp
, i
);
427 /* Release root and working directories. */
428 put_vnode(fp
->fp_rd
);
429 put_vnode(fp
->fp_wd
);
430 fp
->fp_rd
= NIL_VNODE
;
431 fp
->fp_wd
= NIL_VNODE
;
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 /* The rest of these actions is only done when processes actually
443 if(!(flags
& FP_EXITING
))
446 /* Invalidate endpoint number for error and sanity checks. */
447 fp
->fp_endpoint
= NONE
;
449 /* If a session leader exits and it has a controlling tty, then revoke
450 * access to its controlling tty from all other processes using it.
452 if (fp
->fp_sesldr
&& fp
->fp_tty
!= 0) {
456 for (rfp
= &fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
457 if(rfp
->fp_pid
== PID_FREE
) continue;
458 if (rfp
->fp_tty
== dev
) rfp
->fp_tty
= 0;
460 for (i
= 0; i
< OPEN_MAX
; i
++) {
461 if ((rfilp
= rfp
->fp_filp
[i
]) == NIL_FILP
) continue;
462 if (rfilp
->filp_mode
== FILP_CLOSED
) continue;
463 vp
= rfilp
->filp_vno
;
464 if ((vp
->v_mode
& I_TYPE
) != I_CHAR_SPECIAL
) continue;
465 if ((dev_t
) vp
->v_sdev
!= dev
) continue;
467 rfilp
->filp_mode
= FILP_CLOSED
;
472 /* Exit done. Mark slot as free. */
473 fp
->fp_pid
= PID_FREE
;
476 /*===========================================================================*
478 *===========================================================================*/
479 PUBLIC
void pm_exit(proc
)
483 /* Perform the file system portion of the exit(status) system call. */
485 /* Nevertheless, pretend that the call came from the user. */
486 okendpt(proc
, &exitee_p
);
487 free_proc(&fproc
[exitee_p
], FP_EXITING
);
490 /*===========================================================================*
492 *===========================================================================*/
493 PUBLIC
void pm_setgid(proc_e
, egid
, rgid
)
498 register struct fproc
*tfp
;
501 okendpt(proc_e
, &slot
);
504 tfp
->fp_effgid
= egid
;
505 tfp
->fp_realgid
= rgid
;
509 /*===========================================================================*
511 *===========================================================================*/
512 PUBLIC
void pm_setuid(proc_e
, euid
, ruid
)
517 register struct fproc
*tfp
;
520 okendpt(proc_e
, &slot
);
523 tfp
->fp_effuid
= euid
;
524 tfp
->fp_realuid
= ruid
;
527 /*===========================================================================*
529 *===========================================================================*/
530 PUBLIC
int do_svrctl()
532 switch (m_in
.svrctl_req
) {
534 /* A server in user space calls in to manage a device. */
535 struct fssignon device
;
536 int r
, major
, proc_nr_n
;
538 if (fp
->fp_effuid
!= SU_UID
&& fp
->fp_effuid
!= SERVERS_UID
)
541 /* Try to copy request structure to FS. */
542 if ((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.svrctl_argp
,
543 FS_PROC_NR
, (vir_bytes
) &device
,
544 (phys_bytes
) sizeof(device
))) != OK
)
547 if (isokendpt(who_e
, &proc_nr_n
) != OK
)
550 /* Try to update device mapping. */
551 major
= (device
.dev
>> MAJOR
) & BYTE
;
552 r
=map_driver(major
, who_e
, device
.style
, 0 /* !force */);
555 /* If a driver has completed its exec(), it can be announced
558 if(fproc
[proc_nr_n
].fp_execced
) {
561 dmap
[major
].dmap_flags
|= DMAP_BABY
;
568 struct fsdevunmap fdu
;
570 /* Try to copy request structure to FS. */
571 if ((r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.svrctl_argp
,
572 FS_PROC_NR
, (vir_bytes
) &fdu
,
573 (phys_bytes
) sizeof(fdu
))) != OK
)
575 major
= (fdu
.dev
>> MAJOR
) & BYTE
;
576 r
=map_driver(major
, NONE
, 0, 0);
584 /*===========================================================================*
586 *===========================================================================*/
587 PUBLIC
int pm_dumpcore(proc_e
, seg_ptr
)
589 struct mem_map
*seg_ptr
;
593 /* Terminate the process */
594 okendpt(proc_e
, &proc_s
);
595 free_proc(&fproc
[proc_s
], FP_EXITING
);