-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.c
147 lines (121 loc) · 3.15 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "apue.h"
#include <termios.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifdef LINUX
#define OPTSTR "+d:einvr"
#else
#define OPTSTR "d:einvr"
#endif
static void set_noecho (int); /* at the end of this file */
void do_driver (char *); /* in the file driver.c */
void loop (int, int); /* in the file loop.c */
int
main (int argc, char *argv[])
{
int fdm, c, ignoreeof, interactive, noecho, verbose, returncode, status;
pid_t pid;
char *driver;
char slave_name[20];
struct termios orig_termios;
struct winsize size;
interactive = isatty (STDIN_FILENO);
ignoreeof = 0;
noecho = 0;
verbose = 0;
driver = NULL;
returncode = 0;
opterr = 0; /* don't want getopt() writing to stderr */
while ((c = getopt (argc, argv, OPTSTR)) != EOF)
{
switch (c)
{
case 'd': /* driver for stdin/stdout */
driver = optarg;
break;
case 'e': /* noecho for slave pty's line discipline */
noecho = 1;
break;
case 'i': /* ignore EOF on standard input */
ignoreeof = 1;
break;
case 'n': /* not interactive */
interactive = 0;
break;
case 'v': /* verbose */
verbose = 1;
break;
case 'r':
returncode = 1;
break;
case '?':
err_quit ("unrecognized option: -%c", optopt);
}
}
if (optind >= argc)
err_quit ("usage: pty [ -d driver -einv ] program [ arg ... ]");
if (interactive)
{ /* fetch current termios and window size */
if (tcgetattr (STDIN_FILENO, &orig_termios) < 0)
err_sys ("tcgetattr error on stdin");
if (ioctl (STDIN_FILENO, TIOCGWINSZ, (char *) &size) < 0)
err_sys ("TIOCGWINSZ error");
pid = pty_fork (&fdm, slave_name, sizeof (slave_name),
&orig_termios, &size);
}
else
{
pid = pty_fork (&fdm, slave_name, sizeof (slave_name), NULL, NULL);
}
if (pid < 0)
{
err_sys ("fork error");
}
else if (pid == 0)
{ /* child */
if (noecho)
set_noecho (STDIN_FILENO); /* stdin is slave pty */
if (execvp (argv[optind], &argv[optind]) < 0)
err_sys ("can't execute: %s", argv[optind]);
}
if (verbose)
{
fprintf (stderr, "slave name = %s\n", slave_name);
if (driver != NULL)
fprintf (stderr, "driver = %s\n", driver);
}
if (interactive && driver == NULL)
{
if (tty_raw (STDIN_FILENO) < 0) /* user's tty to raw mode */
err_sys ("tty_raw error");
if (atexit (tty_atexit) < 0) /* reset user's tty on exit */
err_sys ("atexit error");
}
if (driver)
do_driver (driver); /* changes our stdin/stdout */
loop (fdm, ignoreeof); /* copies stdin -> ptym, ptym -> stdout */
if (returncode)
{
if (waitpid (pid, &status, 0) < 0)
err_sys ("waitpid error");
if (WIFEXITED (status))
exit (WEXITSTATUS (status));
else
exit (EXIT_FAILURE);
}
exit (0);
}
static void
set_noecho (int fd) /* turn off echo (for slave pty) */
{
struct termios stermios;
if (tcgetattr (fd, &stermios) < 0)
err_sys ("tcgetattr error");
stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
/*
* Also turn off NL to CR/NL mapping on output.
*/
stermios.c_oflag &= ~(ONLCR);
if (tcsetattr (fd, TCSANOW, &stermios) < 0)
err_sys ("tcsetattr error");
}