Exemple #1
0
/*
 * Process a write call on a tty device.
 */
static int
tty_write(file_t file, char *buf, size_t *nbyte, int blkno)
{
	struct tty *tp = file->priv;
	size_t remain, count = 0;
	unsigned char c;	/* must be char (not int) for BIG ENDIAN */

	DPRINTF(("tty_write\n"));

	remain = *nbyte;
	while (remain > 0) {
		if (tp->t_outq.tq_count > TTYQ_HIWAT) {
			tty_start(tp);
			if (tp->t_outq.tq_count <= TTYQ_HIWAT)
				continue;
			tp->t_state |= TS_ASLEEP;
			sched_sleep(&tp->t_output);
			continue;
		}
		if (umem_copyin(buf, &c, 1))
			return EFAULT;
		tty_output(c, tp);
		buf++;
		remain--;
		count++;
	}
	tty_start(tp);
	*nbyte = count;
	return 0;
}
Exemple #2
0
static void watcher(void *arg, int fd, int events)
{
	int len = 0;
	char buf[EVENT_SIZE], name[42];
	tty_node_t *entry;
	struct inotify_event *notified = (struct inotify_event *)buf;

	while ((len = read(fd, buf, sizeof(buf)))) {
		if (-1 == len) {
			if (errno == EINVAL)
				setup();
			if (errno == EINTR)
				continue;

			break;	/* Likely EAGAIN */
		}

		snprintf(name, sizeof(name), "/dev/%s", notified->name);
		entry = tty_find(name);
		if (entry && tty_enabled(&entry->data)) {
			if (notified->mask & IN_CREATE)
				tty_start(&entry->data);
			else if (entry->data.pid)
				tty_stop(&entry->data);
		}
	}
}
Exemple #3
0
/*
 * Process a write call on a tty device.
 */
int tty_write(struct tty *tp, struct uio *uio, size_t *size)
{
  u_char c;

  DPRINTF(TTYDB_CORE, ("tty_write\n"));

  size_t total = 0;
  for (int i = 0; i < uio->iovcnt; ++i) {
    size_t count = 0;
    char *buf = uio->iov[i].iov_base;
    size_t nbyte = uio->iov[i].iov_len;
    while (nbyte > 0) {
      if (tp->t_outq.tq_count > TTYQ_HIWAT) {
        tty_start(tp);
        if (tp->t_outq.tq_count <= TTYQ_HIWAT)
          continue;

        tp->t_state |= TS_ASLEEP;
        sem_wait(&tp->t_output);
        continue;
      }

      if (copyin(buf, &c, 1))
        return -EFAULT;

      tty_output((int)c, tp);
      ++buf;
      --nbyte;
      ++count;
    }

    total += count;
  }

  tty_start(tp);
  *size = total;
  return 0;
}
Exemple #4
0
/*
 * Flush tty read and/or write queues, notifying anyone waiting.
 */
static void
tty_flush(struct tty *tp, int rw)
{

	DPRINTF(("tty_flush rw=%d\n", rw));

	if (rw & FREAD) {
		while (ttyq_getc(&tp->t_canq) != -1)
			;
		while (ttyq_getc(&tp->t_rawq) != -1)
			;
		sched_wakeup(&tp->t_input);
	}
	if (rw & FWRITE) {
		tp->t_state &= ~TS_TTSTOP;
		tty_start(tp);
	}
}
Exemple #5
0
/*
 * Flush tty read and/or write queues, notifying anyone waiting.
 */
static void tty_flush(struct tty *tp, int rw)
{

  DPRINTF(TTYDB_CORE, ("tty_flush rw=%d\n", rw));

  if (rw & FREAD) {
    while (tty_getc(&tp->t_canq) != -1)
      continue;

    while (tty_getc(&tp->t_rawq) != -1)
      continue;

    sem_post(&tp->t_input);
  }

  if (rw & FWRITE) {
    tp->t_state &= ~TS_TTSTOP;
    tty_start(tp);
  }
}
Exemple #6
0
/*
 * Ioctls for all tty devices.
 */
