vm: remove leftover diag print
[minix.git] / servers / vfs / misc.c
blob6d3c25fab4503cc491b40ce43827fa0552ceb5e6
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
21 #include "fs.h"
22 #include <fcntl.h>
23 #include <assert.h>
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>
32 #include "file.h"
33 #include "fproc.h"
34 #include "param.h"
35 #include <minix/vfsif.h>
36 #include "vnode.h"
37 #include "vmnt.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];
44 #endif
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) );
56 #define FP_EXITING 1
59 /*===========================================================================*
60 * do_getsysinfo *
61 *===========================================================================*/
62 PUBLIC int do_getsysinfo()
64 struct fproc *proc_addr;
65 vir_bytes src_addr, dst_addr;
66 size_t len;
67 int s;
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) {
76 case SI_PROC_ADDR:
77 proc_addr = &fproc[0];
78 src_addr = (vir_bytes) &proc_addr;
79 len = sizeof(struct fproc *);
80 break;
81 case SI_PROC_TAB:
82 src_addr = (vir_bytes) fproc;
83 len = sizeof(struct fproc) * NR_PROCS;
84 break;
85 case SI_DMAP_TAB:
86 src_addr = (vir_bytes) dmap;
87 len = sizeof(struct dmap) * NR_DEVICES;
88 break;
89 #if ENABLE_SYSCALL_STATS
90 case SI_CALL_STATS:
91 src_addr = (vir_bytes) calls_stats;
92 len = sizeof(calls_stats);
93 break;
94 #endif
95 default:
96 return(EINVAL);
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);
101 return(OK);
105 /*===========================================================================*
106 * do_dup *
107 *===========================================================================*/
108 PUBLIC int do_dup()
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.
116 register int rfd;
117 register struct filp *f;
118 struct filp *dummy;
119 int r;
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 */
127 /* dup(fd) */
128 if ((r = get_fd(0, 0, &m_in.fd2, &dummy)) != OK) return(r);
129 } else {
130 /* dup2(fd, fd2) */
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. */
138 f->filp_count++;
139 fp->fp_filp[m_in.fd2] = f;
140 FD_SET(m_in.fd2, &fp->fp_filp_inuse);
141 return(m_in.fd2);
145 /*===========================================================================*
146 * do_fcntl *
147 *===========================================================================*/
148 PUBLIC int do_fcntl()
150 /* Perform the fcntl(fd, request, ...) system call. */
152 register struct filp *f;
153 int new_fd, r, fl;
154 struct filp *dummy;
156 /* Is the file descriptor valid? */
157 if ((f = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
159 switch (m_in.request) {
160 case F_DUPFD:
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);
164 f->filp_count++;
165 fp->fp_filp[new_fd] = f;
166 return(new_fd);
168 case F_GETFD:
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);
172 case F_SETFD:
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);
176 else
177 FD_CLR(m_in.fd, &fp->fp_cloexec_set);
178 return(OK);
180 case F_GETFL:
181 /* Get file status flags (O_NONBLOCK and O_APPEND). */
182 fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE);
183 return(fl);
185 case F_SETFL:
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);
189 return(OK);
191 case F_GETLK:
192 case F_SETLK:
193 case F_SETLKW:
194 /* Set or clear a file lock. */
195 r = lock_op(f, m_in.request);
196 return(r);
198 case F_FREESP:
200 /* Free a section of a file. Preparation is done here, actual freeing
201 * in freesp_inode().
203 off_t start, end;
204 struct flock flock_arg;
205 signed long offset;
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)
214 return(r);
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;
222 case SEEK_CUR:
223 if (ex64hi(f->filp_pos) != 0)
224 panic("do_fcntl: position in file too high");
225 start = ex64lo(f->filp_pos);
226 break;
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;
234 start += offset;
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;
242 } else {
243 end = 0;
246 r = req_ftrunc(f->filp_vno->v_fs_e, f->filp_vno->v_inode_nr, start,
247 end);
249 if(r == OK && flock_arg.l_len == 0)
250 f->filp_vno->v_size = start;
252 return(r);
255 default:
256 return(EINVAL);
261 /*===========================================================================*
262 * do_sync *
263 *===========================================================================*/
264 PUBLIC int do_sync()
266 struct vmnt *vmp;
267 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
268 if (vmp->m_dev != NO_DEV)
269 req_sync(vmp->m_fs_e);
271 return(OK);
274 /*===========================================================================*
275 * do_fsync *
276 *===========================================================================*/
277 PUBLIC int do_fsync()
279 /* Perform the fsync() system call. For now, don't be unnecessarily smart. */
281 do_sync();
282 return(OK);
285 /*===========================================================================*
286 * unmount_all *
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.
294 int i;
295 for (i= 0; i < NR_MNTS; i++) {
296 struct vmnt *vmp;
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 /*===========================================================================*
307 * pm_reboot *
308 *===========================================================================*/
309 PUBLIC void pm_reboot()
311 /* Perform the FS side of the reboot call. */
312 int i;
314 do_sync();
316 SANITYCHECK;
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)
327 * future.
329 free_proc(&fproc[i], 0);
331 SANITYCHECK;
333 unmount_all();
335 SANITYCHECK;
339 /*===========================================================================*
340 * pm_fork *
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. */
380 cp->fp_pid = cpid;
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. */
396 cp->fp_sesldr = 0;
398 /* This child has not exec()ced yet. */
399 cp->fp_execced = 0;
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 /*===========================================================================*
407 * free_proc *
408 *===========================================================================*/
409 PRIVATE void free_proc(struct fproc *exiter, int flags)
411 int i;
412 register struct fproc *rfp;
413 register struct filp *rfilp;
414 register struct vnode *vp;
415 dev_t dev;
417 SANITYCHECK;
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)) {
426 SANITYCHECK;
427 unpause(fp->fp_endpoint);
428 SANITYCHECK;
431 SANITYCHECK;
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
450 * exit.
452 if(!(flags & FP_EXITING)) {
453 SANITYCHECK;
454 return;
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) {
465 dev = fp->fp_tty;
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;
489 SANITYCHECK;
492 /*===========================================================================*
493 * pm_exit *
494 *===========================================================================*/
495 PUBLIC void pm_exit(proc)
496 int proc;
498 int exitee_p;
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 /*===========================================================================*
507 * pm_setgid *
508 *===========================================================================*/
509 PUBLIC void pm_setgid(proc_e, egid, rgid)
510 int proc_e;
511 int egid;
512 int rgid;
514 register struct fproc *tfp;
515 int slot;
517 okendpt(proc_e, &slot);
518 tfp = &fproc[slot];
520 tfp->fp_effgid = egid;
521 tfp->fp_realgid = rgid;
525 /*===========================================================================*
526 * pm_setgroups *
527 *===========================================================================*/
528 PUBLIC void pm_setgroups(proc_e, ngroups, groups)
529 int proc_e;
530 int ngroups;
531 gid_t *groups;
533 struct fproc *rfp;
534 int slot;
536 okendpt(proc_e, &slot);
537 rfp = &fproc[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;
543 } else
544 panic("VFS: pm_setgroups: datacopy failed");
548 /*===========================================================================*
549 * pm_setuid *
550 *===========================================================================*/
551 PUBLIC void pm_setuid(proc_e, euid, ruid)
552 int proc_e;
553 int euid;
554 int ruid;
556 register struct fproc *tfp;
557 int slot;
559 okendpt(proc_e, &slot);
560 tfp = &fproc[slot];
562 tfp->fp_effuid = euid;
563 tfp->fp_realuid = ruid;
566 /*===========================================================================*
567 * do_svrctl *
568 *===========================================================================*/
569 PUBLIC int do_svrctl()
571 switch (m_in.svrctl_req) {
572 /* No control request implemented yet. */
573 default:
574 return(EINVAL);
578 /*===========================================================================*
579 * pm_dumpcore *
580 *===========================================================================*/
581 PUBLIC int pm_dumpcore(proc_e, seg_ptr)
582 int proc_e;
583 struct mem_map *seg_ptr;
585 int proc_s;
587 /* Terminate the process */
588 okendpt(proc_e, &proc_s);
589 free_proc(&fproc[proc_s], FP_EXITING);
591 return OK;
594 /*===========================================================================*
595 * ds_event *
596 *===========================================================================*/
597 PUBLIC void ds_event()
599 char key[DS_MAX_KEYLEN];
600 char *driver_prefix = "drv.vfs.";
601 u32_t value;
602 int type;
603 endpoint_t owner_endpoint;
604 int r;
606 /* Get the event and the owner from DS. */
607 r = ds_check(key, &type, &owner_endpoint);
608 if(r != OK) {
609 if(r != ENOENT)
610 printf("vfs: ds_event: ds_check failed: %d\n", r);
611 return;
613 r = ds_retrieve_u32(key, &value);
614 if(r != OK) {
615 printf("vfs: ds_event: ds_retrieve_u32 failed\n");
616 return;
619 /* Only check for VFS driver up events. */
620 if(strncmp(key, driver_prefix, sizeof(driver_prefix))
621 || value != DS_DRIVER_UP) {
622 return;
625 /* Perform up. */
626 dmap_endpt_up(owner_endpoint);