/*
- * Copyright (C) 1998-2012 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1998-2013 Andre Noll <maan@systemlinux.org>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
#include <signal.h>
#include <sys/types.h>
#include <curses.h>
+#include <sys/time.h>
#include "gui.cmdline.h"
#include "para.h"
static unsigned scroll_position;
-static int cmd_died, curses_active;
+static int curses_active;
static pid_t cmd_pid;
static int command_fds[2];
return file_exists(tmp)? tmp: NULL;
}
-/*
- * print num spaces to curses window
- */
+/* Print given number of spaces to curses window. */
static void add_spaces(WINDOW* win, unsigned int num)
{
- while (num > 0) {
- num--;
- waddstr(win, " ");
+ char space[] = " ";
+ unsigned sz = sizeof(space);
+
+ while (num >= sz) {
+ waddstr(win, space);
+ num -= sz;
+ }
+ if (num > 0) {
+ assert(num < sz);
+ space[num] = '\0';
+ waddstr(win, space);
}
}
para_sigaction(SIGHUP, SIG_IGN);
}
-__noreturn static void do_exit(int ret)
+/* kill every process in the process group and exit */
+__noreturn static void kill_pg_and_die(int ret)
{
para_sigaction(SIGTERM, SIG_IGN);
kill(0, SIGTERM);
__noreturn static void finish(int ret)
{
shutdown_curses();
- do_exit(ret);
+ kill_pg_and_die(ret);
}
/*
va_start(argp, fmt);
vfprintf(outfd, fmt, argp);
va_end(argp);
- do_exit(ret);
+ kill_pg_and_die(ret);
}
static void print_welcome(void)
ret = para_reap_child(&pid);
if (ret <= 0)
return;
- if (pid == cmd_pid) {
+ if (pid == cmd_pid)
cmd_pid = 0;
- cmd_died = 1;
- }
goto reap_next_child;
}
}
}
-static int open_stat_pipe(void)
+static void status_pre_select(fd_set *rfds, int *max_fileno, struct timeval *tv)
{
- static int init = 1;
+ static struct timeval next_exec, atm, diff;
int ret, fds[3] = {0, 1, 0};
pid_t pid;
- if (init)
- init = 0;
- else
- /*
- * Sleep a bit to avoid a busy loop. As the call to sleep() may
- * be interrupted by SIGCHLD, we simply wait until the call
- * succeeds.
- */
- while (sleep(2))
- ; /* nothing */
+ if (stat_pipe >= 0)
+ goto success;
+ /* Avoid busy loop */
+ gettimeofday(&atm, NULL);
+ if (tv_diff(&next_exec, &atm, &diff) > 0) {
+ if (tv_diff(&diff, tv, NULL) < 0)
+ *tv = diff;
+ return;
+ }
+ next_exec.tv_sec = atm.tv_sec + 2;
ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds);
if (ret < 0)
- return ret;
+ return;
ret = mark_fd_nonblocking(fds[1]);
- if (ret >= 0)
- return fds[1];
- close(fds[1]);
- return ret;
+ if (ret < 0) {
+ close(fds[1]);
+ return;
+ }
+ stat_pipe = fds[1];
+success:
+ para_fd_set(stat_pipe, rfds, max_fileno);
}
-#define COMMAND_BUF_SIZE 4096
+#define COMMAND_BUF_SIZE 32768
/*
* This is the core select loop. Besides the (internal) signal
// ret = refresh_status();
FD_ZERO(&rfds);
max_fileno = 0;
- if (stat_pipe < 0)
- stat_pipe = open_stat_pipe();
- if (stat_pipe >= 0)
- para_fd_set(stat_pipe, &rfds, &max_fileno);
+ status_pre_select(&rfds, &max_fileno, &tv);
/* signal pipe */
para_fd_set(signal_pipe, &rfds, &max_fileno);
/* command pipe only for COMMAND_MODE */
if (command_fds[1] >= 0)
para_fd_set(command_fds[1], &rfds, &max_fileno);
}
+ if (mode == GETCH_MODE || mode == COMMAND_MODE)
+ para_fd_set(STDIN_FILENO, &rfds, &max_fileno);
ret = para_select(max_fileno + 1, &rfds, NULL, &tv);
if (ret <= 0)
goto check_return; /* skip fd checks */
COMMAND_BUF_SIZE - 1 - cbo[i], &rfds, &sz);
cbo[i] += sz;
sz = cbo[i];
- cbo[i] = for_each_line(command_buf[i], cbo[i],
+ cbo[i] = for_each_line(0, command_buf[i], cbo[i],
add_output_line, &i);
if (sz != cbo[i])
wrefresh(bot.win);
if (command_fds[!i] < 0) /* both fds closed */
return 0;
}
+ if (cbo[i] == COMMAND_BUF_SIZE - 1) {
+ PARA_NOTICE_LOG("discarding overlong line");
+ cbo[i] = 0;
+ }
}
}
ret = read_stat_pipe(&rfds);
return ret;
break;
case EXTERNAL_MODE:
- if (cmd_died) {
- cmd_died = 0;
+ if (cmd_pid == 0)
return 0;
- }
}
goto repeat;
}
shutdown_curses();
if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0)
return;
- cmd_died = 0;
do_select(EXTERNAL_MODE);
init_curses();
}