int tty_ioctl(struct tty *tp, u_long cmd, void *data)
{
  struct tty_queue *qp;

  switch (cmd) {
  case TCGETS:
    if (copyout(&tp->t_termios, data,
         sizeof(struct termios)))
      return -EFAULT;
    break;
  case TCSETSW:
  case TCSETSF:
    tty_wait(tp);
    if (cmd == TCSETSF)
      tty_flush(tp, FREAD);
    /* FALLTHROUGH */
  case TCSETS:
    if (copyin(data, &tp->t_termios,
         sizeof(struct termios)))
      return -EFAULT;
    break;
  case TIOCSPGRP:      /* set pgrp of tty */
    if (copyin(data, &tp->t_pgid, sizeof(pid_t)))
      return -EFAULT;
    break;
  case TIOCGPGRP:
    if (copyout(&tp->t_pgid, data, sizeof(pid_t)))
      return -EFAULT;
    break;
#ifdef TIOCFLUSH
  case TIOCFLUSH: {
    int flags;
    if (copyin(data, &flags, sizeof(flags)))
      return -EFAULT;
    if (flags == 0)
      flags = FREAD | FWRITE;
    else
      flags &= FREAD | FWRITE;
    tty_flush(tp, flags);
    break;
    }
#endif
#ifdef TIOCSTART
  case TIOCSTART:
    if (tp->t_state & TS_TTSTOP) {
      tp->t_state &= ~TS_TTSTOP;
      tty_start(tp);
    }
    break;
#endif
#ifdef TIOCSTOP
  case TIOCSTOP:
    if (!(tp->t_state & TS_TTSTOP)) {
      tp->t_state |= TS_TTSTOP;
    }
    break;
#endif
  case TIOCGWINSZ:
    if (copyout(&tp->t_winsize, data,
          sizeof(struct winsize)))
      return -EFAULT;
    break;
  case TIOCSWINSZ:
    if (copyin(data, &tp->t_winsize,
         sizeof(struct winsize)))
      return -EFAULT;
    break;
#ifdef TIOCSETSIGT
  case TIOCSETSIGT:  /* Prex */
    if (copyin(data, &tp->t_pid, sizeof(pid_t)))
      return -EFAULT;
    break;
#endif
  case TIOCINQ:
    qp = (tp->t_lflag & ICANON) ? &tp->t_canq : &tp->t_rawq;
    if (copyout(&qp->tq_count, data, sizeof(int)))
      return -EFAULT;
    break;
  case TIOCOUTQ:
    if (copyout(&tp->t_outq.tq_count, data, sizeof(int)))
      return -EFAULT;
    break;
  }
  return 0;
}
Exemple #7
0
/*
 * Process input of a single character received on a tty.
 * echo if required.
 * This may be called with interrupt level.
 */
