summaryrefslogtreecommitdiffstats
path: root/sys/kern/tty_cons.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/tty_cons.c')
-rw-r--r--sys/kern/tty_cons.c375
1 files changed, 300 insertions, 75 deletions
diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c
index 6189d72..581ff3f 100644
--- a/sys/kern/tty_cons.c
+++ b/sys/kern/tty_cons.c
@@ -35,129 +35,323 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)cons.c 7.2 (Berkeley) 5/9/91
- *
- * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
- * -------------------- ----- ----------------------
- * CURRENT PATCH LEVEL: 1 00083
- * -------------------- ----- ----------------------
- *
- * 16 Aug 92 Pace Willisson /dev/console redirect (xterm -C, etc.)
- * 14 Mar 93 Chris G. Demetriou Moved pg() here from isa/pccons.c
+ * from: @(#)cons.c 7.2 (Berkeley) 5/9/91
+ * $Id: cons.c,v 1.59 1998/08/23 08:26:40 bde Exp $
*/
+#include "opt_devfs.h"
-#include "sys/param.h"
-#include "sys/proc.h"
-#include "sys/user.h"
-#include "sys/systm.h"
-#include "sys/buf.h"
-#include "sys/ioctl.h"
-#include "sys/tty.h"
-#include "sys/file.h"
-#include "sys/conf.h"
+#include <sys/param.h>
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif /*DEVFS*/
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/reboot.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
-#include "cons.h"
+#include <machine/cpu.h>
+#include <machine/cons.h>
-/* XXX - all this could be autoconfig()ed */
-int pccnprobe(), pccninit(), pccngetc(), pccnputc();
-#include "com.h"
-#if NCOM > 0
-int comcnprobe(), comcninit(), comcngetc(), comcnputc();
-#endif
+static d_open_t cnopen;
+static d_close_t cnclose;
+static d_read_t cnread;
+static d_write_t cnwrite;
+static d_ioctl_t cnioctl;
+static d_poll_t cnpoll;
-struct consdev constab[] = {
- { pccnprobe, pccninit, pccngetc, pccnputc },
-#if NCOM > 0
- { comcnprobe, comcninit, comcngetc, comcnputc },
-#endif
- { 0 },
+#define CDEV_MAJOR 0
+static struct cdevsw cn_cdevsw = {
+ cnopen, cnclose, cnread, cnwrite,
+ cnioctl, nullstop, nullreset, nodevtotty,
+ cnpoll, nommap, NULL, "console",
+ NULL, -1, nodump, nopsize,
+ D_TTY,
};
-/* end XXX */
-struct tty *constty = 0; /* virtual console output device */
-struct consdev *cn_tab; /* physical console device info */
-struct tty *cn_tty; /* XXX: console tty struct for tprintf */
+static dev_t cn_dev_t; /* seems to be never really used */
+SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
+ &cn_dev_t, sizeof cn_dev_t, "T,dev_t", "");
+
+static int cn_mute;
+int cons_unavail = 0; /* XXX:
+ * physical console not available for
+ * input (i.e., it is in graphics mode)
+ */
+
+static u_char cn_is_open; /* nonzero if logical console is open */
+static int openmode, openflag; /* how /dev/console was openned */
+static u_char cn_phys_is_open; /* nonzero if physical device is open */
+static d_close_t *cn_phys_close; /* physical device close function */
+static d_open_t *cn_phys_open; /* physical device open function */
+static struct consdev *cn_tab; /* physical console device info */
+static struct tty *cn_tp; /* physical console tty struct */
+#ifdef DEVFS
+static void *cn_devfs_token; /* represents the devfs entry */
+#endif /* DEVFS */
+
+CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL);
+
+void
cninit()
{
- register struct consdev *cp;
+ struct consdev *best_cp, *cp;
+ struct consdev **list;
/*
- * Collect information about all possible consoles
- * and find the one with highest priority
+ * Find the first console with the highest priority.
*/
- for (cp = constab; cp->cn_probe; cp++) {
+ best_cp = NULL;
+ list = (struct consdev **)cons_set.ls_items;
+ while ((cp = *list++) != NULL) {
+ if (cp->cn_probe == NULL)
+ continue;
(*cp->cn_probe)(cp);
if (cp->cn_pri > CN_DEAD &&
- (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri))
- cn_tab = cp;
+ (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
+ best_cp = cp;
}
+
+ /*
+ * Check if we should mute the console (for security reasons perhaps)
+ * It can be changes dynamically using sysctl kern.consmute
+ * once we are up and going.
+ *
+ */
+ cn_mute = ((boothowto & (RB_MUTE
+ |RB_SINGLE
+ |RB_VERBOSE
+ |RB_ASKNAME
+ |RB_CONFIG)) == RB_MUTE);
+
+ /*
+ * If no console, give up.
+ */
+ if (best_cp == NULL) {
+ cn_tab = best_cp;
+ return;
+ }
+
+ /*
+ * Initialize console, then attach to it. This ordering allows
+ * debugging using the previous console, if any.
+ * XXX if there was a previous console, then its driver should
+ * be informed when we forget about it.
+ */
+ (*best_cp->cn_init)(best_cp);
+ cn_tab = best_cp;
+}
+
+void
+cninit_finish()
+{
+ struct cdevsw *cdp;
+
+ if ((cn_tab == NULL) || cn_mute)
+ return;
+
/*
- * No console, we can handle it
+ * Hook the open and close functions.
*/
- if ((cp = cn_tab) == NULL)
+ cdp = cdevsw[major(cn_tab->cn_dev)];
+ cn_phys_close = cdp->d_close;
+ cdp->d_close = cnclose;
+ cn_phys_open = cdp->d_open;
+ cdp->d_open = cnopen;
+ cn_tp = (*cdp->d_devtotty)(cn_tab->cn_dev);
+ cn_dev_t = cn_tp->t_dev;
+}
+
+static void
+cnuninit(void)
+{
+ struct cdevsw *cdp;
+
+ if (cn_tab == NULL)
return;
+
/*
- * Turn on console
+ * Unhook the open and close functions.
*/
- cn_tty = cp->cn_tp;
- (*cp->cn_init)(cp);
+ cdp = cdevsw[major(cn_tab->cn_dev)];
+ cdp->d_close = cn_phys_close;
+ cn_phys_close = NULL;
+ cdp->d_open = cn_phys_open;
+ cn_phys_open = NULL;
+ cn_tp = NULL;
+ cn_dev_t = 0;
+}
+
+/*
+ * User has changed the state of the console muting.
+ * This may require us to open or close the device in question.
+ */
+static int
+sysctl_kern_consmute SYSCTL_HANDLER_ARGS
+{
+ int error;
+ int ocn_mute;
+
+ ocn_mute = cn_mute;
+ error = sysctl_handle_int(oidp, &cn_mute, 0, req);
+ if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
+ if(ocn_mute && !cn_mute) {
+ /*
+ * going from muted to unmuted.. open the physical dev
+ * if the console has been openned
+ */
+ cninit_finish();
+ if(cn_is_open)
+ /* XXX curproc is not what we want really */
+ error = cnopen(cn_dev_t, openflag,
+ openmode, curproc);
+ /* if it failed, back it out */
+ if ( error != 0) cnuninit();
+ } else if (!ocn_mute && cn_mute) {
+ /*
+ * going from unmuted to muted.. close the physical dev
+ * if it's only open via /dev/console
+ */
+ if(cn_is_open)
+ error = cnclose(cn_dev_t, openflag,
+ openmode, curproc);
+ if ( error == 0) cnuninit();
+ }
+ if (error != 0) {
+ /*
+ * back out the change if there was an error
+ */
+ cn_mute = ocn_mute;
+ }
+ }
+ return (error);
}
+SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
+ 0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
+
+static int
cnopen(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
+ dev_t cndev, physdev;
+ int retval = 0;
+
if (cn_tab == NULL)
return (0);
- dev = cn_tab->cn_dev;
- return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
+ cndev = cn_tab->cn_dev;
+ physdev = (major(dev) == major(cndev) ? dev : cndev);
+ /*
+ * If mute is active, then non console opens don't get here
+ * so we don't need to check for that. They
+ * bypass this and go straight to the device.
+ */
+ if(!cn_mute)
+ retval = (*cn_phys_open)(physdev, flag, mode, p);
+ if (retval == 0) {
+ /*
+ * check if we openned it via /dev/console or
+ * via the physical entry (e.g. /dev/sio0).
+ */
+ if (dev == cndev)
+ cn_phys_is_open = 1;
+ else if (physdev == cndev) {
+ openmode = mode;
+ openflag = flag;
+ cn_is_open = 1;
+ }
+ }
+ return (retval);
}
-
+
+static int
cnclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
+ dev_t cndev;
+
if (cn_tab == NULL)
return (0);
- dev = cn_tab->cn_dev;
- return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
+ cndev = cn_tab->cn_dev;
+ /*
+ * act appropriatly depending on whether it's /dev/console
+ * or the pysical device (e.g. /dev/sio) that's being closed.
+ * in either case, don't actually close the device unless
+ * both are closed.
+ */
+ if (dev == cndev) {
+ /* the physical device is about to be closed */
+ cn_phys_is_open = 0;
+ if (cn_is_open) {
+ if (cn_tp) {
+ /* perform a ttyhalfclose() */
+ /* reset session and proc group */
+ cn_tp->t_pgrp = NULL;
+ cn_tp->t_session = NULL;
+ }
+ return (0);
+ }
+ } else if (major(dev) != major(cndev)) {
+ /* the logical console is about to be closed */
+ cn_is_open = 0;
+ if (cn_phys_is_open)
+ return (0);
+ dev = cndev;
+ }
+ if(cn_phys_close)
+ return ((*cn_phys_close)(dev, flag, mode, p));
+ return (0);
}
-
+
+static int
cnread(dev, uio, flag)
dev_t dev;
struct uio *uio;
+ int flag;
{
- if (cn_tab == NULL)
+ if ((cn_tab == NULL) || cn_mute)
return (0);
dev = cn_tab->cn_dev;
- return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
+ return ((*cdevsw[major(dev)]->d_read)(dev, uio, flag));
}
-
+
+static int
cnwrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
+ int flag;
{
- if (cn_tab == NULL)
+ if ((cn_tab == NULL) || cn_mute) {
+ uio->uio_resid = 0; /* dump the data */
return (0);
- if (constty) /* 16 Aug 92*/
+ }
+ if (constty)
dev = constty->t_dev;
else
dev = cn_tab->cn_dev;
- return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
+ return ((*cdevsw[major(dev)]->d_write)(dev, uio, flag));
}
-
+
+static int
cnioctl(dev, cmd, data, flag, p)
dev_t dev;
+ u_long cmd;
caddr_t data;
+ int flag;
struct proc *p;
{
int error;
- if (cn_tab == NULL)
+ if ((cn_tab == NULL) || cn_mute)
return (0);
/*
* Superuser can always use this to wrest control of console
@@ -171,43 +365,74 @@ cnioctl(dev, cmd, data, flag, p)
return (0);
}
dev = cn_tab->cn_dev;
- return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
+ return ((*cdevsw[major(dev)]->d_ioctl)(dev, cmd, data, flag, p));
}
-/*ARGSUSED*/
-cnselect(dev, rw, p)
+static int
+cnpoll(dev, events, p)
dev_t dev;
- int rw;
+ int events;
struct proc *p;
{
- if (cn_tab == NULL)
+ if ((cn_tab == NULL) || cn_mute)
return (1);
- return (ttselect(cn_tab->cn_dev, rw, p));
+
+ dev = cn_tab->cn_dev;
+
+ return ((*cdevsw[major(dev)]->d_poll)(dev, events, p));
}
+int
cngetc()
{
- if (cn_tab == NULL)
- return (0);
- return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
+ int c;
+ if ((cn_tab == NULL) || cn_mute)
+ return (-1);
+ c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
+ if (c == '\r') c = '\n'; /* console input is always ICRNL */
+ return (c);
}
+int
+cncheckc()
+{
+ if ((cn_tab == NULL) || cn_mute)
+ return (-1);
+ return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
+}
+
+void
cnputc(c)
register int c;
{
- if (cn_tab == NULL)
+ if ((cn_tab == NULL) || cn_mute)
return;
if (c) {
- (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
if (c == '\n')
(*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
}
}
-pg(p,q,r,s,t,u,v,w,x,y,z) char *p; {
- printf(p,q,r,s,t,u,v,w,x,y,z);
- printf("\n>");
- return(cngetc());
+static cn_devsw_installed = 0;
+
+static void
+cn_drvinit(void *unused)
+{
+ dev_t dev;
+
+ if( ! cn_devsw_installed ) {
+ dev = makedev(CDEV_MAJOR,0);
+ cdevsw_add(&dev,&cn_cdevsw,NULL);
+ cn_devsw_installed = 1;
+#ifdef DEVFS
+ cn_devfs_token = devfs_add_devswf(&cn_cdevsw, 0, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600,
+ "console");
+#endif
+ }
}
+SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
+
OpenPOWER on IntegriCloud