// SPDX-License-Identifier: LGPL-2.1-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2014 Intel Corporation * Copyright (C) 2002-2010 Marcel Holtmann * * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "display.h" static pid_t pager_pid = 0; int default_pager_num_columns = FALLBACK_TERMINAL_WIDTH; enum monitor_color setting_monitor_color = COLOR_AUTO; void set_monitor_color(enum monitor_color color) { setting_monitor_color = color; } bool use_color(void) { static int cached_use_color = -1; if (setting_monitor_color == COLOR_ALWAYS) cached_use_color = 1; else if (setting_monitor_color == COLOR_NEVER) cached_use_color = 0; else if (__builtin_expect(!!(cached_use_color < 0), 0)) cached_use_color = isatty(STDOUT_FILENO) > 0 || pager_pid > 0; return cached_use_color; } void set_default_pager_num_columns(int num_columns) { default_pager_num_columns = num_columns; } int num_columns(void) { static int cached_num_columns = -1; if (__builtin_expect(!!(cached_num_columns < 0), 0)) { struct winsize ws; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0 || ws.ws_col == 0) cached_num_columns = default_pager_num_columns; else cached_num_columns = ws.ws_col; } return cached_num_columns; } static void close_pipe(int p[]) { if (p[0] >= 0) close(p[0]); if (p[1] >= 0) close(p[1]); } static void wait_for_terminate(pid_t pid) { siginfo_t dummy; for (;;) { memset(&dummy, 0, sizeof(dummy)); if (waitid(P_PID, pid, &dummy, WEXITED) < 0) { if (errno == EINTR) continue; return; } return; } } void open_pager(void) { const char *pager; pid_t parent_pid; int fd[2]; if (pager_pid > 0) return; pager = getenv("PAGER"); if (pager) { if (!*pager || strcmp(pager, "cat") == 0) return; } if (!(isatty(STDOUT_FILENO) > 0)) return; num_columns(); if (pipe(fd) < 0) { perror("Failed to create pager pipe"); return; } parent_pid = getpid(); pager_pid = fork(); if (pager_pid < 0) { perror("Failed to fork pager"); close_pipe(fd); return; } if (pager_pid == 0) { dup2(fd[0], STDIN_FILENO); close_pipe(fd); setenv("LESS", "FRSX", 0); if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) _exit(EXIT_FAILURE); if (getppid() != parent_pid) _exit(EXIT_SUCCESS); if (pager) { execlp(pager, pager, NULL); execl("/bin/sh", "sh", "-c", pager, NULL); } execlp("pager", "pager", NULL); execlp("less", "less", NULL); execlp("more", "more", NULL); _exit(EXIT_FAILURE); } if (dup2(fd[1], STDOUT_FILENO) < 0) { perror("Failed to duplicate pager pipe"); return; } close_pipe(fd); } void close_pager(void) { if (pager_pid <= 0) return; fclose(stdout); kill(pager_pid, SIGCONT); wait_for_terminate(pager_pid); pager_pid = 0; }