Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* posix */
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <sys/pty.h>
#include "lib.h"
#include "sys9.h"
#include "dir.h"

/*
 * return the name of the slave
 */
char*
ptsname(int fd)
{
        Dir *d;
        static char buf[32];

        if((d = _dirfstat(fd)) == nil || strlen(d->name) < 4){
                free(d);
                _syserrno();
                return 0;
        }
        snprintf(buf, sizeof buf, "/dev/ptty%d", atoi(d->name+4));
        free(d);
        return buf;
}

/*
 * return the name of the master
 */
char*
ptmname(int fd)
{
        Dir *d;
        static char buf[32];

        if((d = _dirfstat(fd)) == nil || strlen(d->name) < 4){
                free(d);
                _syserrno();
                return 0;
        }

        snprintf(buf, sizeof buf, "/dev/ttym%d", atoi(d->name+4));
        return buf;
}

static char ptycl[] = "/dev/ptyclone";
static char fssrv[] = "/srv/ptyfs";

static void
mkserver(void)
{
        int fd, i;
        char *argv[3];

        fd = _OPEN(fssrv, O_RDWR);
        if(_MOUNT(fd, -1, "/dev", MAFTER, "") < 0) {
                /*
                 * remove fssrv here, if it exists, to avoid a race
                 * between the loop in the default case below and the
                 * new ptyfs removing fssrv when it starts.
                 * we otherwise might be unlucky enough to open the old
                 * (hung channel) fssrv before ptyfs removes it and break
                 * out of the loop with an open fd to a hung channel?
                 */
                _CLOSE(fd);
                _REMOVE(fssrv);
                switch(_RFORK(RFPROC|RFFDG)) {
                case -1:
                        return;
                case 0:
                        argv[0] = "ptyfs";
                        argv[1] = 0;
                        _EXEC("/bin/ape/ptyfs", argv);
                        _EXITS(0);
                default:
                        for(i = 0; i < 3; i++) {
                                fd = _OPEN(fssrv, O_RDWR);
                                if(fd >= 0)
                                        break;
                                _SLEEP(1000);
                        }
                }
                if(fd < 0)
                        return;
                if(_MOUNT(fd, -1, "/dev", MAFTER, "") < 0)
                        _CLOSE(fd);
        }
        /* successful _MOUNT closes fd */
}

/*
 * allocate a new pty
 */
int
_getpty(void)
{
        struct stat sb;

        if(stat(ptycl, &sb) < 0)
                mkserver();

        return open(ptycl, O_RDWR);
}