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