pty.c 3.2 KB

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