emehta-contrib/os_procwatch.c

102 lines
2.4 KiB
C

/*
* Copyright (c) 2009 Jilles Tjoelker, et al
* Rights to this code are as documented in doc/LICENSE.
*
* Monitors exit of given processes, using kqueue.
* The kqueue is added to the main poll loop.
*/
#include "atheme.h"
#include <sys/event.h>
DECLARE_MODULE_V1
(
"contrib/os_procwatch", false, _modinit, _moddeinit,
PACKAGE_STRING,
"Atheme Development Group <http://www.atheme.org>"
);
static void procwatch_readhandler(connection_t *cptr);
static void os_cmd_procwatch(sourceinfo_t *si, int parc, char *parv[]);
command_t os_procwatch = { "PROCWATCH", "Notifies snoop channel on process exit.",
PRIV_ADMIN, 1, os_cmd_procwatch, { .path = "contrib/procwatch" } };
static connection_t *kq_conn;
void _modinit(module_t *m)
{
int kq;
kq = kqueue();
if (kq == -1)
{
m->mflags = MODTYPE_FAIL;
return;
}
kq_conn = connection_add("procwatch kqueue", kq, 0, procwatch_readhandler, NULL);
service_named_bind_command("operserv", &os_procwatch);
}
void _moddeinit(module_unload_intent_t intent)
{
if (kq_conn != NULL)
connection_close_soon(kq_conn);
service_named_unbind_command("operserv", &os_procwatch);
}
static void procwatch_readhandler(connection_t *cptr)
{
struct kevent ev;
if (cptr != kq_conn)
{
slog(LG_INFO, "procwatch_readhandler(): called with unexpected fd %d", cptr->fd);
return;
}
while (kevent(cptr->fd, NULL, 0, &ev, 1, &(const struct timespec){ 0, 0 }) > 0)
{
slog(LG_INFO, "PROCWATCH: %ld exited with status %x",
(long)ev.ident, (unsigned)ev.data);
}
}
static void os_cmd_procwatch(sourceinfo_t *si, int parc, char *parv[])
{
long v;
char *end;
struct kevent ev;
if (parc == 0)
{
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "PROCWATCH");
command_fail(si, fault_needmoreparams, _("Syntax: PROCWATCH <pid>"));
return;
}
errno = 0;
v = strtol(parv[0], &end, 10);
if (errno != 0 || *end != '\0' || v < 0 || (pid_t)v != v)
{
command_fail(si, fault_needmoreparams, STR_INVALID_PARAMS, "PROCWATCH");
command_fail(si, fault_needmoreparams, _("Syntax: PROCWATCH <pid>"));
return;
}
EV_SET(&ev, v, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL);
if (kevent(kq_conn->fd, &ev, 1, NULL, 0, NULL) == -1)
{
command_fail(si, fault_toomany, _("Failed to add pid %ld"), v);
return;
}
command_success_nodata(si, "Added pid %ld to list.", v);
}
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
* vim:ts=8
* vim:sw=8
* vim:noexpandtab
*/