xref: /openbmc/linux/arch/um/drivers/pty.c (revision 976e3645923bdd2fe7893aae33fd7a21098bfb28)
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