1bfdaa523SEd Schouten /*- 2bfdaa523SEd Schouten * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> 3bfdaa523SEd Schouten * All rights reserved. 4bfdaa523SEd Schouten * 5bfdaa523SEd Schouten * Portions of this software were developed under sponsorship from Snow 6bfdaa523SEd Schouten * B.V., the Netherlands. 7bfdaa523SEd Schouten * 8bfdaa523SEd Schouten * Redistribution and use in source and binary forms, with or without 9bfdaa523SEd Schouten * modification, are permitted provided that the following conditions 10bfdaa523SEd Schouten * are met: 11bfdaa523SEd Schouten * 1. Redistributions of source code must retain the above copyright 12bfdaa523SEd Schouten * notice, this list of conditions and the following disclaimer. 13bfdaa523SEd Schouten * 2. Redistributions in binary form must reproduce the above copyright 14bfdaa523SEd Schouten * notice, this list of conditions and the following disclaimer in the 15bfdaa523SEd Schouten * documentation and/or other materials provided with the distribution. 16bfdaa523SEd Schouten * 17bfdaa523SEd Schouten * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18bfdaa523SEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19bfdaa523SEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20bfdaa523SEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21bfdaa523SEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22bfdaa523SEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23bfdaa523SEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24bfdaa523SEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25bfdaa523SEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26bfdaa523SEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27bfdaa523SEd Schouten * SUCH DAMAGE. 28bfdaa523SEd Schouten */ 29bfdaa523SEd Schouten 30bfdaa523SEd Schouten #include <sys/cdefs.h> 31bfdaa523SEd Schouten __FBSDID("$FreeBSD$"); 32bfdaa523SEd Schouten 33bfdaa523SEd Schouten #include <sys/param.h> 34bfdaa523SEd Schouten #include <sys/conf.h> 35bfdaa523SEd Schouten #include <sys/eventhandler.h> 36bfdaa523SEd Schouten #include <sys/fcntl.h> 37bfdaa523SEd Schouten #include <sys/kernel.h> 38bfdaa523SEd Schouten #include <sys/module.h> 39bfdaa523SEd Schouten #include <sys/proc.h> 40bfdaa523SEd Schouten #include <sys/sysctl.h> 41bfdaa523SEd Schouten #include <sys/syslog.h> 42bfdaa523SEd Schouten #include <sys/systm.h> 43bfdaa523SEd Schouten #include <sys/tty.h> 44bfdaa523SEd Schouten 45bfdaa523SEd Schouten /* 46bfdaa523SEd Schouten * This driver implements a BSD-style compatibility naming scheme for 47bfdaa523SEd Schouten * the pts(4) driver. We just call into pts(4) to create the actual PTY. 48bfdaa523SEd Schouten * To make sure we don't use the same PTY multiple times, we abuse 49bfdaa523SEd Schouten * si_drv1 inside the cdev to mark whether the PTY is in use. 504d3b1aacSEd Schouten * 514d3b1aacSEd Schouten * It also implements a /dev/ptmx device node, which is useful for Linux 524d3b1aacSEd Schouten * binary emulation. 53bfdaa523SEd Schouten */ 54bfdaa523SEd Schouten 55bfdaa523SEd Schouten static unsigned int pty_warningcnt = 1; 56bfdaa523SEd Schouten SYSCTL_UINT(_kern, OID_AUTO, tty_pty_warningcnt, CTLFLAG_RW, 57bfdaa523SEd Schouten &pty_warningcnt, 0, 58bfdaa523SEd Schouten "Warnings that will be triggered upon legacy PTY allocation"); 59bfdaa523SEd Schouten 60bfdaa523SEd Schouten static int 61bfdaa523SEd Schouten ptydev_fdopen(struct cdev *dev, int fflags, struct thread *td, struct file *fp) 62bfdaa523SEd Schouten { 63bfdaa523SEd Schouten int error; 64bfdaa523SEd Schouten char name[6]; /* "ttyXX" */ 65bfdaa523SEd Schouten 66bfdaa523SEd Schouten if (!atomic_cmpset_ptr((uintptr_t *)&dev->si_drv1, 0, 1)) 67bfdaa523SEd Schouten return (EBUSY); 68bfdaa523SEd Schouten 69bfdaa523SEd Schouten /* Generate device name and create PTY. */ 70bfdaa523SEd Schouten strcpy(name, devtoname(dev)); 71bfdaa523SEd Schouten name[0] = 't'; 72bfdaa523SEd Schouten 73bfdaa523SEd Schouten error = pts_alloc_external(fflags & (FREAD|FWRITE), td, fp, dev, name); 74bfdaa523SEd Schouten if (error != 0) { 75bfdaa523SEd Schouten destroy_dev_sched(dev); 76bfdaa523SEd Schouten return (error); 77bfdaa523SEd Schouten } 78bfdaa523SEd Schouten 79bfdaa523SEd Schouten /* Raise a warning when a legacy PTY has been allocated. */ 80bfdaa523SEd Schouten if (pty_warningcnt > 0) { 81bfdaa523SEd Schouten pty_warningcnt--; 82bfdaa523SEd Schouten log(LOG_INFO, "pid %d (%s) is using legacy pty devices%s\n", 83bfdaa523SEd Schouten td->td_proc->p_pid, td->td_name, 84bfdaa523SEd Schouten pty_warningcnt ? "" : " - not logging anymore"); 85bfdaa523SEd Schouten } 86bfdaa523SEd Schouten 87bfdaa523SEd Schouten return (0); 88bfdaa523SEd Schouten } 89bfdaa523SEd Schouten 90bfdaa523SEd Schouten static struct cdevsw ptydev_cdevsw = { 91bfdaa523SEd Schouten .d_version = D_VERSION, 92bfdaa523SEd Schouten .d_fdopen = ptydev_fdopen, 93bfdaa523SEd Schouten .d_name = "ptydev", 94bfdaa523SEd Schouten }; 95bfdaa523SEd Schouten 96bfdaa523SEd Schouten static void 97bfdaa523SEd Schouten pty_clone(void *arg, struct ucred *cr, char *name, int namelen, 98bfdaa523SEd Schouten struct cdev **dev) 99bfdaa523SEd Schouten { 100bfdaa523SEd Schouten 101bfdaa523SEd Schouten /* Cloning is already satisfied. */ 102bfdaa523SEd Schouten if (*dev != NULL) 103bfdaa523SEd Schouten return; 104bfdaa523SEd Schouten 105bfdaa523SEd Schouten /* Only catch /dev/ptyXX. */ 106bfdaa523SEd Schouten if (namelen != 5 || bcmp(name, "pty", 3) != 0) 107bfdaa523SEd Schouten return; 108bfdaa523SEd Schouten 109bfdaa523SEd Schouten /* Only catch /dev/pty[l-sL-S]X. */ 110bfdaa523SEd Schouten if (!(name[3] >= 'l' && name[3] <= 's') && 111bfdaa523SEd Schouten !(name[3] >= 'L' && name[3] <= 'S')) 112bfdaa523SEd Schouten return; 113bfdaa523SEd Schouten 114bfdaa523SEd Schouten /* Only catch /dev/pty[l-sL-S][0-9a-v]. */ 115bfdaa523SEd Schouten if (!(name[4] >= '0' && name[4] <= '9') && 116bfdaa523SEd Schouten !(name[4] >= 'a' && name[4] <= 'v')) 117bfdaa523SEd Schouten return; 118bfdaa523SEd Schouten 119bfdaa523SEd Schouten /* Create the controller device node. */ 120bfdaa523SEd Schouten *dev = make_dev_credf(MAKEDEV_REF, &ptydev_cdevsw, 0, 121bfdaa523SEd Schouten NULL, UID_ROOT, GID_WHEEL, 0666, "%s", name); 122bfdaa523SEd Schouten } 123bfdaa523SEd Schouten 124bfdaa523SEd Schouten static int 1254d3b1aacSEd Schouten ptmx_fdopen(struct cdev *dev __unused, int fflags, struct thread *td, 1264d3b1aacSEd Schouten struct file *fp) 1274d3b1aacSEd Schouten { 1284d3b1aacSEd Schouten 1294d3b1aacSEd Schouten return (pts_alloc(fflags & (FREAD|FWRITE), td, fp)); 1304d3b1aacSEd Schouten } 1314d3b1aacSEd Schouten 1324d3b1aacSEd Schouten static struct cdevsw ptmx_cdevsw = { 1334d3b1aacSEd Schouten .d_version = D_VERSION, 1344d3b1aacSEd Schouten .d_fdopen = ptmx_fdopen, 1354d3b1aacSEd Schouten .d_name = "ptmx", 1364d3b1aacSEd Schouten }; 1374d3b1aacSEd Schouten 1384d3b1aacSEd Schouten static int 139bfdaa523SEd Schouten pty_modevent(module_t mod, int type, void *data) 140bfdaa523SEd Schouten { 141bfdaa523SEd Schouten 142bfdaa523SEd Schouten switch(type) { 143bfdaa523SEd Schouten case MOD_LOAD: 144bfdaa523SEd Schouten EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); 145*23b70c1aSKonstantin Belousov make_dev_credf(MAKEDEV_ETERNAL_KLD, &ptmx_cdevsw, 0, NULL, 146*23b70c1aSKonstantin Belousov UID_ROOT, GID_WHEEL, 0666, "ptmx"); 147bfdaa523SEd Schouten break; 148bfdaa523SEd Schouten case MOD_SHUTDOWN: 149bfdaa523SEd Schouten break; 150bfdaa523SEd Schouten case MOD_UNLOAD: 151bfdaa523SEd Schouten /* XXX: No unloading support yet. */ 152bfdaa523SEd Schouten return (EBUSY); 153bfdaa523SEd Schouten default: 154bfdaa523SEd Schouten return (EOPNOTSUPP); 155bfdaa523SEd Schouten } 156bfdaa523SEd Schouten 157bfdaa523SEd Schouten return (0); 158bfdaa523SEd Schouten } 159bfdaa523SEd Schouten 160bfdaa523SEd Schouten DEV_MODULE(pty, pty_modevent, NULL); 161