

Please wait until the page is fully downloaded and then press the "Expand" button or the blue line numbers.
0107001 * Special character files also require I/O. The routines for these are here.
0107002 *
0107003 * The entry points in this file are:
0107004 * dev_open: FS opens a device
0107005 * dev_close: FS closes a device
0107006 * dev_io: FS does a read or write on a device
0107007 * gen_opcl: generic call to a task to perform an open/close
0107008 * gen_io: generic call to a task to perform an I/O operation
0107009 * no_dev: open/close processing for devices that don't exist
0107010 * tty_opcl: perform tty-specific processing for open/close
0107011 * ctty_opcl: perform controlling-tty-specific processing for open/close
0107012 * ctty_io: perform controlling-tty-specific processing for I/O
0107013 * do_ioctl: perform the IOCTL system call
0107014 * do_setsid: perform the SETSID system call (FS side)
0107015 */
0107016
0107017 #include "fs.h"
0107018 #include <fcntl.h>
0107019 #include <minix/callnr.h>
0107020 #include <minix/com.h>
0107021 #include "dev.h"
0107022 #include "file.h"
0107023 #include "fproc.h"
0107024 #include "inode.h"
0107025 #include "param.h"
0107026
0107027
0107028 /*===========================================================================*
0107029 * dev_open *
0107030 *===========================================================================*/
0107031 PUBLIC int dev_open(dev, proc, flags)
0107032 dev_t dev; /* device to open */
0107033 int proc; /* process to open for */
0107034 int flags; /* mode bits and flags */
0107035 {
0107036 int major, r;
0107037 struct dmap *dp;
0107038
0107039 /* Determine the major device number call the device class specific
0107040 * open/close routine. (This is the only routine that must check the
0107041 * device number for being in range. All others can trust this check.)
0107042 */
0107043 major = (dev >> MAJOR) & BYTE;
0107044 if (major >= max_major) major = 0;
0107045 dp = &dmap[major];
0107046 r = (*dp->dmap_opcl)(DEV_OPEN, dev, proc, flags);
0107047 if (r == SUSPEND) panic("Suspend on open from", dp->dmap_task);
0107048 return(r);
0107049 }
0107050
0107051
0107052 /*===========================================================================*
0107053 * dev_close *
0107054 *===========================================================================*/
0107055 PUBLIC void dev_close(dev)
0107056 dev_t dev; /* device to close */
0107057 {
0107058 (void) (*dmap[(dev >> MAJOR) & BYTE].dmap_opcl)(DEV_CLOSE, dev, 0, 0);
0107059 }
0107060
0107061
0107062 /*===========================================================================*
0107063 * dev_io *
0107064 *===========================================================================*/
0107065 PUBLIC int dev_io(op, dev, proc, buf, pos, bytes, flags)
0107066 int op; /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
0107067 dev_t dev; /* major-minor device number */
0107068 int proc; /* in whose address space is buf? */
0107069 void *buf; /* virtual address of the buffer */
0107070 off_t pos; /* byte position */
0107071 int bytes; /* how many bytes to transfer */
0107072 int flags; /* special flags, like O_NONBLOCK */
0107073 {
0107074 /* Read or write from a device. The parameter 'dev' tells which one. */
0107075 struct dmap *dp;
0107076 message dev_mess;
0107077
0107078 /* Determine task dmap. */
0107079 dp = &dmap[(dev >> MAJOR) & BYTE];
0107080
0107081 /* Set up the message passed to task. */
0107082 dev_mess.m_type = op;
0107083 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
0107084 dev_mess.POSITION = pos;
0107085 dev_mess.PROC_NR = proc;
0107086 dev_mess.ADDRESS = buf;
0107087 dev_mess.COUNT = bytes;
0107088 dev_mess.TTY_FLAGS = flags;
0107089
0107090 /* Call the task. */
0107091 (*dp->dmap_io)(dp->dmap_task, &dev_mess);
0107092
0107093 /* Task has completed. See if call completed. */
0107094 if (dev_mess.REP_STATUS == SUSPEND) {
0107095 if (flags & O_NONBLOCK) {
0107096 /* Not supposed to block. */
0107097 dev_mess.m_type = CANCEL;
0107098 dev_mess.PROC_NR = proc;
0107099 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
0107100 (*dp->dmap_io)(dp->dmap_task, &dev_mess);
0107101 if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN;
0107102 } else {
0107103 /* Suspend user. */
0107104 suspend(dp->dmap_task);
0107105 }
0107106 }
0107107
0107108 return(dev_mess.REP_STATUS);
0107109 }
0107110
0107111
0107112 /*===========================================================================*
0107113 * gen_opcl *
0107114 *===========================================================================*/
0107115 PUBLIC int gen_opcl(op, dev, proc, flags)
0107116 int op; /* operation, DEV_OPEN or DEV_CLOSE */
0107117 dev_t dev; /* device to open or close */
0107118 int proc; /* process to open/close for */
0107119 int flags; /* mode bits and flags */
0107120 {
0107121 /* Called from the dmap struct in table.c on opens & closes of special files.*/
0107122 struct dmap *dp;
0107123 message dev_mess;
0107124
0107125 /* Determine task dmap. */
0107126 dp = &dmap[(dev >> MAJOR) & BYTE];
0107127
0107128 dev_mess.m_type = op;
0107129 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
0107130 dev_mess.PROC_NR = proc;
0107131 dev_mess.COUNT = flags;
0107132
0107133 /* Call the task. */
0107134 (*dp->dmap_io)(dp->dmap_task, &dev_mess);
0107135
0107136 return(dev_mess.REP_STATUS);
0107137 }
0107138
0107139
0107140 /*===========================================================================*
0107141 * tty_opcl *
0107142 *===========================================================================*/
0107143 PUBLIC int tty_opcl(op, dev, proc, flags)
0107144 int op; /* operation, DEV_OPEN or DEV_CLOSE */
0107145 dev_t dev; /* device to open or close */
0107146 int proc; /* process to open/close for */
0107147 int flags; /* mode bits and flags */
0107148 {
0107149 /* This procedure is called from the dmap struct on tty open/close. */
0107150
0107151 int r;
0107152 register struct fproc *rfp;
0107153
0107154 /* Add O_NOCTTY to the flags if this process is not a session leader, or
0107155 * if it already has a controlling tty, or if it is someone elses
0107156 * controlling tty.
0107157 */
0107158 if (!fp->fp_sesldr || fp->fp_tty != 0) {
0107159 flags |= O_NOCTTY;
0107160 } else {
0107161 for (rfp = &fproc[LOW_USER]; rfp < &fproc[NR_PROCS]; rfp++) {
0107162 if (rfp->fp_tty == dev) flags |= O_NOCTTY;
0107163 }
0107164 }
0107165
0107166 r = gen_opcl(op, dev, proc, flags);
0107167
0107168 /* Did this call make the tty the controlling tty? */
0107169 if (r == 1) {
0107170 fp->fp_tty = dev;
0107171 r = OK;
0107172 }
0107173 return(r);
0107174 }
0107175
0107176
0107177 /*===========================================================================*
0107178 * ctty_opcl *
0107179 *===========================================================================*/
0107180 PUBLIC int ctty_opcl(op, dev, proc, flags)
0107181 int op; /* operation, DEV_OPEN or DEV_CLOSE */
0107182 dev_t dev; /* device to open or close */
0107183 int proc; /* process to open/close for */
0107184 int flags; /* mode bits and flags */
0107185 {
0107186 /* This procedure is called from the dmap struct in table.c on opening/closing
0107187 * /dev/tty, the magic device that translates to the controlling tty.
0107188 */
0107189
0107190 return(fp->fp_tty == 0 ? ENXIO : OK);
0107191 }
0107192
0107193
0107194 /*===========================================================================*
0107195 * do_setsid *
0107196 *===========================================================================*/
0107197 PUBLIC int do_setsid()
0107198 {
0107199 /* Perform the FS side of the SETSID call, i.e. get rid of the controlling
0107200 * terminal of a process, and make the process a session leader.
0107201 */
0107202 register struct fproc *rfp;
0107203
0107204 /* Only MM may do the SETSID call directly. */
0107205 if (who != MM_PROC_NR) return(ENOSYS);
0107206
0107207 /* Make the process a session leader with no controlling tty. */
0107208 rfp = &fproc[slot1];
0107209 rfp->fp_sesldr = TRUE;
0107210 rfp->fp_tty = 0;
0107211 }
0107212
0107213
0107214 /*===========================================================================*
0107215 * do_ioctl *
0107216 *===========================================================================*/
0107217 PUBLIC int do_ioctl()
0107218 {
0107219 /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
0107220
0107221 struct filp *f;
0107222 register struct inode *rip;
0107223 dev_t dev;
0107224
0107225 if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
0107226 rip = f->filp_ino; /* get inode pointer */
0107227 if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL
0107228 && (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
0107229 dev = (dev_t) rip->i_zone[0];
0107230
0107231 #if ENABLE_BINCOMPAT
0107232 if ((m.TTY_REQUEST >> 8) == 't') {
0107233 /* Obsolete sgtty ioctl, message contains more than is sane. */
0107234 struct dmap *dp;
0107235 message dev_mess;
0107236
0107237 dp = &dmap[(dev >> MAJOR) & BYTE];
0107238
0107239 dev_mess = m; /* Copy full message with all the weird bits. */
0107240 dev_mess.m_type = DEV_IOCTL;
0107241 dev_mess.PROC_NR = who;
0107242 dev_mess.TTY_LINE = (dev >> MINOR) & BYTE;
0107243
0107244 /* Call the task. */
0107245 (*dp->dmap_io)(dp->dmap_task, &dev_mess);
0107246
0107247 m1.TTY_SPEK = dev_mess.TTY_SPEK; /* erase and kill */
0107248 m1.TTY_FLAGS = dev_mess.TTY_FLAGS; /* flags */
0107249 return(dev_mess.REP_STATUS);
0107250 }
0107251 #endif
0107252
0107253 return(dev_io(DEV_IOCTL, dev, who, m.ADDRESS, 0L, m.REQUEST, f->filp_flags));
0107254 }
0107255
0107256
0107257 /*===========================================================================*
0107258 * gen_io *
0107259 *===========================================================================*/
0107260 PUBLIC void gen_io(task_nr, mess_ptr)
0107261 int task_nr; /* which task to call */
0107262 message *mess_ptr; /* pointer to message for task */
0107263 {
0107264 /* All file system I/O ultimately comes down to I/O on major/minor device
0107265 * pairs. These lead to calls on the following routines via the dmap table.
0107266 */
0107267
0107268 int r, proc_nr;
0107269 message local_m;
0107270
0107271 proc_nr = mess_ptr->PROC_NR;
0107272
0107273 while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
0107274 /* sendrec() failed to avoid deadlock. The task 'task_nr' is
0107275 * trying to send a REVIVE message for an earlier request.
0107276 * Handle it and go try again.
0107277 */
0107278 if ((r = receive(task_nr, &local_m)) != OK) break;
0107279
0107280 /* If we're trying to send a cancel message to a task which has just
0107281 * sent a completion reply, ignore the reply and abort the cancel
0107282 * request. The caller will do the revive for the process.
0107283 */
0107284 if (mess_ptr->m_type == CANCEL && local_m.REP_PROC_NR == proc_nr)
0107285 return;
0107286
0107287 /* Otherwise it should be a REVIVE. */
0107288 if (local_m.m_type != REVIVE) {
0107289 printf(
0107290 "fs: strange device reply from %d, type = %d, proc = %d\n",
0107291 local_m.m_source,
0107292 local_m.m_type, local_m.REP_PROC_NR);
0107293 continue;
0107294 }
0107295
0107296 revive(local_m.REP_PROC_NR, local_m.REP_STATUS);
0107297 }
0107298
0107299 /* The message received may be a reply to this call, or a REVIVE for some
0107300 * other process.
0107301 */
0107302 for (;;) {
0107303 if (r != OK) panic("call_task: can't send/receive", NO_NUM);
0107304
0107305 /* Did the process we did the sendrec() for get a result? */
0107306 if (mess_ptr->REP_PROC_NR == proc_nr) break;
0107307
0107308 /* Otherwise it should be a REVIVE. */
0107309 if (mess_ptr->m_type != REVIVE) {
0107310 printf(
0107311 "fs: strange device reply from %d, type = %d, proc = %d\n",
0107312 mess_ptr->m_source,
0107313 mess_ptr->m_type, mess_ptr->REP_PROC_NR);
0107314 continue;
0107315 }
0107316 revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
0107317
0107318 r = receive(task_nr, mess_ptr);
0107319 }
0107320 }
0107321
0107322
0107323 /*===========================================================================*
0107324 * ctty_io *
0107325 *===========================================================================*/
0107326 PUBLIC void ctty_io(task_nr, mess_ptr)
0107327 int task_nr; /* not used - for compatibility with dmap_t */
0107328 message *mess_ptr; /* pointer to message for task */
0107329 {
0107330 /* This routine is only called for one device, namely /dev/tty. Its job
0107331 * is to change the message to use the controlling terminal, instead of the
0107332 * major/minor pair for /dev/tty itself.
0107333 */
0107334
0107335 struct dmap *dp;
0107336
0107337 if (fp->fp_tty == 0) {
0107338 /* No controlling tty present anymore, return an I/O error. */
0107339 mess_ptr->REP_STATUS = EIO;
0107340 } else {
0107341 /* Substitute the controlling terminal device. */
0107342 dp = &dmap[(fp->fp_tty >> MAJOR) & BYTE];
0107343 mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE;
0107344 (*dp->dmap_io)(dp->dmap_task, mess_ptr);
0107345 }
0107346 }
0107347
0107348
0107349 /*===========================================================================*
0107350 * no_dev *
0107351 *===========================================================================*/
0107352 PUBLIC int no_dev(op, dev, proc, flags)
0107353 int op; /* operation, DEV_OPEN or DEV_CLOSE */
0107354 dev_t dev; /* device to open or close */
0107355 int proc; /* process to open/close for */
0107356 int flags; /* mode bits and flags */
0107357 {
0107358 /* Called when opening a nonexistent device. */
0107359
0107360 return(ENODEV);
0107361 }
0107362
0107363
0107364 /*===========================================================================*
0107365 * clone_opcl *
0107366 *===========================================================================*/
0107367 PUBLIC int clone_opcl(op, dev, proc, flags)
0107368 int op; /* operation, DEV_OPEN or DEV_CLOSE */
0107369 dev_t dev; /* device to open or close */
0107370 int proc; /* process to open/close for */
0107371 int flags; /* mode bits and flags */
0107372 {
0107373 /* Some devices need special processing upon open. Such a device is "cloned",
0107374 * i.e. on a succesful open it is replaced by a new device with a new unique
0107375 * minor device number. This new device number identifies a new object (such
0107376 * as a new network connection) that has been allocated within a task.
0107377 */
0107378 struct dmap *dp;
0107379 int minor;
0107380 message dev_mess;
0107381
0107382 /* Determine task dmap. */
0107383 dp = &dmap[(dev >> MAJOR) & BYTE];
0107384 minor = (dev >> MINOR) & BYTE;
0107385
0107386 dev_mess.m_type = op;
0107387 dev_mess.DEVICE = minor;
0107388 dev_mess.PROC_NR = proc;
0107389 dev_mess.COUNT = flags;
0107390
0107391 /* Call the task. */
0107392 (*dp->dmap_io)(dp->dmap_task, &dev_mess);
0107393
0107394 if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) {
0107395 if (dev_mess.REP_STATUS != minor) {
0107396 /* A new minor device number has been returned. Create a
0107397 * temporary device file to hold it.
0107398 */
0107399 struct inode *ip;
0107400
0107401 /* Device number of the new device. */
0107402 dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR);
0107403
0107404 ip = alloc_inode(root_dev, ALL_MODES | I_CHAR_SPECIAL);
0107405 if (ip == NIL_INODE) {
0107406 /* Oops, that didn't work. Undo open. */
0107407 (void) clone_opcl(DEV_CLOSE, dev, proc, 0);
0107408 return(err_code);
0107409 }
0107410 ip->i_zone[0] = dev;
0107411
0107412 put_inode(fp->fp_filp[fd]->filp_ino);
0107413 fp->fp_filp[fd]->filp_ino = ip;
0107414 }
0107415 dev_mess.REP_STATUS = OK;
0107416 }
0107417 return(dev_mess.REP_STATUS);
0107418 }