Beispiel #1
0
/*===========================================================================*
 *				do_open					     *
 *===========================================================================*/
static int do_open(devminor_t minor, int access, endpoint_t user_endpt)
{
/* A tty line has been opened.  Make it the callers controlling tty if
 * CDEV_NOCTTY is *not* set and it is not the log device. CDEV_CTTY is returned
 * if the tty is made the controlling tty, otherwise OK or an error code.
 */
  tty_t *tp;
  int r = OK;

  if ((tp = line2tty(minor)) == NULL)
	return ENXIO;

  if (minor == LOG_MINOR && isconsole(tp)) {
	/* The log device is a write-only diagnostics device. */
	if (access & CDEV_R_BIT) return EACCES;
  } else {
	if (!(access & CDEV_NOCTTY)) {
		tp->tty_pgrp = user_endpt;
		r = CDEV_CTTY;
	}
	tp->tty_openct++;
	if (tp->tty_openct == 1) {
		/* Tell the device that the tty is opened */
		(*tp->tty_open)(tp, 0);
	}
  }

  return r;
}
Beispiel #2
0
/*===========================================================================*
 *				do_close				     *
 *===========================================================================*/
static int do_close(devminor_t minor)
{
/* A tty line has been closed.  Clean up the line if it is the last close. */
  tty_t *tp;

  if ((tp = line2tty(minor)) == NULL)
	return ENXIO;

  if ((minor != LOG_MINOR || !isconsole(tp)) && --tp->tty_openct == 0) {
	tp->tty_pgrp = 0;
	tty_icancel(tp);
	(*tp->tty_ocancel)(tp, 0);
	(*tp->tty_close)(tp, 0);
	tp->tty_termios = termios_defaults;
	tp->tty_winsize = winsize_defaults;
	setattr(tp);
  }

  return OK;
}
Beispiel #3
0
/*===========================================================================*
 *				do_int					     *
 *===========================================================================*/
PRIVATE void do_int()
{
    /* The TTY task can generate two kinds of interrupts:
     *	- a character has been received from the console or an RS232 line.
     *	- an RS232 line has completed a write request (on behalf of a user).
     * The interrupt handler may delay the interrupt message at its discretion
     * to avoid swamping the TTY task.  Messages may be overwritten when the
     * lines are fast or when there are races between different lines, input
     * and output, because MINIX only provides single buffering for interrupt
     * messages (in proc.c).  This is handled by explicitly checking each line
     * for fresh input and completed output on each interrupt.  Input is given
     * priority so signal characters are not delayed by lots of small output
     * requests.  This does not signifigantly delay the detection of output
     * completions, since TTY will be scheduled to handle the output before
     * any new user can request input.
     *
     * If a reply is sent (to FS), further input/output must not be processed
     * for fear of sending a second message to FS, which would be lost under
     * certain race conditions.  E.g. when FS is now ready and is about to
     * sendrec() to TTY (usually from rw_dev()).  FS handles the deadlock
     * resulting from the _first_ send() from TTY clashing with the sendrec()
     * from FS.  But then the scheduling causes the retried sendrec() to get
     * through, so the second send() fails with an E_LOCKED error.  This might
     * be avoided by preempting tasks like TTY over servers like FS, or giving
     * preference to senders over receivers.  In practice, TTY relies on being
     * woken at a later clock tick.
     */

    char *buf;
    static struct tty_struct *last_tp = FIRST_TTY;  /* round-robin service */
    unsigned char odone;
    register char *rbuf;
    unsigned remaining;
    register struct tty_struct *tp;
    unsigned wrapcount;

    tp = last_tp;
    do {
        if (++tp >= END_TTY) tp = FIRST_TTY;

        /* Transfer any fresh input to TTY's buffer, and test output done. */
        remaining = (*tp->tty_devread)(tp->tty_line, &buf, &odone);
        if (remaining == 0)
            goto check_output;	/* avoid even uglier indentation */

        rbuf = buf;
        if (!isconsole(tp) && tp->tty_mode & RAW) {
            /* Avoid grotesquely inefficient in_char(), except for console
             * which needs further translation.
             * Line feeds need not be counted.
             */

            /* If queue becomes too full, ask external device to stop. */
            if (tp->tty_incount < tp->tty_ihighwater &&
                    tp->tty_incount + remaining >= tp->tty_ihighwater)
                rs_istop(tp->tty_line);

            if (remaining > tp->tty_insize - tp->tty_incount)
                /* not all fit, discard */
                remaining = tp->tty_insize - tp->tty_incount;
            wrapcount = tp->tty_inbufend - tp->tty_inhead;
            if (wrapcount < remaining) {
                memcpy(tp->tty_inhead, rbuf, wrapcount);
                tp->tty_inhead = tp->tty_inbuf;
                rbuf += wrapcount;
                tp->tty_incount += wrapcount;
                remaining -= wrapcount;
            }
            memcpy(tp->tty_inhead, rbuf, remaining);
            tp->tty_inhead += remaining;
            tp->tty_incount += remaining;
        } else {
            do
                in_char(tp, *rbuf++);
            while (--remaining != 0);
        }

        /* Possibly restart output (in case there were xoffs or echoes). */
        (*tp->tty_devstart)(tp);

        /* See if a previously blocked reader can now be satisfied. */
        if (tp->tty_inleft != 0 && tp->tty_incount != 0 &&
                (tp->tty_mode & (RAW | CBREAK) || tp->tty_lfct != 0)) {
            /* Tell hanging reader that chars have arrived. */
            tty_reply(REVIVE, (int) tp->tty_incaller,
                      (int) tp->tty_inproc, rd_chars(tp));
        }

check_output:
        /* maybe continue output */
        if (isconsole(tp) && tp->tty_outleft > 0)
            (*tp->tty_devstart)(tp);
        /* Finish off any completed block of output. */
        if (odone) {
            if (tp->tty_rwords > 0) {
                /* not echo */
                tp->tty_phys += tp->tty_rwords;
                tp->tty_cum += tp->tty_rwords;
                tp->tty_outleft -= tp->tty_rwords;
                if (tp->tty_outleft == 0) {
                    finish(tp, tp->tty_cum);
                    continue;
                }
            }
            tp->tty_rwords = 0;
            rs_ocancel(tp->tty_line);	/* tty_ocancel does too much*/
            (*tp->tty_devstart)(tp);	/* maybe continue output */
        }
    }
    while (tp != last_tp || tty_events >= EVENT_THRESHOLD);
    tty_awake = FALSE;
    last_tp = tp;
}
Beispiel #4
0
/*===========================================================================*
 *				do_ioctl				     *
 *===========================================================================*/
