diff --git a/Makefile.am b/Makefile.am index aa31a685..ecbdc522 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,8 @@ client_iwctl_LDADD = ell/libell-internal.la monitor_iwmon_SOURCES = monitor/main.c linux/nl80211.h \ monitor/nlmon.h monitor/nlmon.c \ - monitor/pcap.h monitor/pcap.c + monitor/pcap.h monitor/pcap.c \ + monitor/display.h monitor/display.c monitor_iwmon_LDADD = ell/libell-internal.la noinst_PROGRAMS = tools/hwsim diff --git a/monitor/display.c b/monitor/display.c new file mode 100644 index 00000000..2090b859 --- /dev/null +++ b/monitor/display.c @@ -0,0 +1,171 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; 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 +#include + +#include "display.h" + +#define FALLBACK_TERMINAL_WIDTH 80 + +static pid_t pager_pid = 0; + +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 || pager_pid > 0; + + return !!cached_use_color; +} + +unsigned 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 = FALLBACK_TERMINAL_WIDTH; + 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; +} diff --git a/monitor/display.h b/monitor/display.h new file mode 100644 index 00000000..2a1053e6 --- /dev/null +++ b/monitor/display.h @@ -0,0 +1,30 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2014 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +bool use_color(void); + +unsigned int num_columns(void); + +void open_pager(void); +void close_pager(void); diff --git a/monitor/main.c b/monitor/main.c index e41967cf..49541649 100644 --- a/monitor/main.c +++ b/monitor/main.c @@ -35,6 +35,7 @@ #include "linux/nl80211.h" #include "monitor/nlmon.h" #include "monitor/pcap.h" +#include "monitor/display.h" static struct nlmon *nlmon = NULL; @@ -264,6 +265,8 @@ int main(int argc, char *argv[]) if (reader_path) { struct pcap *pcap; + open_pager(); + pcap = pcap_open(reader_path); if (!pcap) { exit_status = EXIT_FAILURE; @@ -277,6 +280,8 @@ int main(int argc, char *argv[]) exit_status = process_pcap(pcap); pcap_close(pcap); + + close_pager(); goto done; }