1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 #pragma once
3 
4 #include <stdarg.h>
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <syslog.h>
8 #include <sys/types.h>
9 
10 #include "macro.h"
11 #include "time-util.h"
12 
13 /* Regular colors */
14 #define ANSI_BLACK   "\x1B[0;30m" /* Some type of grey usually. */
15 #define ANSI_RED     "\x1B[0;31m"
16 #define ANSI_GREEN   "\x1B[0;32m"
17 #define ANSI_YELLOW  "\x1B[0;33m"
18 #define ANSI_BLUE    "\x1B[0;34m"
19 #define ANSI_MAGENTA "\x1B[0;35m"
20 #define ANSI_CYAN    "\x1B[0;36m"
21 #define ANSI_WHITE   "\x1B[0;37m" /* This is actually rendered as light grey, legible even on a white
22                                    * background. See ANSI_HIGHLIGHT_WHITE for real white. */
23 
24 #define ANSI_BRIGHT_BLACK   "\x1B[0;90m"
25 #define ANSI_BRIGHT_RED     "\x1B[0;91m"
26 #define ANSI_BRIGHT_GREEN   "\x1B[0;92m"
27 #define ANSI_BRIGHT_YELLOW  "\x1B[0;93m"
28 #define ANSI_BRIGHT_BLUE    "\x1B[0;94m"
29 #define ANSI_BRIGHT_MAGENTA "\x1B[0;95m"
30 #define ANSI_BRIGHT_CYAN    "\x1B[0;96m"
31 #define ANSI_BRIGHT_WHITE   "\x1B[0;97m"
32 
33 #define ANSI_GREY    "\x1B[0;38;5;245m"
34 
35 /* Bold/highlighted */
36 #define ANSI_HIGHLIGHT_BLACK    "\x1B[0;1;30m"
37 #define ANSI_HIGHLIGHT_RED      "\x1B[0;1;31m"
38 #define ANSI_HIGHLIGHT_GREEN    "\x1B[0;1;32m"
39 #define _ANSI_HIGHLIGHT_YELLOW  "\x1B[0;1;33m" /* This yellow is currently not displayed well by some terminals */
40 #define ANSI_HIGHLIGHT_BLUE     "\x1B[0;1;34m"
41 #define ANSI_HIGHLIGHT_MAGENTA  "\x1B[0;1;35m"
42 #define ANSI_HIGHLIGHT_CYAN     "\x1B[0;1;36m"
43 #define ANSI_HIGHLIGHT_WHITE    "\x1B[0;1;37m"
44 #define ANSI_HIGHLIGHT_YELLOW4  "\x1B[0;1;38;5;100m"
45 #define ANSI_HIGHLIGHT_KHAKI3   "\x1B[0;1;38;5;185m"
46 #define ANSI_HIGHLIGHT_GREY     "\x1B[0;1;38;5;245m"
47 
48 #define ANSI_HIGHLIGHT_YELLOW   ANSI_HIGHLIGHT_KHAKI3 /* Replacement yellow that is more legible */
49 
50 /* Underlined */
51 #define ANSI_GREY_UNDERLINE              "\x1B[0;4;38;5;245m"
52 #define ANSI_HIGHLIGHT_RED_UNDERLINE     "\x1B[0;1;4;31m"
53 #define ANSI_HIGHLIGHT_GREEN_UNDERLINE   "\x1B[0;1;4;32m"
54 #define ANSI_HIGHLIGHT_YELLOW_UNDERLINE  "\x1B[0;1;4;38;5;185m"
55 #define ANSI_HIGHLIGHT_BLUE_UNDERLINE    "\x1B[0;1;4;34m"
56 #define ANSI_HIGHLIGHT_MAGENTA_UNDERLINE "\x1B[0;1;4;35m"
57 #define ANSI_HIGHLIGHT_GREY_UNDERLINE    "\x1B[0;1;4;38;5;245m"
58 
59 /* Other ANSI codes */
60 #define ANSI_UNDERLINE "\x1B[0;4m"
61 #define ANSI_HIGHLIGHT "\x1B[0;1;39m"
62 #define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m"
63 
64 /* Fallback colors: 256 -> 16 */
65 #define ANSI_HIGHLIGHT_GREY_FALLBACK   "\x1B[0;1;90m"
66 #define ANSI_HIGHLIGHT_YELLOW_FALLBACK "\x1B[0;1;33m"
67 
68 /* Reset/clear ANSI styles */
69 #define ANSI_NORMAL "\x1B[0m"
70 
71 /* Erase characters until the end of the line */
72 #define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
73 
74 /* Move cursor up one line */
75 #define ANSI_REVERSE_LINEFEED "\x1BM"
76 
77 /* Set cursor to top left corner and clear screen */
78 #define ANSI_HOME_CLEAR "\x1B[H\x1B[2J"
79 
80 int reset_terminal_fd(int fd, bool switch_to_text);
81 int reset_terminal(const char *name);
82 
83 int open_terminal(const char *name, int mode);
84 
85 /* Flags for tweaking the way we become the controlling process of a terminal. */
86 typedef enum AcquireTerminalFlags {
87         /* Try to become the controlling process of the TTY. If we can't return -EPERM. */
88         ACQUIRE_TERMINAL_TRY        = 0,
89 
90         /* Tell the kernel to forcibly make us the controlling process of the TTY. Returns -EPERM if the kernel doesn't allow that. */
91         ACQUIRE_TERMINAL_FORCE      = 1,
92 
93         /* If we can't become the controlling process of the TTY right-away, then wait until we can. */
94         ACQUIRE_TERMINAL_WAIT       = 2,
95 
96         /* Pick one of the above, and then OR this flag in, in order to request permissive behaviour, if we can't become controlling process then don't mind */
97         ACQUIRE_TERMINAL_PERMISSIVE = 1 << 2,
98 } AcquireTerminalFlags;
99 
100 /* Limits the use of ANSI colors to a subset. */
101 typedef enum ColorMode {
102         /* No colors, monochrome output. */
103         COLOR_OFF,
104 
105         /* All colors, no restrictions. */
106         COLOR_ON,
107 
108         /* Only the base 16 colors. */
109         COLOR_16,
110 
111         /* Only 256 colors. */
112         COLOR_256,
113 
114         /* For truecolor or 24bit color support.*/
115         COLOR_24BIT,
116 
117         _COLOR_INVALID = -EINVAL,
118 } ColorMode;
119 
120 int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout);
121 int release_terminal(void);
122 
123 int terminal_vhangup_fd(int fd);
124 int terminal_vhangup(const char *name);
125 
126 int terminal_set_size_fd(int fd, const char *ident, unsigned rows, unsigned cols);
127 
128 int chvt(int vt);
129 
130 int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
131 int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
132 int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
133 
134 int vt_disallocate(const char *name);
135 
136 int resolve_dev_console(char **ret);
137 int get_kernel_consoles(char ***ret);
138 bool tty_is_vc(const char *tty);
139 bool tty_is_vc_resolve(const char *tty);
140 bool tty_is_console(const char *tty) _pure_;
141 int vtnr_from_tty(const char *tty);
142 const char *default_term_for_tty(const char *tty);
143 
144 int make_console_stdio(void);
145 
146 int fd_columns(int fd);
147 unsigned columns(void);
148 int fd_lines(int fd);
149 unsigned lines(void);
150 
151 void columns_lines_cache_reset(int _unused_ signum);
152 void reset_terminal_feature_caches(void);
153 
154 bool on_tty(void);
155 bool terminal_is_dumb(void);
156 ColorMode get_color_mode(void);
157 bool underline_enabled(void);
158 bool dev_console_colors_enabled(void);
159 
colors_enabled(void)160 static inline bool colors_enabled(void) {
161 
162         /* Returns true if colors are considered supported on our stdout. */
163         return get_color_mode() != COLOR_OFF;
164 }
165 
166 #define DEFINE_ANSI_FUNC(name, NAME)                            \
167         static inline const char *ansi_##name(void) {           \
168                 return colors_enabled() ? ANSI_##NAME : "";     \
169         }
170 
171 #define DEFINE_ANSI_FUNC_256(name, NAME, FALLBACK)             \
172         static inline const char *ansi_##name(void) {          \
173                 switch (get_color_mode()) {                    \
174                         case COLOR_OFF: return "";             \
175                         case COLOR_16: return ANSI_##FALLBACK; \
176                         default : return ANSI_##NAME;          \
177                 }                                              \
178         }
179 
180 #define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME)                            \
181         static inline const char *ansi_##name(void) {                     \
182                 return underline_enabled() ? ANSI_##NAME ANSI_UNDERLINE : \
183                         colors_enabled() ? ANSI_##NAME : "";              \
184         }
185 
186 
187 #define DEFINE_ANSI_FUNC_UNDERLINE_256(name, NAME, FALLBACK)                                                           \
188         static inline const char *ansi_##name(void) {                                                                  \
189                 switch (get_color_mode()) {                                                                            \
190                         case COLOR_OFF: return "";                                                                     \
191                         case COLOR_16: return underline_enabled() ? ANSI_##FALLBACK ANSI_UNDERLINE : ANSI_##FALLBACK;  \
192                         default : return underline_enabled() ? ANSI_##NAME ANSI_UNDERLINE: ANSI_##NAME;                \
193                 }                                                                                                      \
194         }
195 
196 DEFINE_ANSI_FUNC(normal,            NORMAL);
197 DEFINE_ANSI_FUNC(highlight,         HIGHLIGHT);
198 DEFINE_ANSI_FUNC(black,             BLACK);
199 DEFINE_ANSI_FUNC(red,               RED);
200 DEFINE_ANSI_FUNC(green,             GREEN);
201 DEFINE_ANSI_FUNC(yellow,            YELLOW);
202 DEFINE_ANSI_FUNC(blue,              BLUE);
203 DEFINE_ANSI_FUNC(magenta,           MAGENTA);
204 DEFINE_ANSI_FUNC(cyan,              CYAN);
205 DEFINE_ANSI_FUNC(white,             WHITE);
206 DEFINE_ANSI_FUNC_256(grey,          GREY, BRIGHT_BLACK);
207 
208 DEFINE_ANSI_FUNC(bright_black,      BRIGHT_BLACK);
209 DEFINE_ANSI_FUNC(bright_red,        BRIGHT_RED);
210 DEFINE_ANSI_FUNC(bright_green,      BRIGHT_GREEN);
211 DEFINE_ANSI_FUNC(bright_yellow,     BRIGHT_YELLOW);
212 DEFINE_ANSI_FUNC(bright_blue,       BRIGHT_BLUE);
213 DEFINE_ANSI_FUNC(bright_magenta,    BRIGHT_MAGENTA);
214 DEFINE_ANSI_FUNC(bright_cyan,       BRIGHT_CYAN);
215 DEFINE_ANSI_FUNC(bright_white,      BRIGHT_WHITE);
216 
217 DEFINE_ANSI_FUNC(highlight_black,       HIGHLIGHT_BLACK);
218 DEFINE_ANSI_FUNC(highlight_red,         HIGHLIGHT_RED);
219 DEFINE_ANSI_FUNC(highlight_green,       HIGHLIGHT_GREEN);
220 DEFINE_ANSI_FUNC_256(highlight_yellow,  HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK);
221 DEFINE_ANSI_FUNC_256(highlight_yellow4, HIGHLIGHT_YELLOW4, HIGHLIGHT_YELLOW_FALLBACK);
222 DEFINE_ANSI_FUNC(highlight_blue,        HIGHLIGHT_BLUE);
223 DEFINE_ANSI_FUNC(highlight_magenta,     HIGHLIGHT_MAGENTA);
224 DEFINE_ANSI_FUNC(highlight_cyan,        HIGHLIGHT_CYAN);
225 DEFINE_ANSI_FUNC_256(highlight_grey,    HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK);
226 DEFINE_ANSI_FUNC(highlight_white,       HIGHLIGHT_WHITE);
227 
_ansi_highlight_yellow(void)228 static inline const char* _ansi_highlight_yellow(void) {
229         return colors_enabled() ? _ANSI_HIGHLIGHT_YELLOW : "";
230 }
231 
232 DEFINE_ANSI_FUNC_UNDERLINE(underline,                       NORMAL);
233 DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline,             HIGHLIGHT);
234 DEFINE_ANSI_FUNC_UNDERLINE_256(grey_underline,              GREY, BRIGHT_BLACK);
235 DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline,         HIGHLIGHT_RED);
236 DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline,       HIGHLIGHT_GREEN);
237 DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_yellow_underline,  HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK);
238 DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline,        HIGHLIGHT_BLUE);
239 DEFINE_ANSI_FUNC_UNDERLINE(highlight_magenta_underline,     HIGHLIGHT_MAGENTA);
240 DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_grey_underline,    HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK);
241 
242 int get_ctty_devnr(pid_t pid, dev_t *d);
243 int get_ctty(pid_t, dev_t *_devnr, char **r);
244 
245 int getttyname_malloc(int fd, char **r);
246 int getttyname_harder(int fd, char **r);
247 
248 int ptsname_malloc(int fd, char **ret);
249 
250 int openpt_allocate(int flags, char **ret_slave);
251 int openpt_allocate_in_namespace(pid_t pid, int flags, char **ret_slave);
252 int open_terminal_in_namespace(pid_t pid, const char *name, int mode);
253 
254 int vt_default_utf8(void);
255 int vt_reset_keyboard(int fd);
256 int vt_restore(int fd);
257 int vt_release(int fd, bool restore_vt);
258 
259 void get_log_colors(int priority, const char **on, const char **off, const char **highlight);
260 
ansi_highlight_green_red(bool b)261 static inline const char* ansi_highlight_green_red(bool b) {
262         return b ? ansi_highlight_green() : ansi_highlight_red();
263 }
264 
265 /* This assumes there is a 'tty' group */
266 #define TTY_MODE 0620
267