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  *===========================================================================*/
"opcl" stands for "op"en, "cl"ose.


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 }