/src/util-linux/lib/ttyutils.c
Line | Count | Source |
1 | | /* |
2 | | * No copyright is claimed. This code is in the public domain; do with |
3 | | * it what you wish. |
4 | | * |
5 | | * Written by Karel Zak <kzak@redhat.com> |
6 | | */ |
7 | | #include <ctype.h> |
8 | | #include <unistd.h> |
9 | | |
10 | | #ifdef HAVE_GETTTYNAM |
11 | | # include <ttyent.h> |
12 | | #endif |
13 | | |
14 | | #include "c.h" |
15 | | #include "ttyutils.h" |
16 | | |
17 | | #ifdef __linux__ |
18 | | # ifndef DEFAULT_VCTERM |
19 | 0 | # define DEFAULT_VCTERM "linux" |
20 | | # endif |
21 | | # if defined (__s390__) || defined (__s390x__) |
22 | | # define DEFAULT_TTYS0 "dumb" |
23 | | # define DEFAULT_TTY32 "ibm327x" |
24 | | # define DEFAULT_TTYS1 "vt220" |
25 | | # endif |
26 | | # ifndef DEFAULT_STERM |
27 | 0 | # define DEFAULT_STERM "vt102" |
28 | | # endif |
29 | | #elif defined(__GNU__) |
30 | | # ifndef DEFAULT_VCTERM |
31 | | # define DEFAULT_VCTERM "hurd" |
32 | | # endif |
33 | | # ifndef DEFAULT_STERM |
34 | | # define DEFAULT_STERM "vt102" |
35 | | # endif |
36 | | #else |
37 | | # ifndef DEFAULT_VCTERM |
38 | | # define DEFAULT_VCTERM "vt100" |
39 | | # endif |
40 | | # ifndef DEFAULT_STERM |
41 | | # define DEFAULT_STERM "vt100" |
42 | | # endif |
43 | | #endif |
44 | | |
45 | | static int get_env_int(const char *name) |
46 | 0 | { |
47 | 0 | const char *cp = getenv(name); |
48 | |
|
49 | 0 | if (cp) { |
50 | 0 | char *end = NULL; |
51 | 0 | long x; |
52 | |
|
53 | 0 | errno = 0; |
54 | 0 | x = strtol(cp, &end, 10); |
55 | |
|
56 | 0 | if (errno == 0 && end && *end == '\0' && end > cp && |
57 | 0 | x > 0 && x <= INT_MAX) |
58 | 0 | return x; |
59 | 0 | } |
60 | | |
61 | 0 | return -1; |
62 | 0 | } |
63 | | |
64 | | int get_terminal_dimension(int *cols, int *lines) |
65 | 0 | { |
66 | 0 | int c = 0, l = 0; |
67 | |
|
68 | 0 | #if defined(TIOCGWINSZ) |
69 | 0 | struct winsize w_win; |
70 | 0 | if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &w_win) == 0) { |
71 | 0 | c = w_win.ws_col; |
72 | 0 | l = w_win.ws_row; |
73 | 0 | } |
74 | | #elif defined(TIOCGSIZE) |
75 | | struct ttysize t_win; |
76 | | if (ioctl (STDOUT_FILENO, TIOCGSIZE, &t_win) == 0) { |
77 | | c = t_win.ts_cols; |
78 | | l = t_win.ts_lines; |
79 | | } |
80 | | #endif |
81 | 0 | if (cols) { |
82 | 0 | if (c <= 0) |
83 | 0 | c = get_env_int("COLUMNS"); |
84 | 0 | *cols = c; |
85 | 0 | } |
86 | 0 | if (lines) { |
87 | 0 | if (l <= 0) |
88 | 0 | l = get_env_int("LINES"); |
89 | 0 | *lines = l; |
90 | 0 | } |
91 | 0 | return 0; |
92 | 0 | } |
93 | | |
94 | | int get_terminal_width(int default_width) |
95 | 0 | { |
96 | 0 | int width = 0; |
97 | |
|
98 | 0 | get_terminal_dimension(&width, NULL); |
99 | |
|
100 | 0 | return width > 0 ? width : default_width; |
101 | 0 | } |
102 | | |
103 | | int get_terminal_stdfd(void) |
104 | 0 | { |
105 | 0 | if (isatty(STDIN_FILENO)) |
106 | 0 | return STDIN_FILENO; |
107 | 0 | if (isatty(STDOUT_FILENO)) |
108 | 0 | return STDOUT_FILENO; |
109 | 0 | if (isatty(STDERR_FILENO)) |
110 | 0 | return STDERR_FILENO; |
111 | | |
112 | 0 | return -EINVAL; |
113 | 0 | } |
114 | | |
115 | | int get_terminal_name(const char **path, |
116 | | const char **name, |
117 | | const char **number) |
118 | 0 | { |
119 | 0 | const char *tty; |
120 | 0 | const char *p; |
121 | 0 | int fd; |
122 | | |
123 | |
|
124 | 0 | if (name) |
125 | 0 | *name = NULL; |
126 | 0 | if (path) |
127 | 0 | *path = NULL; |
128 | 0 | if (number) |
129 | 0 | *number = NULL; |
130 | |
|
131 | 0 | fd = get_terminal_stdfd(); |
132 | 0 | if (fd < 0) |
133 | 0 | return fd; /* error */ |
134 | | |
135 | 0 | tty = ttyname(fd); |
136 | 0 | if (!tty) |
137 | 0 | return -1; |
138 | | |
139 | 0 | if (path) |
140 | 0 | *path = tty; |
141 | 0 | if (name || number) |
142 | 0 | tty = strncmp(tty, "/dev/", 5) == 0 ? tty + 5 : tty; |
143 | 0 | if (name) |
144 | 0 | *name = tty; |
145 | 0 | if (number) { |
146 | 0 | for (p = tty; p && *p; p++) { |
147 | 0 | if (isdigit(*p)) { |
148 | 0 | *number = p; |
149 | 0 | break; |
150 | 0 | } |
151 | 0 | } |
152 | 0 | } |
153 | 0 | return 0; |
154 | 0 | } |
155 | | |
156 | | int get_terminal_type(const char **type) |
157 | 0 | { |
158 | 0 | *type = getenv("TERM"); |
159 | 0 | if (*type) |
160 | 0 | return -EINVAL; |
161 | 0 | return 0; |
162 | 0 | } |
163 | | |
164 | | char *get_terminal_default_type(const char *ttyname, int is_serial) |
165 | 0 | { |
166 | 0 | if (ttyname) { |
167 | 0 | #ifdef HAVE_GETTTYNAM |
168 | 0 | struct ttyent *ent = getttynam(ttyname); |
169 | |
|
170 | 0 | if (ent && ent->ty_type) |
171 | 0 | return strdup(ent->ty_type); |
172 | 0 | #endif |
173 | |
|
174 | | #if defined (__s390__) || defined (__s390x__) |
175 | | /* |
176 | | * Special terminal on first serial line on a S/390(x) which |
177 | | * is due legacy reasons a block terminal of type 3270 or |
178 | | * higher. Whereas the second serial line on a S/390(x) is |
179 | | * a real character terminal which is compatible with VT220. |
180 | | */ |
181 | | if (strcmp(ttyname, "ttyS0") == 0) /* linux/drivers/s390/char/con3215.c */ |
182 | | return strdup(DEFAULT_TTYS0); |
183 | | else if (strncmp(ttyname, "3270/tty", 8) == 0) /* linux/drivers/s390/char/con3270.c */ |
184 | | return strdup(DEFAULT_TTY32); |
185 | | else if (strcmp(ttyname, "ttyS1") == 0) /* linux/drivers/s390/char/sclp_vt220.c */ |
186 | | return strdup(DEFAULT_TTYS1); |
187 | | #endif |
188 | 0 | } |
189 | | |
190 | 0 | return strdup(is_serial ? DEFAULT_STERM : DEFAULT_VCTERM); |
191 | 0 | } |
192 | | |
193 | | #ifdef TEST_PROGRAM_TTYUTILS |
194 | | # include <stdlib.h> |
195 | | int main(void) |
196 | | { |
197 | | const char *path, *name, *num; |
198 | | int c, l; |
199 | | |
200 | | if (get_terminal_name(&path, &name, &num) == 0) { |
201 | | char *term; |
202 | | |
203 | | fprintf(stderr, "tty path: %s\n", path); |
204 | | fprintf(stderr, "tty name: %s\n", name); |
205 | | fprintf(stderr, "tty number: %s\n", num); |
206 | | |
207 | | fprintf(stderr, "tty term: %s\n", getenv("TERM")); |
208 | | |
209 | | term = get_terminal_default_type(name, 0); |
210 | | fprintf(stderr, "tty dflt term: %s\n", term); |
211 | | free(term); |
212 | | } |
213 | | get_terminal_dimension(&c, &l); |
214 | | fprintf(stderr, "tty cols: %d\n", c); |
215 | | fprintf(stderr, "tty lines: %d\n", l); |
216 | | |
217 | | |
218 | | return EXIT_SUCCESS; |
219 | | } |
220 | | #endif /* TEST_PROGRAM_TTYUTILS */ |