pty.c revision 303432
1139804Simp/*- 2181905Sed * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> 3181905Sed * All rights reserved. 41541Srgrimes * 5181905Sed * Portions of this software were developed under sponsorship from Snow 6181905Sed * B.V., the Netherlands. 7181905Sed * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 17181905Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20181905Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes */ 291541Srgrimes 30116182Sobrien#include <sys/cdefs.h> 31116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/pty/pty.c 303432 2016-07-28 11:43:25Z kib $"); 32116182Sobrien 331541Srgrimes#include <sys/param.h> 341541Srgrimes#include <sys/conf.h> 35181905Sed#include <sys/eventhandler.h> 3624131Sbde#include <sys/fcntl.h> 371541Srgrimes#include <sys/kernel.h> 38196480Sed#include <sys/module.h> 39181905Sed#include <sys/proc.h> 40182069Sed#include <sys/sysctl.h> 41196378Sed#include <sys/syslog.h> 42181905Sed#include <sys/systm.h> 43181905Sed#include <sys/tty.h> 441541Srgrimes 451541Srgrimes/* 46181905Sed * This driver implements a BSD-style compatibility naming scheme for 47181905Sed * the pts(4) driver. We just call into pts(4) to create the actual PTY. 48181905Sed * To make sure we don't use the same PTY multiple times, we abuse 49181905Sed * si_drv1 inside the cdev to mark whether the PTY is in use. 50196886Sed * 51196886Sed * It also implements a /dev/ptmx device node, which is useful for Linux 52196886Sed * binary emulation. 531541Srgrimes */ 541541Srgrimes 55303432Skibstatic unsigned pty_warningcnt = 1; 56182069SedSYSCTL_UINT(_kern, OID_AUTO, tty_pty_warningcnt, CTLFLAG_RW, 57303432Skib &pty_warningcnt, 0, 58303432Skib "Warnings that will be triggered upon legacy PTY allocation"); 59173456Sjhb 60181905Sedstatic int 61181905Sedptydev_fdopen(struct cdev *dev, int fflags, struct thread *td, struct file *fp) 62154833Scognet{ 63187680Sed int error; 64187680Sed char name[6]; /* "ttyXX" */ 65154833Scognet 66181905Sed if (!atomic_cmpset_ptr((uintptr_t *)&dev->si_drv1, 0, 1)) 671541Srgrimes return (EBUSY); 681541Srgrimes 69181905Sed /* Generate device name and create PTY. */ 70298337Scem strlcpy(name, devtoname(dev), sizeof(name)); 71187680Sed name[0] = 't'; 721541Srgrimes 73181905Sed error = pts_alloc_external(fflags & (FREAD|FWRITE), td, fp, dev, name); 74181905Sed if (error != 0) { 75181905Sed destroy_dev_sched(dev); 76181905Sed return (error); 771541Srgrimes } 781541Srgrimes 79181905Sed /* Raise a warning when a legacy PTY has been allocated. */ 80303432Skib counted_warning(&pty_warningcnt, "is using legacy pty devices"); 811541Srgrimes 821541Srgrimes return (0); 831541Srgrimes} 841541Srgrimes 85181905Sedstatic struct cdevsw ptydev_cdevsw = { 86181905Sed .d_version = D_VERSION, 87181905Sed .d_fdopen = ptydev_fdopen, 88181905Sed .d_name = "ptydev", 89181905Sed}; 901541Srgrimes 9112675Sjulianstatic void 92147982Srwatsonpty_clone(void *arg, struct ucred *cr, char *name, int namelen, 93147982Srwatson struct cdev **dev) 9464880Sphk{ 95293825Skib struct make_dev_args mda; 96293825Skib int error; 9764880Sphk 98181905Sed /* Cloning is already satisfied. */ 99130640Sphk if (*dev != NULL) 10064880Sphk return; 101181905Sed 102181905Sed /* Only catch /dev/ptyXX. */ 103181905Sed if (namelen != 5 || bcmp(name, "pty", 3) != 0) 10464880Sphk return; 105181905Sed 106181905Sed /* Only catch /dev/pty[l-sL-S]X. */ 107181905Sed if (!(name[3] >= 'l' && name[3] <= 's') && 108181905Sed !(name[3] >= 'L' && name[3] <= 'S')) 10964880Sphk return; 110181905Sed 111181905Sed /* Only catch /dev/pty[l-sL-S][0-9a-v]. */ 112181905Sed if (!(name[4] >= '0' && name[4] <= '9') && 113181905Sed !(name[4] >= 'a' && name[4] <= 'v')) 114173456Sjhb return; 115181905Sed 116181905Sed /* Create the controller device node. */ 117293825Skib make_dev_args_init(&mda); 118293825Skib mda.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_REF; 119293825Skib mda.mda_devsw = &ptydev_cdevsw; 120293825Skib mda.mda_uid = UID_ROOT; 121293825Skib mda.mda_gid = GID_WHEEL; 122293825Skib mda.mda_mode = 0666; 123293825Skib error = make_dev_s(&mda, dev, "%s", name); 124294594Skib if (error != 0) 125293825Skib *dev = NULL; 12664880Sphk} 12764880Sphk 128196480Sedstatic int 129196886Sedptmx_fdopen(struct cdev *dev __unused, int fflags, struct thread *td, 130196886Sed struct file *fp) 131196886Sed{ 132196886Sed 133196886Sed return (pts_alloc(fflags & (FREAD|FWRITE), td, fp)); 134196886Sed} 135196886Sed 136196886Sedstatic struct cdevsw ptmx_cdevsw = { 137196886Sed .d_version = D_VERSION, 138196886Sed .d_fdopen = ptmx_fdopen, 139196886Sed .d_name = "ptmx", 140196886Sed}; 141196886Sed 142196886Sedstatic int 143196480Sedpty_modevent(module_t mod, int type, void *data) 14412517Sjulian{ 145108363Sphk 146223575Sed switch(type) { 147223575Sed case MOD_LOAD: 148196480Sed EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); 149216952Skib make_dev_credf(MAKEDEV_ETERNAL_KLD, &ptmx_cdevsw, 0, NULL, 150216952Skib UID_ROOT, GID_WHEEL, 0666, "ptmx"); 151196480Sed break; 152196480Sed case MOD_SHUTDOWN: 153196480Sed break; 154196480Sed case MOD_UNLOAD: 155196480Sed /* XXX: No unloading support yet. */ 156196480Sed return (EBUSY); 157196480Sed default: 158196480Sed return (EOPNOTSUPP); 159196480Sed } 160196480Sed 161196480Sed return (0); 16212517Sjulian} 16312517Sjulian 164196480SedDEV_MODULE(pty, pty_modevent, NULL); 165