forked from atheme/atheme-contrib-modules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
os_testproc.c
138 lines (118 loc) · 3.1 KB
/
os_testproc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* 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 <http://www.atheme.org>"
);
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
*/