Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pty.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <string.h>
12 #include <termios.h>
13 #include <sys/stat.h>
14 #include "chan_user.h"
15 #include <os.h>
16 #include <um_malloc.h>
17 
18 struct pty_chan {
19  void (*announce)(char *dev_name, int dev);
20  int dev;
21  int raw;
22  struct termios tt;
23  char dev_name[sizeof("/dev/pts/0123456\0")];
24 };
25 
26 static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
27 {
28  struct pty_chan *data;
29 
30  data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
31  if (data == NULL)
32  return NULL;
33 
34  *data = ((struct pty_chan) { .announce = opts->announce,
35  .dev = device,
36  .raw = opts->raw });
37  return data;
38 }
39 
40 static int pts_open(int input, int output, int primary, void *d,
41  char **dev_out)
42 {
43  struct pty_chan *data = d;
44  char *dev;
45  int fd, err;
46 
47  fd = get_pty();
48  if (fd < 0) {
49  err = -errno;
50  printk(UM_KERN_ERR "open_pts : Failed to open pts\n");
51  return err;
52  }
53 
54  if (data->raw) {
55  CATCH_EINTR(err = tcgetattr(fd, &data->tt));
56  if (err)
57  goto out_close;
58 
59  err = raw(fd);
60  if (err)
61  goto out_close;
62  }
63 
64  dev = ptsname(fd);
65  sprintf(data->dev_name, "%s", dev);
66  *dev_out = data->dev_name;
67 
68  if (data->announce)
69  (*data->announce)(dev, data->dev);
70 
71  return fd;
72 
73 out_close:
74  close(fd);
75  return err;
76 }
77 
78 static int getmaster(char *line)
79 {
80  struct stat buf;
81  char *pty, *bank, *cp;
82  int master, err;
83 
84  pty = &line[strlen("/dev/ptyp")];
85  for (bank = "pqrs"; *bank; bank++) {
86  line[strlen("/dev/pty")] = *bank;
87  *pty = '0';
88  /* Did we hit the end ? */
89  if ((stat(line, &buf) < 0) && (errno == ENOENT))
90  break;
91 
92  for (cp = "0123456789abcdef"; *cp; cp++) {
93  *pty = *cp;
94  master = open(line, O_RDWR);
95  if (master >= 0) {
96  char *tp = &line[strlen("/dev/")];
97 
98  /* verify slave side is usable */
99  *tp = 't';
100  err = access(line, R_OK | W_OK);
101  *tp = 'p';
102  if (!err)
103  return master;
104  close(master);
105  }
106  }
107  }
108 
109  printk(UM_KERN_ERR "getmaster - no usable host pty devices\n");
110  return -ENOENT;
111 }
112 
113 static int pty_open(int input, int output, int primary, void *d,
114  char **dev_out)
115 {
116  struct pty_chan *data = d;
117  int fd, err;
118  char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
119 
120  fd = getmaster(dev);
121  if (fd < 0)
122  return fd;
123 
124  if (data->raw) {
125  err = raw(fd);
126  if (err) {
127  close(fd);
128  return err;
129  }
130  }
131 
132  if (data->announce)
133  (*data->announce)(dev, data->dev);
134 
135  sprintf(data->dev_name, "%s", dev);
136  *dev_out = data->dev_name;
137 
138  return fd;
139 }
140 
141 const struct chan_ops pty_ops = {
142  .type = "pty",
143  .init = pty_chan_init,
144  .open = pty_open,
145  .close = generic_close,
146  .read = generic_read,
147  .write = generic_write,
148  .console_write = generic_console_write,
149  .window_size = generic_window_size,
150  .free = generic_free,
151  .winch = 0,
152 };
153 
154 const struct chan_ops pts_ops = {
155  .type = "pts",
156  .init = pty_chan_init,
157  .open = pts_open,
158  .close = generic_close,
159  .read = generic_read,
160  .write = generic_write,
161  .console_write = generic_console_write,
162  .window_size = generic_window_size,
163  .free = generic_free,
164  .winch = 0,
165 };