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.
4 *
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_fork: adjust the tables after MM has performed a FORK system call
10 * do_exec: handle files with FD_CLOEXEC on after MM has done an EXEC
11 * do_exit: a process has exited; note that in the tables
12 * do_set: set uid or gid for some process
13 * do_revive: revive a process that was waiting for something (e.g. TTY)
14 */
15
16 #include "fs.h"
17 #include <fcntl.h>
18 #include <unistd.h> /* cc runs out of memory with unistd.h :-( */
19 #include <minix/callnr.h>
20 #include <minix/com.h>
21 #include <minix/boot.h>
22 #include "buf.h"
23 #include "file.h"
24 #include "fproc.h"
25 #include "inode.h"
26 #include "dev.h"
27 #include "param.h"
28
29
30 /*===========================================================================*
31 * do_dup *
32 *===========================================================================*/
33 PUBLIC int do_dup()
34 {
35 /* Perform the dup(fd) or dup2(fd,fd2) system call. These system calls are
36 * obsolete. In fact, it is not even possible to invoke them using the
37 * current library because the library routines call fcntl(). They are
38 * provided to permit old binary programs to continue to run.
39 */
40
41 register int rfd;
42 register struct filp *f;
43 struct filp *dummy;
44 int r;
45
46 /* Is the file descriptor valid? */
47 rfd = fd & ~DUP_MASK; /* kill off dup2 bit, if on */
48 if ((f = get_filp(rfd)) == NIL_FILP) return(err_code);
49
50 /* Distinguish between dup and dup2. */
51 if (fd == rfd) { /* bit not on */
52 /* dup(fd) */
53 if ( (r = get_fd(0, 0, &fd2, &dummy)) != OK) return(r);
54 } else {
55 /* dup2(fd, fd2) */
56 if (fd2 < 0 || fd2 >= OPEN_MAX) return(EBADF);
57 if (rfd == fd2) return(fd2); /* ignore the call: dup2(x, x) */
58 fd = fd2; /* prepare to close fd2 */
59 (void) do_close(); /* cannot fail */
60 }
61
62 /* Success. Set up new file descriptors. */
63 f->filp_count++;
64 fp->fp_filp[fd2] = f;
65 return(fd2);
66 }
67
68 /*===========================================================================*
69 * do_fcntl *
70 *===========================================================================*/
71 PUBLIC int do_fcntl()
72 {
73 /* Perform the fcntl(fd, request, ...) system call. */
74
75 register struct filp *f;
76 int new_fd, r, fl;
77 long cloexec_mask; /* bit map for the FD_CLOEXEC flag */
78 long clo_value; /* FD_CLOEXEC flag in proper position */
79 struct filp *dummy;
80
81 /* Is the file descriptor valid? */
82 if ((f = get_filp(fd)) == NIL_FILP) return(err_code);
83
84 switch (request) {
85 case F_DUPFD:
86 /* This replaces the old dup() system call. */
87 if (addr < 0 || addr >= OPEN_MAX) return(EINVAL);
88 if ((r = get_fd(addr, 0, &new_fd, &dummy)) != OK) return(r);
89 f->filp_count++;
90 fp->fp_filp[new_fd] = f;
91 return(new_fd);
92
93 case F_GETFD:
94 /* Get close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
95 return( ((fp->fp_cloexec >> fd) & 01) ? FD_CLOEXEC : 0);
96
97 case F_SETFD:
98 /* Set close-on-exec flag (FD_CLOEXEC in POSIX Table 6-2). */
99 cloexec_mask = 1L << fd; /* singleton set position ok */
100 clo_value = (addr & FD_CLOEXEC ? cloexec_mask : 0L);
101 fp->fp_cloexec = (fp->fp_cloexec & ~cloexec_mask) | clo_value;
102 return(OK);
103
104 case F_GETFL:
105 /* Get file status flags (O_NONBLOCK and O_APPEND). */
106 fl = f->filp_flags & (O_NONBLOCK | O_APPEND | O_ACCMODE);
107 return(fl);
108
109 case F_SETFL:
110 /* Set file status flags (O_NONBLOCK and O_APPEND). */
111 fl = O_NONBLOCK | O_APPEND;
112 f->filp_flags = (f->filp_flags & ~fl) | (addr & fl);
113 return(OK);
114
115 case F_GETLK:
116 case F_SETLK:
117 case F_SETLKW:
118 /* Set or clear a file lock. */
119 r = lock_op(f, request);
120 return(r);
121
122 default:
123 return(EINVAL);
124 }
125 }
126
127
128 /*===========================================================================*
129 * do_sync *
130 *===========================================================================*/
131 PUBLIC int do_sync()
132 {
133 /* Perform the sync() system call. Flush all the tables. */
134
135 register struct inode *rip;
136 register struct buf *bp;
137
138 /* The order in which the various tables are flushed is critical. The
139 * blocks must be flushed last, since rw_inode() leaves its results in
140 * the block cache.
141 */
142
143 /* Write all the dirty inodes to the disk. */
144 for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++)
145 if (rip->i_count > 0 && rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
146
147 /* Write all the dirty blocks to the disk, one drive at a time. */
148 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
149 if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev);
150
151 return(OK); /* sync() can't fail */
152 }
153
154
155 /*===========================================================================*
156 * do_fork *
157 *===========================================================================*/
158 PUBLIC int do_fork()
159 {
160 /* Perform those aspects of the fork() system call that relate to files.
161 * In particular, let the child inherit its parent's file descriptors.
162 * The parent and child parameters tell who forked off whom. The file
163 * system uses the same slot numbers as the kernel. Only MM makes this call.
164 */
165
166 register struct fproc *cp;
167 int i;
168
169 /* Only MM may make this call directly. */
170 if (who != MM_PROC_NR) return(EGENERIC);
171
172 /* Copy the parent's fproc struct to the child. */
173 fproc[child] = fproc[parent];
174
175 /* Increase the counters in the 'filp' table. */
176 cp = &fproc[child];
177 for (i = 0; i < OPEN_MAX; i++)
178 if (cp->fp_filp[i] != NIL_FILP) cp->fp_filp[i]->filp_count++;
179
180 /* Fill in new process id. */
181 cp->fp_pid = pid;
182
183 /* A child is not a process leader. */
184 cp->fp_sesldr = 0;
185
186 /* Record the fact that both root and working dir have another user. */
187 dup_inode(cp->fp_rootdir);
188 dup_inode(cp->fp_workdir);
189 return(OK);
190 }
191
192
193 /*===========================================================================*
194 * do_exec *
195 *===========================================================================*/
196 PUBLIC int do_exec()
197 {
198 /* Files can be marked with the FD_CLOEXEC bit (in fp->fp_cloexec). When
199 * MM does an EXEC, it calls FS to allow FS to find these files and close them.
200 */
201
202 register int i;
203 long bitmap;
204
205 /* Only MM may make this call directly. */
206 if (who != MM_PROC_NR) return(EGENERIC);
207
208 /* The array of FD_CLOEXEC bits is in the fp_cloexec bit map. */
209 fp = &fproc[slot1]; /* get_filp() needs 'fp' */
210 bitmap = fp->fp_cloexec;
211 if (bitmap == 0) return(OK); /* normal case, no FD_CLOEXECs */
212
213 /* Check the file desriptors one by one for presence of FD_CLOEXEC. */
214 for (i = 0; i < OPEN_MAX; i++) {
215 fd = i;
216 if ( (bitmap >> i) & 01) (void) do_close();
217 }
218
219 return(OK);
220 }
221
222
223 /*===========================================================================*
224 * do_exit *
225 *===========================================================================*/
226 PUBLIC int do_exit()
227 {
228 /* Perform the file system portion of the exit(status) system call. */
229
230 register int i, exitee, task;
231 register struct fproc *rfp;
232 register struct filp *rfilp;
233 register struct inode *rip;
234 int major;
235 dev_t dev;
236 message dev_mess;
237
238 /* Only MM may do the EXIT call directly. */
239 if (who != MM_PROC_NR) return(EGENERIC);
240
241 /* Nevertheless, pretend that the call came from the user. */
242 fp = &fproc[slot1]; /* get_filp() needs 'fp' */
243 exitee = slot1;
244
245 if (fp->fp_suspended == SUSPENDED) {
246 task = -fp->fp_task;
247 if (task == XPIPE || task == XPOPEN) susp_count--;
248 pro = exitee;
249 (void) do_unpause(); /* this always succeeds for MM */
250 fp->fp_suspended = NOT_SUSPENDED;
251 }
252
253 /* Loop on file descriptors, closing any that are open. */
254 for (i = 0; i < OPEN_MAX; i++) {
255 fd = i;
256 (void) do_close();
257 }
258
259 /* Release root and working directories. */
260 put_inode(fp->fp_rootdir);
261 put_inode(fp->fp_workdir);
262 fp->fp_rootdir = NIL_INODE;
263 fp->fp_workdir = NIL_INODE;
264
265 /* If a session leader exits then revoke access to its controlling tty from
266 * all other processes using it.
267 */
268 if (!fp->fp_sesldr) return(OK); /* not a session leader */
269 fp->fp_sesldr = FALSE;
270 if (fp->fp_tty == 0) return(OK); /* no controlling tty */
271 dev = fp->fp_tty;
272
273 for (rfp = &fproc[LOW_USER]; rfp < &fproc[NR_PROCS]; rfp++) {
274 if (rfp->fp_tty == dev) rfp->fp_tty = 0;
275
276 for (i = 0; i < OPEN_MAX; i++) {
277 if ((rfilp = rfp->fp_filp[i]) == NIL_FILP) continue;
278 if (rfilp->filp_mode == FILP_CLOSED) continue;
279 rip = rfilp->filp_ino;
280 if ((rip->i_mode & I_TYPE) != I_CHAR_SPECIAL) continue;
281 if ((dev_t) rip->i_zone[0] != dev) continue;
282 dev_mess.m_type = DEV_CLOSE;
283 dev_mess.DEVICE = dev;
284 major = (dev >> MAJOR) & BYTE; /* major device nr */
285 task = dmap[major].dmap_task; /* device task nr */
286 (*dmap[major].dmap_close)(task, &dev_mess);
287 rfilp->filp_mode = FILP_CLOSED;
288 }
289 }
290 return(OK);
291 }
292
293
294 /*===========================================================================*
295 * do_set *
296 *===========================================================================*/
297 PUBLIC int do_set()
298 {
299 /* Set uid_t or gid_t field. */
300
301 register struct fproc *tfp;
302
303 /* Only MM may make this call directly. */
304 if (who != MM_PROC_NR) return(EGENERIC);
305
306 tfp = &fproc[slot1];
307 if (fs_call == SETUID) {
308 tfp->fp_realuid = (uid_t) real_user_id;
309 tfp->fp_effuid = (uid_t) eff_user_id;
310 }
311 if (fs_call == SETGID) {
312 tfp->fp_effgid = (gid_t) eff_grp_id;
313 tfp->fp_realgid = (gid_t) real_grp_id;
314 }
315 return(OK);
316 }
317
318
319 /*===========================================================================*
320 * do_revive *
321 *===========================================================================*/
322 PUBLIC int do_revive()
323 {
324 /* A task, typically TTY, has now gotten the characters that were needed for a
325 * previous read. The process did not get a reply when it made the call.
326 * Instead it was suspended. Now we can send the reply to wake it up. This
327 * business has to be done carefully, since the incoming message is from
328 * a task (to which no reply can be sent), and the reply must go to a process
329 * that blocked earlier. The reply to the caller is inhibited by setting the
330 * 'dont_reply' flag, and the reply to the blocked process is done explicitly
331 * in revive().
332 */
333
334 #if !ALLOW_USER_SEND
335 if (who >= LOW_USER) return(EPERM);
336 #endif
337
338 revive(m.REP_PROC_NR, m.REP_STATUS);
339 dont_reply = TRUE; /* don't reply to the TTY task */
340 return(OK);
341 }
342
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.