Add iexec
This commit is contained in:
parent
38300c0375
commit
047a55640c
|
@ -51,6 +51,9 @@ target_link_libraries (fancontrol-ng ${project_libraries})
|
|||
add_executable (priod priod.c)
|
||||
target_link_libraries (priod ${project_libraries})
|
||||
|
||||
add_executable (iexec iexec.c)
|
||||
target_link_libraries (iexec ${project_libraries})
|
||||
|
||||
if (WITH_GDM)
|
||||
include_directories (${gdm_INCLUDE_DIRS})
|
||||
add_executable (gdm-switch-user gdm-switch-user.c)
|
||||
|
@ -90,8 +93,8 @@ if (WITH_GDM)
|
|||
install (TARGETS gdm-switch-user DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif (WITH_GDM)
|
||||
|
||||
install (TARGETS wmstatus brightness input-switch fancontrol-ng priod siprandom
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install (TARGETS wmstatus brightness input-switch fancontrol-ng priod iexec
|
||||
siprandom DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install (PROGRAMS shellify DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install (FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||
|
||||
|
|
|
@ -13,10 +13,12 @@ to other people as well:
|
|||
- 'fancontrol-ng' is a clone of fancontrol that can handle errors on resume
|
||||
from suspend instead of setting fans to maximum speed and quitting;
|
||||
in general it doesn't handle everything the original does
|
||||
- 'priod' sets CPU, I/O and OOM killer priorities for new processes according
|
||||
to configuration
|
||||
- 'priod' sets process CPU, I/O and OOM killer priorities automatically
|
||||
according to configuration
|
||||
- 'shellify' is a simple script that sets up a shell for commands like vgdb
|
||||
and nmcli that are painfully lacking it
|
||||
- 'iexec' runs a program and attempts to restart it cleanly when the
|
||||
executable file is replaced on the disk
|
||||
- 'gdm-switch-user' tells the running GDM daemon, if any, to show the switch
|
||||
user screen
|
||||
- 'siprandom' uses the SipHash 2-4 algorithm to produce a stream of
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* iexec.c: run a program and restart on file change
|
||||
*
|
||||
* Copyright (c) 2017, Přemysl Janouch <p.janouch@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#undef PROGRAM_NAME
|
||||
#define PROGRAM_NAME "iexec"
|
||||
#include "liberty/liberty.c"
|
||||
|
||||
// This can also work on BSD if someone puts in the effort to support kqueue
|
||||
#include <sys/inotify.h>
|
||||
|
||||
static pid_t g_child;
|
||||
static bool g_restarting = false;
|
||||
static int g_inotify_fd, g_inotify_wd;
|
||||
|
||||
static void
|
||||
handle_file_change (const char *base)
|
||||
{
|
||||
char buf[4096]; ssize_t len; const struct inotify_event *e;
|
||||
while ((len = read (g_inotify_fd, buf, sizeof buf)) > 0)
|
||||
for (char *ptr = buf; ptr < buf + len; ptr += sizeof *e + e->len)
|
||||
{
|
||||
e = (const struct inotify_event *) buf;
|
||||
if (e->wd != g_inotify_wd || strcmp (e->name, base))
|
||||
continue;
|
||||
|
||||
print_debug ("file changed, killing child");
|
||||
g_restarting = true;
|
||||
if (kill (g_child, SIGINT))
|
||||
print_error ("kill: %s", strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn (char *argv[])
|
||||
{
|
||||
if ((g_child = fork ()) == -1)
|
||||
exit_fatal ("fork: %s", strerror (errno));
|
||||
else if (!g_child)
|
||||
{
|
||||
execvp (argv[0], argv);
|
||||
exit_fatal ("execvp: %s", strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
check_child_death (char *argv[])
|
||||
{
|
||||
if (waitpid (g_child, NULL, WNOHANG) != g_child)
|
||||
return true;
|
||||
|
||||
if (!g_restarting)
|
||||
{
|
||||
print_debug ("child died on its own, not respawning");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
print_debug ("child died on request, respawning");
|
||||
spawn (argv);
|
||||
g_restarting = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sigchld_handler (int signum)
|
||||
{
|
||||
// We need to have this handler so that pselect() can return EINTR
|
||||
(void) signum;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
static const struct opt opts[] =
|
||||
{
|
||||
{ 'd', "debug", NULL, 0, "run in debug mode" },
|
||||
{ 'h', "help", NULL, 0, "display this help and exit" },
|
||||
{ 'V', "version", NULL, 0, "output version information and exit" },
|
||||
{ 0, NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
struct opt_handler oh = opt_handler_make (argc, argv, opts,
|
||||
"PROGRAM [ARG...]", "Run a program and restart on file change.");
|
||||
|
||||
// We have to turn that off as it causes more trouble than what it's worth
|
||||
char *nonpermuting = xstrdup_printf ("+%s", oh.opt_string);
|
||||
free (oh.opt_string);
|
||||
oh.opt_string = nonpermuting;
|
||||
|
||||
int c;
|
||||
while ((c = opt_handler_get (&oh)) != -1)
|
||||
switch (c)
|
||||
{
|
||||
case 'd':
|
||||
g_debug_mode = true;
|
||||
break;
|
||||
case 'h':
|
||||
opt_handler_usage (&oh, stdout);
|
||||
exit (EXIT_SUCCESS);
|
||||
case 'V':
|
||||
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
default:
|
||||
print_error ("wrong options");
|
||||
opt_handler_usage (&oh, stderr);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == optind)
|
||||
{
|
||||
opt_handler_usage (&oh, stderr);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
opt_handler_free (&oh);
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
(void) signal (SIGPIPE, SIG_IGN);
|
||||
struct sigaction sa = { .sa_handler = sigchld_handler };
|
||||
sigemptyset (&sa.sa_mask);
|
||||
if (sigaction (SIGCHLD, &sa, NULL))
|
||||
exit_fatal ("sigaction: %s", strerror (errno));
|
||||
|
||||
sigset_t chld, orig;
|
||||
sigemptyset (&chld);
|
||||
sigaddset (&chld, SIGCHLD);
|
||||
if (sigprocmask (SIG_BLOCK, &chld, &orig))
|
||||
exit_fatal ("sigprocmask: %s", strerror (errno));
|
||||
|
||||
char *path = xstrdup (argv[0]);
|
||||
|
||||
if ((g_inotify_fd = inotify_init1 (IN_NONBLOCK)) < 0)
|
||||
exit_fatal ("inotify_init1: %s", strerror (errno));
|
||||
if ((g_inotify_wd = inotify_add_watch (g_inotify_fd,
|
||||
dirname (path), IN_MOVED_TO | IN_CLOSE_WRITE)) < 0)
|
||||
exit_fatal ("inotify_add_watch: %s", strerror (errno));
|
||||
|
||||
free (path);
|
||||
char *base = basename ((path = xstrdup (argv[0])));
|
||||
spawn (argv);
|
||||
|
||||
do
|
||||
{
|
||||
fd_set r; FD_SET (g_inotify_fd, &r);
|
||||
(void) pselect (g_inotify_fd + 1, &r, NULL, NULL, NULL, &orig);
|
||||
handle_file_change (base);
|
||||
}
|
||||
while (check_child_death (argv));
|
||||
|
||||
free (path);
|
||||
close (g_inotify_fd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -34,7 +34,7 @@ parse_program_arguments (int argc, char **argv)
|
|||
};
|
||||
|
||||
struct opt_handler oh =
|
||||
opt_handler_make (argc, argv, opts, "CONFIG", "PRNG.");
|
||||
opt_handler_make (argc, argv, opts, NULL, "PRNG.");
|
||||
|
||||
int c;
|
||||
while ((c = opt_handler_get (&oh)) != -1)
|
||||
|
|
Loading…
Reference in New Issue