From c0cbadfc2bec5e03b59d43011209b6dad8c6c685 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 2 Nov 2012 21:32:54 +0100 Subject: [PATCH] monitor: Add support for automatic pager --- Makefile.tools | 1 + monitor/control.c | 5 ++ monitor/packet.c | 3 +- monitor/pager.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++ monitor/pager.h | 29 ++++++++++ 5 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 monitor/pager.c create mode 100644 monitor/pager.h diff --git a/Makefile.tools b/Makefile.tools index f7c85ef9a..ebda7c584 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -47,6 +47,7 @@ tools_btmgmt_SOURCES = tools/btmgmt.c src/glib-helper.c src/eir.c tools_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \ + monitor/pager.h monitor/pager.c \ monitor/mainloop.h monitor/mainloop.c \ monitor/hcidump.h monitor/hcidump.c \ monitor/btsnoop.h monitor/btsnoop.c \ diff --git a/monitor/control.c b/monitor/control.c index bbcdcbbc5..93189fd1d 100644 --- a/monitor/control.c +++ b/monitor/control.c @@ -40,6 +40,7 @@ #include #include "mainloop.h" +#include "pager.h" #include "packet.h" #include "btsnoop.h" #include "control.h" @@ -778,6 +779,8 @@ void control_reader(const char *path) if (btsnoop_open(path) < 0) return; + pager_open(); + while (1) { if (btsnoop_read(&tv, &index, &opcode, buf, &pktlen) < 0) break; @@ -785,6 +788,8 @@ void control_reader(const char *path) packet_monitor(&tv, index, opcode, buf, pktlen); } + pager_close(); + btsnoop_close(); } diff --git a/monitor/packet.c b/monitor/packet.c index 0c4d360ad..2be1635cd 100644 --- a/monitor/packet.c +++ b/monitor/packet.c @@ -40,6 +40,7 @@ #include #include +#include "pager.h" #include "bt.h" #include "control.h" #include "packet.h" @@ -62,7 +63,7 @@ static bool use_color(void) static int cached_use_color = -1; if (__builtin_expect(!!(cached_use_color < 0), 0)) - cached_use_color = isatty(STDOUT_FILENO) > 0; + cached_use_color = isatty(STDOUT_FILENO) > 0 || pager_have(); return cached_use_color; } diff --git a/monitor/pager.c b/monitor/pager.c new file mode 100644 index 000000000..f24eca7af --- /dev/null +++ b/monitor/pager.c @@ -0,0 +1,145 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2011-2012 Intel Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pager.h" + +static pid_t pager_pid = 0; + +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 pager_open(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; + + 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 pager_close(void) +{ + if (pager_pid <= 0) + return; + + fclose(stdout); + kill(pager_pid, SIGCONT); + wait_for_terminate(pager_pid); + pager_pid = 0; +} + +bool pager_have(void) +{ + return pager_pid > 0; +} diff --git a/monitor/pager.h b/monitor/pager.h new file mode 100644 index 000000000..041eb74dd --- /dev/null +++ b/monitor/pager.h @@ -0,0 +1,29 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2011-2012 Intel Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +void pager_open(void); +void pager_close(void); +bool pager_have(void); -- 2.47.3