1*dbddf429SAlex Dewar // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
375886f21SJeff Dike * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds #include <stdio.h>
724fa6c08SJeff Dike #include <stdlib.h>
81da177e4SLinus Torvalds #include <unistd.h>
91da177e4SLinus Torvalds #include <errno.h>
10cb8fa61cSJeff Dike #include <fcntl.h>
11cb8fa61cSJeff Dike #include <string.h>
121da177e4SLinus Torvalds #include <termios.h>
1375886f21SJeff Dike #include <sys/stat.h>
141da177e4SLinus Torvalds #include "chan_user.h"
1537185b33SAl Viro #include <os.h>
1637185b33SAl Viro #include <um_malloc.h>
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds struct pty_chan {
191da177e4SLinus Torvalds void (*announce)(char *dev_name, int dev);
201da177e4SLinus Torvalds int dev;
211da177e4SLinus Torvalds int raw;
221da177e4SLinus Torvalds struct termios tt;
231da177e4SLinus Torvalds char dev_name[sizeof("/dev/pts/0123456\0")];
241da177e4SLinus Torvalds };
251da177e4SLinus Torvalds
pty_chan_init(char * str,int device,const struct chan_opts * opts)265e7672ecSJeff Dike static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
271da177e4SLinus Torvalds {
281da177e4SLinus Torvalds struct pty_chan *data;
291da177e4SLinus Torvalds
3043f5b308SJeff Dike data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
3175886f21SJeff Dike if (data == NULL)
3275886f21SJeff Dike return NULL;
3375886f21SJeff Dike
341da177e4SLinus Torvalds *data = ((struct pty_chan) { .announce = opts->announce,
351da177e4SLinus Torvalds .dev = device,
361da177e4SLinus Torvalds .raw = opts->raw });
3775886f21SJeff Dike return data;
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds
pts_open(int input,int output,int primary,void * d,char ** dev_out)401da177e4SLinus Torvalds static int pts_open(int input, int output, int primary, void *d,
411da177e4SLinus Torvalds char **dev_out)
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds struct pty_chan *data = d;
441da177e4SLinus Torvalds char *dev;
451da177e4SLinus Torvalds int fd, err;
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds fd = get_pty();
481da177e4SLinus Torvalds if (fd < 0) {
49b4fd310eSJeff Dike err = -errno;
5075886f21SJeff Dike printk(UM_KERN_ERR "open_pts : Failed to open pts\n");
51b4fd310eSJeff Dike return err;
521da177e4SLinus Torvalds }
5375886f21SJeff Dike
541da177e4SLinus Torvalds if (data->raw) {
551da177e4SLinus Torvalds CATCH_EINTR(err = tcgetattr(fd, &data->tt));
561da177e4SLinus Torvalds if (err)
57e99525f9SJeff Dike goto out_close;
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds err = raw(fd);
601da177e4SLinus Torvalds if (err)
61e99525f9SJeff Dike goto out_close;
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds dev = ptsname(fd);
651da177e4SLinus Torvalds sprintf(data->dev_name, "%s", dev);
661da177e4SLinus Torvalds *dev_out = data->dev_name;
6775886f21SJeff Dike
681da177e4SLinus Torvalds if (data->announce)
691da177e4SLinus Torvalds (*data->announce)(dev, data->dev);
7075886f21SJeff Dike
7175886f21SJeff Dike return fd;
72e99525f9SJeff Dike
73e99525f9SJeff Dike out_close:
74e99525f9SJeff Dike close(fd);
75e99525f9SJeff Dike return err;
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds
getmaster(char * line)781da177e4SLinus Torvalds static int getmaster(char *line)
791da177e4SLinus Torvalds {
8075886f21SJeff Dike struct stat buf;
811da177e4SLinus Torvalds char *pty, *bank, *cp;
821da177e4SLinus Torvalds int master, err;
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds pty = &line[strlen("/dev/ptyp")];
851da177e4SLinus Torvalds for (bank = "pqrs"; *bank; bank++) {
861da177e4SLinus Torvalds line[strlen("/dev/pty")] = *bank;
871da177e4SLinus Torvalds *pty = '0';
8875886f21SJeff Dike /* Did we hit the end ? */
8975886f21SJeff Dike if ((stat(line, &buf) < 0) && (errno == ENOENT))
901da177e4SLinus Torvalds break;
9175886f21SJeff Dike
921da177e4SLinus Torvalds for (cp = "0123456789abcdef"; *cp; cp++) {
931da177e4SLinus Torvalds *pty = *cp;
9475886f21SJeff Dike master = open(line, O_RDWR);
951da177e4SLinus Torvalds if (master >= 0) {
961da177e4SLinus Torvalds char *tp = &line[strlen("/dev/")];
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds /* verify slave side is usable */
991da177e4SLinus Torvalds *tp = 't';
10075886f21SJeff Dike err = access(line, R_OK | W_OK);
1011da177e4SLinus Torvalds *tp = 'p';
10275886f21SJeff Dike if (!err)
10375886f21SJeff Dike return master;
10475886f21SJeff Dike close(master);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds }
10875886f21SJeff Dike
10975886f21SJeff Dike printk(UM_KERN_ERR "getmaster - no usable host pty devices\n");
11075886f21SJeff Dike return -ENOENT;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds
pty_open(int input,int output,int primary,void * d,char ** dev_out)1131da177e4SLinus Torvalds static int pty_open(int input, int output, int primary, void *d,
1141da177e4SLinus Torvalds char **dev_out)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds struct pty_chan *data = d;
1171da177e4SLinus Torvalds int fd, err;
1181da177e4SLinus Torvalds char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds fd = getmaster(dev);
1211da177e4SLinus Torvalds if (fd < 0)
12275886f21SJeff Dike return fd;
1231da177e4SLinus Torvalds
1241da177e4SLinus Torvalds if (data->raw) {
1251da177e4SLinus Torvalds err = raw(fd);
126e99525f9SJeff Dike if (err) {
127e99525f9SJeff Dike close(fd);
12875886f21SJeff Dike return err;
1291da177e4SLinus Torvalds }
130e99525f9SJeff Dike }
1311da177e4SLinus Torvalds
13275886f21SJeff Dike if (data->announce)
13375886f21SJeff Dike (*data->announce)(dev, data->dev);
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds sprintf(data->dev_name, "%s", dev);
1361da177e4SLinus Torvalds *dev_out = data->dev_name;
13775886f21SJeff Dike
13875886f21SJeff Dike return fd;
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds
1415e7672ecSJeff Dike const struct chan_ops pty_ops = {
1421da177e4SLinus Torvalds .type = "pty",
1431da177e4SLinus Torvalds .init = pty_chan_init,
1441da177e4SLinus Torvalds .open = pty_open,
1451da177e4SLinus Torvalds .close = generic_close,
1461da177e4SLinus Torvalds .read = generic_read,
1471da177e4SLinus Torvalds .write = generic_write,
148fd9bc53bSPaolo 'Blaisorblade' Giarrusso .console_write = generic_console_write,
1491da177e4SLinus Torvalds .window_size = generic_window_size,
1501da177e4SLinus Torvalds .free = generic_free,
1511da177e4SLinus Torvalds .winch = 0,
1521da177e4SLinus Torvalds };
1531da177e4SLinus Torvalds
1545e7672ecSJeff Dike const struct chan_ops pts_ops = {
1551da177e4SLinus Torvalds .type = "pts",
1561da177e4SLinus Torvalds .init = pty_chan_init,
1571da177e4SLinus Torvalds .open = pts_open,
1581da177e4SLinus Torvalds .close = generic_close,
1591da177e4SLinus Torvalds .read = generic_read,
1601da177e4SLinus Torvalds .write = generic_write,
161fd9bc53bSPaolo 'Blaisorblade' Giarrusso .console_write = generic_console_write,
1621da177e4SLinus Torvalds .window_size = generic_window_size,
1631da177e4SLinus Torvalds .free = generic_free,
1641da177e4SLinus Torvalds .winch = 0,
1651da177e4SLinus Torvalds };
166