/* * Copyright (c) 2009 Jilles Tjoelker, et al * Rights to this code are as documented in doc/LICENSE. * * Reads data from a child process via a pipe. */ #include "atheme-compat.h" #include "datastream.h" #ifndef _WIN32 DECLARE_MODULE_V1 ( "contrib/os_testproc", false, _modinit, _moddeinit, PACKAGE_STRING, "Atheme Development Group " ); struct testprocdata { char dest[NICKLEN]; connection_t *pip; }; static struct testprocdata procdata; static void os_cmd_testproc(sourceinfo_t *si, int parc, char *parv[]); command_t os_testproc = { "TESTPROC", "Does something with child processes.", AC_NONE, 0, os_cmd_testproc, { .path = "contrib/testproc" } }; void _modinit(module_t *m) { service_named_bind_command("operserv", &os_testproc); } void _moddeinit(module_unload_intent_t intent) { if (procdata.pip != NULL) connection_close_soon(procdata.pip); service_named_unbind_command("operserv", &os_testproc); } static void testproc_recvqhandler(connection_t *cptr) { char buf[BUFSIZE]; int count; user_t *u; if (cptr != procdata.pip) { slog(LG_INFO, "testproc_recvqhandler(): called with unexpected fd %d", cptr->fd); return; } count = recvq_getline(cptr, buf, sizeof buf - 1); if (count <= 0) return; if (buf[count - 1] == '\n') count--; if (count > 0 && buf[count - 1] == '\r') count--; if (count == 0) buf[count++] = ' '; buf[count] = '\0'; u = user_find(procdata.dest); if (u != NULL) notice(service_find("operserv")->me->nick, u->nick, "%s", buf); } static void testproc_closehandler(connection_t *cptr) { if (cptr != procdata.pip) { slog(LG_INFO, "testproc_closehandler(): called with unexpected fd %d", cptr->fd); return; } slog(LG_DEBUG, "testproc_closehandler(): fd %d closed", cptr->fd); procdata.pip = NULL; } static void os_cmd_testproc(sourceinfo_t *si, int parc, char *parv[]) { int pipes[2]; if (si->su == NULL) { command_fail(si, fault_noprivs, _("\2%s\2 can only be executed via IRC."), "TESTPROC"); return; } if (procdata.pip != NULL) { command_fail(si, fault_toomany, "Another TESTPROC is still in progress"); return; } if (pipe(pipes) == -1) { command_fail(si, fault_toomany, "Failed to create pipe"); return; } switch (fork()) { case -1: close(pipes[0]); close(pipes[1]); command_fail(si, fault_toomany, "Failed to fork"); return; case 0: connection_close_all_fds(); close(pipes[0]); dup2(pipes[1], 1); dup2(pipes[1], 2); close(pipes[1]); execl("/bin/sh", "sh", "-c", "echo hi; sleep 1; echo hi 2; sleep 0.5; echo hi 3; sleep 4; echo hi 4", (char *)NULL); (void)write(2, "Failed to exec /bin/sh\n", 23); _exit(255); break; default: close(pipes[1]); procdata.pip = connection_add("testproc pipe", pipes[0], 0, recvq_put, NULL); procdata.pip->recvq_handler = testproc_recvqhandler; procdata.pip->close_handler = testproc_closehandler; mowgli_strlcpy(procdata.dest, CLIENT_NAME(si->su), sizeof procdata.dest); break; } } #endif /* 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 */