void tty_input(int c, struct tty *tp)
{
  unsigned char *cc;
  tcflag_t iflag, lflag;
  int sig = -1;

  DPRINTF(TTYDB_CORE, ("tty_input: %d\n", c));

  // Reload power management timer */
  pm_notify(PME_USER_ACTIVITY);

  lflag = tp->t_lflag;
  iflag = tp->t_iflag;
  cc = tp->t_cc;

#if defined(DEBUG) && defined(CONFIG_KD)
  if (c == cc[VDDB]) {
    kd_enter();
    tty_flush(tp, FREAD | FWRITE);
    goto endcase;
  }
#endif /* !CONFIG_KD*/

  /* IGNCR, ICRNL, INLCR */
  if (c == '\r') {
    if (iflag & IGNCR)
      goto endcase;
    else if (iflag & ICRNL)
      c = '\n';
  } else if (c == '\n' && (iflag & INLCR)) {
    c = '\r';
  }

  if (iflag & IXON) {
    /* stop (^S) */
    if (c == cc[VSTOP]) {
      if (!(tp->t_state & TS_TTSTOP)) {
        tp->t_state |= TS_TTSTOP;
        return;
      }
      if (c != cc[VSTART])
        return;
      /* if VSTART == VSTOP then toggle */
      goto endcase;
    }

    /* start (^Q) */
    if (c == cc[VSTART])
      goto restartoutput;
  }

  if (lflag & ICANON) {
    /* erase (^H / ^?) or backspace */
    if (c == cc[VERASE] || c == '\b') {
      if (!ttyq_empty(&tp->t_rawq))
        tty_rubout(tty_unputc(&tp->t_rawq), tp);
      goto endcase;
    }

    /* kill (^U) */
    if (c == cc[VKILL]) {
      while (!ttyq_empty(&tp->t_rawq))
        tty_rubout(tty_unputc(&tp->t_rawq), tp);
      goto endcase;
    }
  }

  if (lflag & ISIG) {
    /* quit (^C) */
    if (c == cc[VINTR] || c == cc[VQUIT]) {
      if (!(lflag & NOFLSH)) {
        tp->t_state |= TS_ISIG;
        tty_flush(tp, FREAD | FWRITE);
      }
      tty_echo(c, tp);
      sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT;
      goto endcase;
    }

    /* suspend (^Z) */
    if (c == cc[VSUSP]) {
      if (!(lflag & NOFLSH)) {
        tp->t_state |= TS_ISIG;
        tty_flush(tp, FREAD | FWRITE);
      }
      tty_echo(c, tp);
      sig = SIGTSTP;
      goto endcase;
    }
  }

  /*
   * Check for input buffer overflow
   */
  if (ttyq_full(&tp->t_rawq)) {
    tty_flush(tp, FREAD | FWRITE);
    goto endcase;
  }

  tty_putc(c, &tp->t_rawq);

  if (lflag & ICANON) {
    if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) {
      tty_catq(&tp->t_rawq, &tp->t_canq);
      sem_post(&tp->t_input);
    }
  } else {
    sem_post(&tp->t_input);
  }

  if (lflag & ECHO)
    tty_echo(c, tp);

endcase:
  /*
   * IXANY means allow any character to restart output.
   */
  if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 &&
      cc[VSTART] != cc[VSTOP])
    return;

restartoutput:
  tp->t_state &= ~TS_TTSTOP;

  if (sig != -1) {
    if (tp->t_pid) {
      tp->t_signo = sig;
      sched_dpc(&tp->t_dpc, &tty_signal, tp);
    }
  }

  tty_start(tp);
}
Exemple #8
0
/*
 * Ioctls for all tty devices.
 */
static int
tty_ioctl(file_t file, u_long cmd, void *data)
{
	struct tty *tp = file->priv;
	int flags;
	struct tty_queue *qp;

	switch (cmd) {
	case TIOCGETA:
		if (umem_copyout(&tp->t_termios, data,
				 sizeof(struct termios)))
			return EFAULT;
		break;
	case TIOCSETAW:
	case TIOCSETAF:
		tty_wait(tp);
		if (cmd == TIOCSETAF)
			tty_flush(tp, FREAD);
		/* FALLTHROUGH */
	case TIOCSETA:
		if (umem_copyin(data, &tp->t_termios,
				 sizeof(struct termios)))
			return EFAULT;
		break;
	case TIOCSPGRP:			/* set pgrp of tty */
		if (umem_copyin(data, &tp->t_pgid, sizeof(pid_t)))
			return EFAULT;
		break;
	case TIOCGPGRP:
		if (umem_copyout(&tp->t_pgid, data, sizeof(pid_t)))
			return EFAULT;
		break;
	case TIOCFLUSH:
		if (umem_copyin(data, &flags, sizeof(flags)))
			return EFAULT;
		break;
		if (flags == 0)
			flags = FREAD | FWRITE;
		else
			flags &= FREAD | FWRITE;
		tty_flush(tp, flags);
		break;
	case TIOCSTART:
		if (tp->t_state & TS_TTSTOP) {
			tp->t_state &= ~TS_TTSTOP;
			tty_start(tp);
		}
		break;
	case TIOCSTOP:
		if (!(tp->t_state & TS_TTSTOP)) {
			tp->t_state |= TS_TTSTOP;
		}
		break;
	case TIOCGWINSZ:
		if (umem_copyout(&tp->t_winsize, data,
				 sizeof(struct winsize)))
			return EFAULT;
		break;
	case TIOCSWINSZ:
		if (umem_copyin(&tp->t_winsize, data,
				 sizeof(struct winsize)))
			return EFAULT;
		break;
	case TIOCSETSIGT:
		if (umem_copyin(data, &sig_task, sizeof(task_t)))
			return EFAULT;
		break;
	case TIOCINQ:
		qp = (tp->t_lflag & ICANON) ? &tp->t_canq : &tp->t_rawq;
		if (umem_copyout(&qp->tq_count, data, sizeof(int)))
			return EFAULT;
		break;
	case TIOCOUTQ:
		if (umem_copyout(&tp->t_outq.tq_count, data, sizeof(int)))
			return EFAULT;
		break;
	}
	return 0;
}
Exemple #9
0
/*
 * Process input of a single character received on a tty.
 * echo if required.
 * This may be called with interrupt level.
 */