static int do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
	cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id)
{
/* Perform an IOCTL on this terminal. POSIX termios calls are handled
 * by the IOCTL system call.
 */
  kio_bell_t bell;
  clock_t ticks;
  tty_t *tp;
  int i, r;

  if ((tp = line2tty(minor)) == NULL)
	return ENXIO;

  r = OK;
  switch (request) {
    case TIOCGETA:
	/* Get the termios attributes. */
	r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_termios,
		sizeof(struct termios));
	break;

    case TIOCSETAW:
    case TIOCSETAF:
    case TIOCDRAIN:
	if (tp->tty_outleft > 0) {
		if (flags & CDEV_NONBLOCK)
			return EAGAIN;
		/* Wait for all ongoing output processing to finish. */
		tp->tty_iocaller = endpt;
		tp->tty_ioid = id;
		tp->tty_ioreq = request;
		tp->tty_iogrant = grant;
		return EDONTREPLY;	/* suspend the caller */
	}
	if (request == TIOCDRAIN) break;
	if (request == TIOCSETAF) tty_icancel(tp);
	/*FALL THROUGH*/
    case TIOCSETA:
	/* Set the termios attributes. */
	r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_termios,
		sizeof(struct termios));
	if (r != OK) break;
	setattr(tp);
	break;

    case TIOCFLUSH:
	r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i, sizeof(i));
	if (r != OK) break;
	if(i & FREAD) {	tty_icancel(tp); }
	if(i & FWRITE) { (*tp->tty_ocancel)(tp, 0); }
	break;
    case TIOCSTART:
	tp->tty_inhibited = 0;
	tp->tty_events = 1;
	break;
    case TIOCSTOP:
	tp->tty_inhibited = 1;
	tp->tty_events = 1;
	break;
    case TIOCSBRK:	/* tcsendbreak - turn break on */
	if (tp->tty_break_on != NULL) (*tp->tty_break_on)(tp,0);
	break;
    case TIOCCBRK:	/* tcsendbreak - turn break off */
	if (tp->tty_break_off != NULL) (*tp->tty_break_off)(tp,0);
	break;

    case TIOCGWINSZ:
	r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &tp->tty_winsize,
		sizeof(struct winsize));
	break;

    case TIOCSWINSZ:
	r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &tp->tty_winsize,
		sizeof(struct winsize));
	sigchar(tp, SIGWINCH, 0);
	break;
    case KIOCBELL:
	/* Sound bell (only /dev/console). */
	if (!isconsole(tp))
		break;
	r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &bell, sizeof(bell));
	if (r != OK)
		break;
	ticks = bell.kb_duration.tv_usec * system_hz / 1000000;
	ticks += bell.kb_duration.tv_sec * system_hz;
	if (!ticks)
		ticks++;
	beep_x(bell.kb_pitch, ticks);
	break;
    case TIOCGETD:	/* get line discipline */
	i = TTYDISC;
	r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &i, sizeof(i));
	break;
    case TIOCSETD:	/* set line discipline */
	printf("TTY: TIOCSETD: can't set any other line discipline.\n");
	r = ENOTTY;
	break;
    case TIOCGLINED:	/* get line discipline as string */
	r = sys_safecopyto(endpt, grant, 0, (vir_bytes) lined, sizeof(lined));
	break;
    case TIOCGQSIZE:	/* get input/output queue sizes */
	i = TTY_IN_BYTES;	/* best we can do.. */
	r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &i, sizeof(i));
	break;
    case KIOCSMAP:
	/* Load a new keymap (only /dev/console). */
	if (isconsole(tp)) r = kbd_loadmap(endpt, grant);
	break;

    case TIOCSFON:
	/* Load a font into an EGA or VGA card ([email protected]) */
	if (isconsole(tp)) r = con_loadfont(endpt, grant);
	break;

    case TIOCSCTTY:
	/* Process sets this tty as its controlling tty */
	tp->tty_pgrp = user_endpt;
	break;
	
/* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is 
 * not defined.
 */
    case TIOCGPGRP:     
    case TIOCSPGRP:	
    default:
	r = ENOTTY;
  }

  return r;
}
/*
 *	Find out the _real_ console. Assume that stdin is connected to
 *	the console device (/dev/console).
 */
int consolename(char *res, int rlen)
{
#ifdef TIOCGDEV
	unsigned int	kdev;
#endif
	struct stat	st, st2;
	char		buf[256];
	char		*p;
	int		didmount = 0;
	int		n, r;
	int		fd;

	fstat(0, &st);
	if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) {
		/*
		 *	Old kernel, can find real device easily.
		 */
		int r = findtty(res, "/dev", rlen, st.st_rdev);
		if (0 != r)
			fprintf(stderr, "bootlogd: cannot find console device "
				"%d:%d under /dev\n", major(st.st_rdev), minor(st.st_rdev));
		return r;
	}

#ifdef TIOCGDEV
# ifndef  ENOIOCTLCMD
#  define ENOIOCTLCMD	515
# endif
	if (ioctl(0, TIOCGDEV, &kdev) == 0) {
		int r = findtty(res, "/dev", rlen, (dev_t)kdev);
		if (0 != r)
			fprintf(stderr, "bootlogd: cannot find console device "
				"%d:%d under /dev\n", major(kdev), minor(kdev));
		return r;
	}
	if (errno != ENOIOCTLCMD) return -1;
#endif

#ifdef __linux__
	/*
	 *	Read /proc/cmdline.
	 */
	stat("/", &st);
	if (stat("/proc", &st2) < 0) {
		perror("bootlogd: /proc");
		return -1;
	}
	if (st.st_dev == st2.st_dev) {
		if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
			perror("bootlogd: mount /proc");
			return -1;
		}
		didmount = 1;
	}

	n = 0;
	r = -1;
	if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
		perror("bootlogd: /proc/cmdline");
	} else {
		buf[0] = 0;
		if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0)
			r = 0;
		else
			perror("bootlogd: /proc/cmdline");
		close(fd);
	}
	if (didmount) umount("/proc");

	if (r < 0) return r;

	/*
	 *	OK, so find console= in /proc/cmdline.
	 *	Parse in reverse, opening as we go.
	 */
	p = buf + n;
	*p-- = 0;
	r = -1;
	while (p >= buf) {
		if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
			*p-- = 0;
			continue;
		}
		if (strncmp(p, "console=", 8) == 0 &&
		    isconsole(p + 8, res, rlen)) {
			r = 0;
			break;
		}
		p--;
	}

	if (r == 0) return r;
#endif

	/*
	 *	Okay, no console on the command line -
	 *	guess the default console.
	 */
	for (n = 0; defcons[n]; n++)
		if (isconsole(defcons[n], res, rlen))
			return 0;

	fprintf(stderr, "bootlogd: cannot deduce real console device\n");

	return -1;
}