acrn-hypervisor/devicemodel/hw/platform/pty_vuart.c

97 lines
1.9 KiB
C

/*
* Project Acrn
* Acrn-dm-pty
*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <termios.h>
#include <stdbool.h>
#include <libgen.h>
#include "log.h"
/*
* Check and create the directory.
* To avoid symlink failure if the directory does not exist.
*/
static int check_dir(const char *file)
{
char *tmp, *dir;
tmp = strdup(file);
if (!tmp) {
pr_err("failed to dup file, error:%s\n", strerror(errno));
return -1;
}
dir = dirname(tmp);
if (access(dir, F_OK) && mkdir(dir, 0666)) {
pr_err("failed to create dir:%s, erorr:%s\n", dir, strerror(errno));
free(tmp);
return -1;
}
free(tmp);
return 0;
}
/*
* Open PTY host device to used by caller and the PTY client device for virtual
* UART. The pair(host/client) can work as a communication channel between
* the caller and virtual UART.
*/
int pty_open_virtual_uart(const char *dev_name)
{
int fd;
char *client_name;
struct termios attr;
fd = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0)
goto open_err;
if (grantpt(fd) < 0)
goto pty_err;
if (unlockpt(fd) < 0)
goto pty_err;
client_name = ptsname(fd);
if (!client_name)
goto pty_err;
if ((unlink(dev_name) < 0) && errno != ENOENT)
goto pty_err;
/*
* The check_dir restriction is that only create one directory
* not support multi-level directroy.
*/
if (check_dir(dev_name) < 0)
goto pty_err;
if (symlink(client_name, dev_name) < 0)
goto pty_err;
if (chmod(dev_name, 0660) < 0)
goto attr_err;
if (tcgetattr(fd, &attr) < 0)
goto attr_err;
cfmakeraw(&attr);
attr.c_cflag |= CLOCAL;
if (tcsetattr(fd, TCSANOW, &attr) < 0)
goto attr_err;
return fd;
attr_err:
unlink(dev_name);
pty_err:
close(fd);
open_err:
return -1;
}