void
tty_input(int c, struct tty *tp)
{
	unsigned char *cc;
	tcflag_t iflag, lflag;
	int sig = -1;

#ifdef CONFIG_CPUFREQ
	/* Reload power management timer */
	pm_active();
#endif
	lflag = tp->t_lflag;
	iflag = tp->t_iflag;
	cc = tp->t_cc;

	/* IGNCR, ICRNL, INLCR */
	if (c == '\r') {
		if (iflag & IGNCR)
			goto endcase;
		else if (iflag & ICRNL)
			c = '\n';
	} else if (c == '\n' && (iflag & INLCR))
		c = '\r';

	if (iflag & IXON) {
		/* stop (^S) */
		if (c == cc[VSTOP]) {
			if (!(tp->t_state & TS_TTSTOP)) {
				tp->t_state |= TS_TTSTOP;
				return;
			}
			if (c != cc[VSTART])
				return;
			/* if VSTART == VSTOP then toggle */
			goto endcase;
		}
		/* start (^Q) */
		if (c == cc[VSTART])
			goto restartoutput;
	}
	if (lflag & ICANON) {
		/* erase (^H / ^?) or backspace */
		if (c == cc[VERASE] || c == '\b') {
			if (!ttyq_empty(&tp->t_rawq)) {
				ttyq_unputc(&tp->t_rawq);
				tty_rubout(tp);
			}
			goto endcase;
		}
		/* kill (^U) */
		if (c == cc[VKILL]) {
			while (!ttyq_empty(&tp->t_rawq)) {
				ttyq_unputc(&tp->t_rawq);
				tty_rubout(tp);
			}
			goto endcase;
		}
	}
	if (lflag & ISIG) {
		/* quit (^C) */
		if (c == cc[VINTR] || c == cc[VQUIT]) {
			if (!(lflag & NOFLSH))
				tty_flush(tp, FREAD | FWRITE);
			tty_echo(c, tp);
			sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT;
			goto endcase;
		}
		/* suspend (^Z) */
		if (c == cc[VSUSP]) {
			if (!(lflag & NOFLSH))
				tty_flush(tp, FREAD | FWRITE);
			tty_echo(c, tp);
			sig = SIGTSTP;
			goto endcase;
		}
	}

	/*
	 * Check for input buffer overflow
	 */
	if (ttyq_full(&tp->t_rawq)) {
		tty_flush(tp, FREAD | FWRITE);
		goto endcase;
	}
	ttyq_putc(c, &tp->t_rawq);

	if (lflag & ICANON) {
		if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) {
			tty_catq(&tp->t_rawq, &tp->t_canq);
			sched_wakeup(&tp->t_input);
		}
	} else
		sched_wakeup(&tp->t_input);

	if (lflag & ECHO)
		tty_echo(c, tp);
 endcase:
	/*
	 * IXANY means allow any character to restart output.
	 */
	if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 &&
	    cc[VSTART] != cc[VSTOP])
		return;
 restartoutput:
	tp->t_state &= ~TS_TTSTOP;

	if (sig != -1) {
		if (sig_task)
			exception_post(sig_task, sig);
	}
	tty_start(tp);
}
Exemple #10
0
/*
 * start an editing session: process the EDIT/VIEW message
 * if view == 1, text will be viewed, else edited
 */
