device: Set disconnect timer to zero for fast disconnection
[platform/upstream/bluez.git] / monitor / display.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2011-2014  Intel Corporation
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
8  *
9  *
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <stdio.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <sys/wait.h>
23 #include <sys/prctl.h>
24 #include <sys/ioctl.h>
25 #include <termios.h>
26
27 #include "display.h"
28
29 static pid_t pager_pid = 0;
30 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
31 int default_pager_num_columns = FALLBACK_TERMINAL_WIDTH;
32 #endif
33
34 enum monitor_color setting_monitor_color = COLOR_AUTO;
35
36 void set_monitor_color(enum monitor_color color)
37 {
38         setting_monitor_color = color;
39 }
40
41 bool use_color(void)
42 {
43         static int cached_use_color = -1;
44
45         if (setting_monitor_color == COLOR_ALWAYS)
46                 cached_use_color = 1;
47         else if (setting_monitor_color == COLOR_NEVER)
48                 cached_use_color = 0;
49         else if (__builtin_expect(!!(cached_use_color < 0), 0))
50                 cached_use_color = isatty(STDOUT_FILENO) > 0 || pager_pid > 0;
51
52         return cached_use_color;
53 }
54
55 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
56 void set_default_pager_num_columns(int num_columns)
57 {
58         default_pager_num_columns = num_columns;
59 }
60 #endif
61
62 int num_columns(void)
63 {
64         static int cached_num_columns = -1;
65
66         if (__builtin_expect(!!(cached_num_columns < 0), 0)) {
67                 struct winsize ws;
68
69                 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0 ||
70                                                                 ws.ws_col == 0)
71 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
72                         cached_num_columns = FALLBACK_TERMINAL_WIDTH;
73 #else
74                         cached_num_columns = default_pager_num_columns;
75 #endif
76                 else
77                         cached_num_columns = ws.ws_col;
78         }
79
80         return cached_num_columns;
81 }
82
83 static void close_pipe(int p[])
84 {
85         if (p[0] >= 0)
86                 close(p[0]);
87         if (p[1] >= 0)
88                 close(p[1]);
89 }
90
91 static void wait_for_terminate(pid_t pid)
92 {
93         siginfo_t dummy;
94
95         for (;;) {
96                 memset(&dummy, 0, sizeof(dummy));
97
98                 if (waitid(P_PID, pid, &dummy, WEXITED) < 0) {
99                         if (errno == EINTR)
100                                 continue;
101                         return;
102                 }
103
104                 return;
105         }
106 }
107
108 void open_pager(void)
109 {
110         const char *pager;
111         pid_t parent_pid;
112         int fd[2];
113
114         if (pager_pid > 0)
115                 return;
116
117         pager = getenv("PAGER");
118         if (pager) {
119                 if (!*pager || strcmp(pager, "cat") == 0)
120                         return;
121         }
122
123         if (!(isatty(STDOUT_FILENO) > 0))
124                 return;
125
126         num_columns();
127
128         if (pipe(fd) < 0) {
129                 perror("Failed to create pager pipe");
130                 return;
131         }
132
133         parent_pid = getpid();
134
135         pager_pid = fork();
136         if (pager_pid < 0) {
137                 perror("Failed to fork pager");
138                 close_pipe(fd);
139                 return;
140         }
141
142         if (pager_pid == 0) {
143                 dup2(fd[0], STDIN_FILENO);
144                 close_pipe(fd);
145
146                 setenv("LESS", "FRSX", 0);
147
148                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
149                         _exit(EXIT_FAILURE);
150
151                 if (getppid() != parent_pid)
152                         _exit(EXIT_SUCCESS);
153
154                 if (pager) {
155                         execlp(pager, pager, NULL);
156                         execl("/bin/sh", "sh", "-c", pager, NULL);
157                 }
158
159                 execlp("pager", "pager", NULL);
160                 execlp("less", "less", NULL);
161                 execlp("more", "more", NULL);
162
163                 _exit(EXIT_FAILURE);
164         }
165
166         if (dup2(fd[1], STDOUT_FILENO) < 0) {
167                 perror("Failed to duplicate pager pipe");
168                 return;
169         }
170
171         close_pipe(fd);
172 }
173
174 void close_pager(void)
175 {
176         if (pager_pid <= 0)
177                 return;
178
179         fclose(stdout);
180         kill(pager_pid, SIGCONT);
181         wait_for_terminate(pager_pid);
182         pager_pid = 0;
183 }