123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-12-07 Shell init ver.
- */
- #include <ipc/condvar.h>
- #include <rid_bitmap.h>
- #include <terminal/terminal.h>
- #include <terminal/tty_internal.h>
- #include <ptyfs.h>
- #include <rtthread.h>
- /*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
- * All rights reserved.
- *
- * Portions of this software were developed under sponsorship from Snow
- * B.V., the Netherlands.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #define PTS_EXTERNAL
- /*
- * Per-PTS structure.
- *
- * List of locks
- * (t) locked by tty_lock()
- * (c) const until freeing
- */
- struct pts_softc
- {
- int pts_unit; /* (c) Device unit number. */
- unsigned int pts_flags; /* (t) Device flags. */
- #define PTS_PKT 0x1 /* Packet mode. */
- #define PTS_FINISHED 0x2 /* Return errors on read()/write(). */
- #define PTS_PTLOCKED 0x4 /* ioctl %TIOCSPTLCK/%TIOCGPTLCK */
- char pts_pkt; /* (t) Unread packet mode data. */
- struct rt_condvar pts_inwait; /* (t) Blocking write() on master. */
- struct rt_wqueue pts_inpoll; /* (t) Select queue for write(). */
- struct rt_condvar pts_outwait; /* (t) Blocking read() on master. */
- struct rt_wqueue pts_outpoll; /* (t) Select queue for read(). */
- struct ucred *pts_cred; /* (c) Resource limit. */
- rt_device_t pts_master; /** (c) Master device.
- * (Note: in rtsmart kernel, we support
- * multi-instance ptmx )
- */
- };
- /**
- * Controller-side file operations.
- * (P)seudo-(T)erminal (M)ultiple(X)er
- */
- static int ptsdev_read(struct lwp_tty *tp, struct uio *uio,
- struct ucred *active_cred, int oflags,
- struct rt_thread *td)
- {
- struct pts_softc *psc = tty_softc(tp);
- int error = 0;
- char pkt;
- if (uio->uio_resid == 0)
- return (0);
- tty_lock(tp);
- for (;;)
- {
- /*
- * Implement packet mode. When packet mode is turned on,
- * the first byte contains a bitmask of events that
- * occurred (start, stop, flush, window size, etc).
- */
- if (psc->pts_flags & PTS_PKT && psc->pts_pkt)
- {
- pkt = psc->pts_pkt;
- psc->pts_pkt = 0;
- tty_unlock(tp);
- error = uiomove(&pkt, 1, uio);
- return (error);
- }
- /*
- * Transmit regular data.
- *
- * XXX: We shouldn't use ttydisc_getc_poll()! Even
- * though in this implementation, there is likely going
- * to be data, we should just call ttydisc_getc_uio()
- * and use its return value to sleep.
- */
- if (ttydisc_getc_poll(tp))
- {
- if (psc->pts_flags & PTS_PKT)
- {
- /*
- * XXX: Small race. Fortunately PTY
- * consumers aren't multithreaded.
- */
- tty_unlock(tp);
- pkt = TIOCPKT_DATA;
- error = uiomove(&pkt, 1, uio);
- if (error)
- return (error);
- tty_lock(tp);
- }
- error = ttydisc_getc_uio(tp, uio);
- break;
- }
- /* Maybe the device isn't used anyway. */
- if (psc->pts_flags & PTS_FINISHED)
- break;
- /* Wait for more data. */
- if (oflags & O_NONBLOCK)
- {
- error = EWOULDBLOCK;
- break;
- }
- error = cv_wait_sig(&psc->pts_outwait, tp->t_mtx);
- if (error != 0)
- break;
- }
- tty_unlock(tp);
- return (error);
- }
- static int ptsdev_write(struct lwp_tty *tp, struct uio *uio,
- struct ucred *active_cred, int oflags,
- struct rt_thread *td)
- {
- struct pts_softc *psc = tty_softc(tp);
- char ib[256], *ibstart;
- size_t iblen, rintlen;
- int error = 0;
- if (uio->uio_resid == 0)
- return (0);
- for (;;)
- {
- ibstart = ib;
- iblen = MIN(uio->uio_resid, sizeof ib);
- error = uiomove(ib, iblen, uio);
- tty_lock(tp);
- if (error != 0)
- {
- iblen = 0;
- goto done;
- }
- /*
- * When possible, avoid the slow path. rint_bypass()
- * copies all input to the input queue at once.
- */
- MPASS(iblen > 0);
- do
- {
- rintlen = ttydisc_rint_simple(tp, ibstart, iblen);
- ibstart += rintlen;
- iblen -= rintlen;
- if (iblen == 0)
- {
- /* All data written. */
- break;
- }
- /* Maybe the device isn't used anyway. */
- if (psc->pts_flags & PTS_FINISHED)
- {
- error = -EIO;
- goto done;
- }
- /* Wait for more data. */
- if (oflags & O_NONBLOCK)
- {
- error = -EWOULDBLOCK;
- goto done;
- }
- /* Wake up users on the slave side. */
- ttydisc_rint_done(tp);
- error = cv_wait_sig(&psc->pts_inwait, tp->t_mtx);
- if (error != 0)
- goto done;
- } while (iblen > 0);
- if (uio->uio_resid == 0)
- break;
- tty_unlock(tp);
- }
- done:
- ttydisc_rint_done(tp);
- tty_unlock(tp);
- /*
- * Don't account for the part of the buffer that we couldn't
- * pass to the TTY.
- */
- uio->uio_resid += iblen;
- return (error);
- }
- static int ptsdev_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, void *data,
- struct ucred *active_cred, int fflags,
- struct rt_thread *td)
- {
- struct pts_softc *psc = tty_softc(tp);
- int error = 0, sig;
- switch (cmd)
- {
- #ifdef USING_BSD_IOCTL_EXT
- case FIODTYPE:
- *(int *)data = D_TTY;
- return (0);
- #endif
- case FIONBIO:
- /* This device supports non-blocking operation. */
- return (0);
- case FIONREAD:
- tty_lock(tp);
- if (psc->pts_flags & PTS_FINISHED)
- {
- /* Force read() to be called. */
- *(int *)data = 1;
- }
- else
- {
- *(int *)data = ttydisc_getc_poll(tp);
- }
- tty_unlock(tp);
- return (0);
- #ifdef USING_BSD_IOCTL_EXT
- case FIODGNAME:
- #ifdef COMPAT_FREEBSD32
- case FIODGNAME_32:
- #endif
- {
- struct fiodgname_arg *fgn;
- const char *p;
- int i;
- /* Reverse device name lookups, for ptsname() and ttyname(). */
- fgn = data;
- p = tty_devname(tp);
- i = strlen(p) + 1;
- if (i > fgn->len)
- return -EINVAL;
- return (copyout(p, fiodgname_buf_get_ptr(fgn, cmd), i));
- }
- #endif
- /*
- * We need to implement TIOCGPGRP and TIOCGSID here again. When
- * called on the pseudo-terminal master, it should not check if
- * the terminal is the foreground terminal of the calling
- * process.
- *
- * TIOCGETA is also implemented here. Various Linux PTY routines
- * often call isatty(), which is implemented by tcgetattr().
- */
- case TIOCGETA:
- /* Obtain terminal flags through tcgetattr(). */
- tty_lock(tp);
- *(struct termios *)data = tp->t_termios;
- tty_unlock(tp);
- return (0);
- case TIOCSETAF:
- case TIOCSETAW:
- /*
- * We must make sure we turn tcsetattr() calls of TCSAFLUSH and
- * TCSADRAIN into something different. If an application would
- * call TCSAFLUSH or TCSADRAIN on the master descriptor, it may
- * deadlock waiting for all data to be read.
- */
- cmd = TIOCSETA;
- break;
- case TIOCGPTN:
- /*
- * Get the device unit number.
- */
- if (psc->pts_unit < 0)
- return -ENOTTY;
- *(unsigned int *)data = psc->pts_unit;
- return (0);
- case TIOCGPGRP:
- /* Get the foreground process group ID. */
- tty_lock(tp);
- if (tp->t_pgrp != NULL)
- *(int *)data = tp->t_pgrp->pgid;
- else
- *(int *)data = NO_PID;
- tty_unlock(tp);
- return (0);
- case TIOCGSID:
- /* Get the session leader process ID. */
- tty_lock(tp);
- if (tp->t_session == NULL)
- error = -ENOTTY;
- else
- *(int *)data = tp->t_session->sid;
- tty_unlock(tp);
- return (error);
- #ifdef USING_BSD_IOCTL_EXT
- case TIOCPTMASTER:
- /* Yes, we are a pseudo-terminal master. */
- return (0);
- #endif /* USING_BSD_IOCTL_EXT */
- case TIOCSIG:
- /* Signal the foreground process group. */
- sig = *(int *)data;
- if (sig < 1 || sig >= _LWP_NSIG)
- return -EINVAL;
- tty_lock(tp);
- lwp_tty_signal_pgrp(tp, sig);
- tty_unlock(tp);
- return (0);
- case TIOCPKT:
- /* Enable/disable packet mode. */
- tty_lock(tp);
- if (*(int *)data)
- psc->pts_flags |= PTS_PKT;
- else
- psc->pts_flags &= ~PTS_PKT;
- tty_unlock(tp);
- return (0);
- }
- /* Just redirect this ioctl to the slave device. */
- tty_lock(tp);
- error = tty_ioctl(tp, cmd, data, fflags, td);
- tty_unlock(tp);
- if (error == -ENOIOCTL)
- error = -ENOTTY;
- return error;
- }
- static int ptsdev_poll(struct lwp_tty *tp, struct rt_pollreq *req,
- struct ucred *active_cred, struct rt_thread *td)
- {
- struct pts_softc *psc = tty_softc(tp);
- int revents = 0;
- int events = req->_key;
- tty_lock(tp);
- if (psc->pts_flags & PTS_FINISHED)
- {
- /* Slave device is not opened. */
- tty_unlock(tp);
- return ((events & (POLLIN | POLLRDNORM)) | POLLHUP);
- }
- if (events & (POLLIN | POLLRDNORM))
- {
- /* See if we can getc something. */
- if (ttydisc_getc_poll(tp) || (psc->pts_flags & PTS_PKT && psc->pts_pkt))
- revents |= events & (POLLIN | POLLRDNORM);
- }
- if (events & (POLLOUT | POLLWRNORM))
- {
- /* See if we can rint something. */
- if (ttydisc_rint_poll(tp))
- revents |= events & (POLLOUT | POLLWRNORM);
- }
- /*
- * No need to check for POLLHUP here. This device cannot be used
- * as a callout device, which means we always have a carrier,
- * because the master is.
- */
- if (revents == 0)
- {
- /*
- * This code might look misleading, but the naming of
- * poll events on this side is the opposite of the slave
- * device.
- */
- if (events & (POLLIN | POLLRDNORM))
- rt_poll_add(&psc->pts_outpoll, req);
- if (events & (POLLOUT | POLLWRNORM))
- rt_poll_add(&psc->pts_inpoll, req);
- }
- tty_unlock(tp);
- return (revents);
- }
- #if USING_BSD_KQUEUE
- /*
- * kqueue support.
- */
- static void pts_kqops_read_detach(struct knote *kn)
- {
- struct file *fp = kn->kn_fp;
- struct lwp_tty *tp = fp->f_data;
- struct pts_softc *psc = tty_softc(tp);
- knlist_remove(&psc->pts_outpoll.si_note, kn, 0);
- }
- static int pts_kqops_read_event(struct knote *kn, long hint)
- {
- struct file *fp = kn->kn_fp;
- struct lwp_tty *tp = fp->f_data;
- struct pts_softc *psc = tty_softc(tp);
- if (psc->pts_flags & PTS_FINISHED)
- {
- kn->kn_flags |= EV_EOF;
- return (1);
- }
- else
- {
- kn->kn_data = ttydisc_getc_poll(tp);
- return (kn->kn_data > 0);
- }
- }
- static void pts_kqops_write_detach(struct knote *kn)
- {
- struct file *fp = kn->kn_fp;
- struct lwp_tty *tp = fp->f_data;
- struct pts_softc *psc = tty_softc(tp);
- knlist_remove(&psc->pts_inpoll.si_note, kn, 0);
- }
- static int pts_kqops_write_event(struct knote *kn, long hint)
- {
- struct file *fp = kn->kn_fp;
- struct lwp_tty *tp = fp->f_data;
- struct pts_softc *psc = tty_softc(tp);
- if (psc->pts_flags & PTS_FINISHED)
- {
- kn->kn_flags |= EV_EOF;
- return (1);
- }
- else
- {
- kn->kn_data = ttydisc_rint_poll(tp);
- return (kn->kn_data > 0);
- }
- }
- static struct filterops pts_kqops_read = {
- .f_isfd = 1,
- .f_detach = pts_kqops_read_detach,
- .f_event = pts_kqops_read_event,
- };
- static struct filterops pts_kqops_write = {
- .f_isfd = 1,
- .f_detach = pts_kqops_write_detach,
- .f_event = pts_kqops_write_event,
- };
- static int ptsdev_kqfilter(struct file *fp, struct knote *kn)
- {
- struct lwp_tty *tp = fp->f_data;
- struct pts_softc *psc = tty_softc(tp);
- int error = 0;
- tty_lock(tp);
- switch (kn->kn_filter)
- {
- case EVFILT_READ:
- kn->kn_fop = &pts_kqops_read;
- knlist_add(&psc->pts_outpoll.si_note, kn, 1);
- break;
- case EVFILT_WRITE:
- kn->kn_fop = &pts_kqops_write;
- knlist_add(&psc->pts_inpoll.si_note, kn, 1);
- break;
- default:
- error = EINVAL;
- break;
- }
- tty_unlock(tp);
- return (error);
- }
- #endif
- #if USING_BSD_STAT
- static int ptsdev_stat(struct file *fp, struct stat *sb,
- struct ucred *active_cred)
- {
- struct lwp_tty *tp = fp->f_data;
- #ifdef PTS_EXTERNAL
- struct pts_softc *psc = tty_softc(tp);
- #endif /* PTS_EXTERNAL */
- struct cdev *dev = tp->t_dev;
- /*
- * According to POSIX, we must implement an fstat(). This also
- * makes this implementation compatible with Linux binaries,
- * because Linux calls fstat() on the pseudo-terminal master to
- * obtain st_rdev.
- *
- * XXX: POSIX also mentions we must fill in st_dev, but how?
- */
- bzero(sb, sizeof *sb);
- #ifdef PTS_EXTERNAL
- if (psc->pts_cdev != NULL)
- sb->st_ino = sb->st_rdev = dev2udev(psc->pts_cdev);
- else
- #endif /* PTS_EXTERNAL */
- sb->st_ino = sb->st_rdev = tty_udev(tp);
- sb->st_atim = dev->si_atime;
- sb->st_ctim = dev->si_ctime;
- sb->st_mtim = dev->si_mtime;
- sb->st_uid = dev->si_uid;
- sb->st_gid = dev->si_gid;
- sb->st_mode = dev->si_mode | S_IFCHR;
- return (0);
- }
- #endif
- static int ptsdev_close(struct lwp_tty *tp, struct rt_thread *td)
- {
- /* Deallocate TTY device. */
- tty_lock(tp);
- tty_rel_gone(tp);
- #ifdef USING_BSD_VNODE
- /* TODO: consider the vnode operation on DFS */
- /*
- * Open of /dev/ptmx or /dev/ptyXX changes the type of file
- * from DTYPE_VNODE to DTYPE_PTS. vn_open() increases vnode
- * use count, we need to decrement it, and possibly do other
- * required cleanup.
- */
- if (fp->f_vnode != NULL)
- return (vnops.fo_close(fp, td));
- #endif /* USING_BSD_VNODE */
- return 0;
- }
- #ifdef USING_BSD_KINFO
- static int ptsdev_fill_kinfo(struct file *fp, struct kinfo_file *kif,
- struct filedesc *fdp)
- {
- struct lwp_tty *tp;
- kif->kf_type = KF_TYPE_PTS;
- tp = fp->f_data;
- kif->kf_un.kf_pts.kf_pts_dev = tty_udev(tp);
- kif->kf_un.kf_pts.kf_pts_dev_freebsd11 =
- kif->kf_un.kf_pts.kf_pts_dev; /* truncate */
- strlcpy(kif->kf_path, tty_devname(tp), sizeof(kif->kf_path));
- return (0);
- }
- #endif
- struct bsd_fileops bsd_ptsdev_methods = {
- .fo_read = ptsdev_read,
- .fo_write = ptsdev_write,
- // .fo_truncate = invfo_truncate,
- .fo_ioctl = ptsdev_ioctl,
- .fo_poll = ptsdev_poll,
- // .fo_kqfilter = ptsdev_kqfilter,
- // .fo_stat = ptsdev_stat,
- .fo_close = ptsdev_close,
- // .fo_chmod = invfo_chmod,
- // .fo_chown = invfo_chown,
- // .fo_sendfile = invfo_sendfile,
- // .fo_fill_kinfo = ptsdev_fill_kinfo,
- .fo_flags = DFLAG_PASSABLE,
- };
- /*
- * Driver-side hooks.
- */
- static void ptsdrv_outwakeup(struct lwp_tty *tp)
- {
- struct pts_softc *psc = tty_softc(tp);
- cv_broadcast(&psc->pts_outwait);
- rt_wqueue_wakeup_all(&psc->pts_outpoll, (void *)POLLIN);
- }
- static void ptsdrv_inwakeup(struct lwp_tty *tp)
- {
- struct pts_softc *psc = tty_softc(tp);
- cv_broadcast(&psc->pts_inwait);
- rt_wqueue_wakeup_all(&psc->pts_inpoll, (void *)POLLOUT);
- }
- static int ptsdrv_open(struct lwp_tty *tp)
- {
- struct pts_softc *psc = tty_softc(tp);
- /* for ioctl(TIOCSPTLCK) */
- if (psc->pts_flags & PTS_PTLOCKED)
- return -EIO;
- psc->pts_flags &= ~PTS_FINISHED;
- return 0;
- }
- static void ptsdrv_close(struct lwp_tty *tp)
- {
- struct pts_softc *psc = tty_softc(tp);
- /* Wake up any blocked readers/writers. */
- psc->pts_flags |= PTS_FINISHED;
- ptsdrv_outwakeup(tp);
- ptsdrv_inwakeup(tp);
- }
- static void ptsdrv_pktnotify(struct lwp_tty *tp, char event)
- {
- struct pts_softc *psc = tty_softc(tp);
- /*
- * Clear conflicting flags.
- */
- switch (event)
- {
- case TIOCPKT_STOP:
- psc->pts_pkt &= ~TIOCPKT_START;
- break;
- case TIOCPKT_START:
- psc->pts_pkt &= ~TIOCPKT_STOP;
- break;
- case TIOCPKT_NOSTOP:
- psc->pts_pkt &= ~TIOCPKT_DOSTOP;
- break;
- case TIOCPKT_DOSTOP:
- psc->pts_pkt &= ~TIOCPKT_NOSTOP;
- break;
- }
- psc->pts_pkt |= event;
- /**
- * Note: on smart, we don't wakeup master until it's willing to accept
- * packet event. Because on poll, we setup POLLIN for PTS_PKT only. So There
- * is a chance when we wakeup ipc but we can't wakeup user again. Since
- * current wakeup will remove the wakequeue node on the meanwhile
- */
- if (psc->pts_flags & PTS_PKT)
- ptsdrv_outwakeup(tp);
- }
- static void ptsdrv_free(void *softc)
- {
- struct pts_softc *psc = softc;
- /* Make device number available again. */
- if (psc->pts_unit >= 0)
- ptyfs_unregister_pts(psc->pts_master, psc->pts_unit);
- #ifdef USING_BSD_UCRED
- chgptscnt(psc->pts_cred->cr_ruidinfo, -1, 0);
- racct_sub_cred(psc->pts_cred, RACCT_NPTS, 1);
- crfree(psc->pts_cred);
- #endif
- rt_wqueue_wakeup_all(&psc->pts_inpoll, (void *)POLLHUP);
- rt_wqueue_wakeup_all(&psc->pts_outpoll, (void *)POLLHUP);
- rt_free(psc);
- }
- static struct lwp_ttydevsw pts_class = {
- .tsw_flags = TF_NOPREFIX,
- .tsw_outwakeup = ptsdrv_outwakeup,
- .tsw_inwakeup = ptsdrv_inwakeup,
- .tsw_open = ptsdrv_open,
- .tsw_close = ptsdrv_close,
- .tsw_pktnotify = ptsdrv_pktnotify,
- .tsw_free = ptsdrv_free,
- };
- int pts_alloc(int fflags, struct rt_thread *td, struct dfs_file *ptm_file)
- {
- int unit;
- struct lwp_tty *tp;
- struct pts_softc *psc;
- char name_buf[DIRENT_NAME_MAX];
- const char *rootpath;
- rt_device_t ptmx_device = ptm_file->vnode->data;
- #ifdef USING_BSD_UCRED
- struct rt_lwp *p = td->lwp;
- int ok, error;
- struct ucred *cred = td->td_ucred;
- #endif
- /* Resource limiting. */
- #ifdef USING_BSD_UCRED
- LWP_LOCK(p);
- error = racct_add(p, RACCT_NPTS, 1);
- if (error != 0)
- {
- LWP_UNLOCK(p);
- return -EAGAIN;
- }
- ok = chgptscnt(cred->cr_ruidinfo, 1, lim_cur(td, RLIMIT_NPTS));
- if (!ok)
- {
- racct_sub(p, RACCT_NPTS, 1);
- LWP_UNLOCK(p);
- return -EAGAIN;
- }
- LWP_UNLOCK(p);
- #endif
- /* Allocate TTY and softc. */
- psc = rt_calloc(1, sizeof(struct pts_softc));
- cv_init(&psc->pts_inwait, "ptsin");
- cv_init(&psc->pts_outwait, "ptsout");
- rt_wqueue_init(&psc->pts_inpoll);
- rt_wqueue_init(&psc->pts_outpoll);
- psc->pts_master = ptmx_device;
- #ifdef USING_BSD_UCRED
- psc->pts_cred = crhold(cred);
- #else
- psc->pts_cred = 0;
- #endif
- tp = lwp_tty_create(&pts_class, psc);
- if (!tp)
- {
- rt_free(psc);
- rt_condvar_detach(&psc->pts_inwait);
- rt_condvar_detach(&psc->pts_outwait);
- return -ENOMEM;
- }
- /* Try to allocate a new pts uint*/
- unit = ptyfs_register_pts(ptmx_device, &tp->parent);
- if (unit < 0)
- {
- #ifdef USING_BSD_UCRED
- racct_sub(p, RACCT_NPTS, 1);
- chgptscnt(cred->cr_ruidinfo, -1, 0);
- #endif
- lwp_tty_delete(tp);
- return -EAGAIN;
- }
- psc->pts_unit = unit;
- /* Expose the slave device as well. */
- #ifdef USING_BSD_UCRED
- tty_makedev(tp, td->td_ucred, "pts/%u", psc->pts_unit);
- #else
- rootpath = ptyfs_get_rootpath(ptmx_device);
- RT_ASSERT(rootpath[strlen(rootpath) - 1] != '/');
- snprintf(name_buf, DIRENT_NAME_MAX, "%s/%d", rootpath, psc->pts_unit);
- /* setup the pts */
- lwp_tty_register(tp, name_buf);
- /* now this file operating on new pty */
- ptm_file->data = tp;
- #endif
- return 0;
- }
- void pts_set_lock(lwp_tty_t pts, rt_bool_t is_lock)
- {
- struct pts_softc *psc = tty_softc(pts);
- if (is_lock)
- psc->pts_flags |= PTS_PTLOCKED;
- else
- psc->pts_flags &= ~PTS_PTLOCKED;
- }
- rt_bool_t pts_is_locked(lwp_tty_t pts)
- {
- struct pts_softc *psc = tty_softc(pts);
- return !!(psc->pts_flags & PTS_PTLOCKED);
- }
- int pts_get_pktmode(lwp_tty_t pts)
- {
- struct pts_softc *psc = tty_softc(pts);
- return !!(psc->pts_flags & PTS_PKT);
- }
|