void message_edit __P4 (char *,text, int,msglen, char,view, char,builtin)
{
    char tmpname[BUFSIZE], command_str[BUFSIZE], buf[BUFSIZE];
    char *errdesc = "#warning: protocol error (message_edit, no %s)\n";
    int tmpfd, i, childpid;
    unsigned int key;
    editsess *s;
    char *editor, *descr;
    char *args[4];
    int waitforeditor;
    
    status(1);

    args[0] = "/bin/sh"; args[1] = "-c";
    args[2] = command_str; args[3] = 0;  

    if (view) {
	key = (unsigned int)-1;
	i = 0;
    } else {
	if (text[0] != 'M') {
	    tty_printf(errdesc, "M");
	    free(text);
	    return;
	}
	for (i = 1; i < msglen && isdigit(text[i]); i++)
	    ;
	if (text[i++] != '\n' || i >= msglen) {
	    tty_printf(errdesc, "\\n");
	    free(text);
	    return;
	}
	key = strtoul(text + 1, NULL, 10);
    }
    descr = text + i;
    while (i < msglen && text[i] != '\n') i++;
    if (i >= msglen) {
	tty_printf(errdesc, "desc");
	free(text);
	return;
    }
    text[i++] = '\0';
    
    sprintf(tmpname, "/tmp/powwow.%u.%d%d", key, getpid(), abs(rand()) >> 8);
    if ((tmpfd = open(tmpname, O_WRONLY | O_CREAT, 0600)) < 0) {
	errmsg("create temp edit file");
	free(text);
	return;
    }
    if (write(tmpfd, text + i, msglen - i) < msglen - i) {
	errmsg("write to temp edit file");
	free(text);
	close(tmpfd);
	return;
    }
    close(tmpfd);
    
    s = (editsess*)malloc(sizeof(editsess));
    if (!s) {
	errmsg("malloc");
	return;
    }
    s->ctime = time((time_t*)NULL);
    s->oldsize = msglen - i;
    s->key = key;
    s->fd = (view || builtin) ? -1 : tcp_fd; /* MUME doesn't expect a reply. */
    s->cancel = 0;
    s->descr = my_strdup(descr);
    s->file = my_strdup(tmpname);
    free(text);
    
    /* send a edit_start message (if wanted) */ 
    if ((!edit_sess) && (*edit_start)) {
	error = 0;
	parse_instruction(edit_start, 0, 0, 1);
	history_done = 0;
    }
    
    if (view) {
	if (!(editor = getenv("POWWOWPAGER")) && !(editor = getenv("PAGER")))
	    editor = "more";
    } else {
	if (!(editor = getenv("POWWOWEDITOR")) && !(editor = getenv("EDITOR")))
	    editor = "emacs";
    }
    
    if (editor[0] == '&') {
	waitforeditor = 0;
	editor++;
    } else
	waitforeditor = 1;
    
    if (waitforeditor) {
	tty_quit();
	/* ignore SIGINT since interrupting the child would interrupt us too,
	 if we are in the same tty group */
	sig_permanent(SIGINT, SIG_IGN);
	sig_permanent(SIGCHLD, SIG_DFL);
    }
    
    switch(childpid = fork()) {		/* let's get schizophrenic */
      case 0:
	sprintf(command_str, "%s %s", editor, s->file);
	sprintf(buf, "TITLE=%s", s->descr);
	putenv(buf);
	/*	   setenv("TITLE", s->descr, 1);*/
	execvp((char *)args[0], (char **)args);
	syserr("execve");
	break;
      case -1:
	errmsg("fork");
	free(s->descr);
	free(s->file);
	free(s);
	return;
    }
    s->pid = childpid;
    if (waitforeditor) {
	while ((i = waitpid(childpid, (int*)NULL, 0)) == -1 && errno == EINTR)
	    ;

	signal_start();		/* reset SIGINT and SIGCHLD handlers */
	tty_start();
	
	if (s->fd != -1) {
	    tty_gotoxy(0, lines - 1);
	    tty_putc('\n');
	}
	
	if (i == -1)
	    errmsg("waitpid");
	else
	    finish_edit(s);
	
	free(s->descr);
	free(s->file);
	if (i != -1 && !edit_sess && *edit_end) {
	    error = 0;
	    parse_instruction(edit_end, 0, 0, 1);
	    history_done = 0;
	}
	
	free(s);
	
    } else {
	s->next = edit_sess;
	edit_sess = s;
    }
}