1 /*
2 * Project Acrn
3 * Acrn-dm-pty
4 *
5 * Copyright (C) 2019-2022 Intel Corporation.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <sys/stat.h>
18 #include <dirent.h>
19 #include <termios.h>
20 #include <stdbool.h>
21 #include <libgen.h>
22
23 #include "log.h"
24
25 /*
26 * Check and create the directory.
27 * To avoid symlink failure if the directory does not exist.
28 */
check_dir(const char * file)29 static int check_dir(const char *file)
30 {
31 char *tmp, *dir;
32
33 tmp = strdup(file);
34 if (!tmp) {
35 pr_err("failed to dup file, error:%s\n", strerror(errno));
36 return -1;
37 }
38
39 dir = dirname(tmp);
40 if (access(dir, F_OK) && mkdir(dir, 0666)) {
41 pr_err("failed to create dir:%s, erorr:%s\n", dir, strerror(errno));
42 free(tmp);
43 return -1;
44 }
45 free(tmp);
46 return 0;
47 }
48
49 /*
50 * Open PTY host device to used by caller and the PTY client device for virtual
51 * UART. The pair(host/client) can work as a communication channel between
52 * the caller and virtual UART.
53 */
pty_open_virtual_uart(const char * dev_name)54 int pty_open_virtual_uart(const char *dev_name)
55 {
56 int fd;
57 char *client_name;
58 struct termios attr;
59
60 fd = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_NONBLOCK);
61 if (fd < 0)
62 goto open_err;
63 if (grantpt(fd) < 0)
64 goto pty_err;
65 if (unlockpt(fd) < 0)
66 goto pty_err;
67 client_name = ptsname(fd);
68 if (!client_name)
69 goto pty_err;
70 if ((unlink(dev_name) < 0) && errno != ENOENT)
71 goto pty_err;
72 /*
73 * The check_dir restriction is that only create one directory
74 * not support multi-level directroy.
75 */
76 if (check_dir(dev_name) < 0)
77 goto pty_err;
78 if (symlink(client_name, dev_name) < 0)
79 goto pty_err;
80 if (chmod(dev_name, 0660) < 0)
81 goto attr_err;
82 if (tcgetattr(fd, &attr) < 0)
83 goto attr_err;
84 cfmakeraw(&attr);
85 attr.c_cflag |= CLOCAL;
86 if (tcsetattr(fd, TCSANOW, &attr) < 0)
87 goto attr_err;
88 return fd;
89
90 attr_err:
91 unlink(dev_name);
92 pty_err:
93 close(fd);
94 open_err:
95 return -1;
96 }
97