1 /******************************************************************************/
2 /* */
3 /* Copyright (c) 2008 FUJITSU LIMITED */
4 /* */
5 /* This program is free software; you can redistribute it and/or modify */
6 /* it under the terms of the GNU General Public License as published by */
7 /* the Free Software Foundation; either version 2 of the License, or */
8 /* (at your option) any later version. */
9 /* */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
13 /* the GNU General Public License for more details. */
14 /* */
15 /* You should have received a copy of the GNU General Public License */
16 /* along with this program; if not, write to the Free Software */
17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18 /* */
19 /* Author: Li Zefan <lizf@cn.fujitsu.com> */
20 /* */
21 /******************************************************************************/
22
23 #include <sys/socket.h>
24 #include <sys/poll.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <signal.h>
32 #include <linux/types.h>
33 #include <linux/netlink.h>
34
35 #ifndef NETLINK_CONNECTOR
36
main(void)37 int main(void)
38 {
39 return 2;
40 }
41
42 #else
43
44 #include <linux/connector.h>
45
46 #ifndef CN_IDX_PROC
47
main(void)48 int main(void)
49 {
50 return 2;
51 }
52
53 #else
54
55 #define _LINUX_TIME_H
56 #include <linux/cn_proc.h>
57
58 #define PEC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event))
59 #define PEC_CTRL_MSG_SIZE (sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op))
60
61 #define MAX_MSG_SIZE 256
62
63 static __u32 seq;
64
65 static int exit_flag;
66 static struct sigaction sigint_action;
67
68 struct nlmsghdr *nlhdr;
69
70 /*
71 * Handler for signal int. Set exit flag.
72 *
73 * @signo: the signal number, not used
74 */
sigint_handler(int signo)75 static void sigint_handler(int __attribute__ ((unused)) signo)
76 {
77 exit_flag = 1;
78 }
79
80 /*
81 * Send netlink package.
82 *
83 * @sd: socket descripor
84 * @to: the destination sockaddr
85 * @cnmsg: the pec control message
86 */
netlink_send(int sd,struct sockaddr_nl * to,struct cn_msg * cnmsg)87 static int netlink_send(int sd, struct sockaddr_nl *to, struct cn_msg *cnmsg)
88 {
89 int ret;
90 struct iovec iov;
91 struct msghdr msg;
92
93 memset(nlhdr, 0, NLMSG_SPACE(MAX_MSG_SIZE));
94
95 nlhdr->nlmsg_seq = seq++;
96 nlhdr->nlmsg_pid = getpid();
97 nlhdr->nlmsg_type = NLMSG_DONE;
98 nlhdr->nlmsg_len = NLMSG_LENGTH(sizeof(*cnmsg) + cnmsg->len);
99 nlhdr->nlmsg_flags = 0;
100 memcpy(NLMSG_DATA(nlhdr), cnmsg, sizeof(*cnmsg) + cnmsg->len);
101
102 memset(&iov, 0, sizeof(struct iovec));
103 iov.iov_base = (void *)nlhdr;
104 iov.iov_len = nlhdr->nlmsg_len;
105
106 memset(&msg, 0, sizeof(struct msghdr));
107 msg.msg_name = (void *)to;
108 msg.msg_namelen = sizeof(*to);
109 msg.msg_iov = &iov;
110 msg.msg_iovlen = 1;
111
112 ret = sendmsg(sd, &msg, 0);
113
114 return ret;
115 }
116
117 /*
118 * Receive package from netlink.
119 *
120 * @sd: socket descripor
121 * @from: source sockaddr
122 */
netlink_recv(int sd,struct sockaddr_nl * from)123 static int netlink_recv(int sd, struct sockaddr_nl *from)
124 {
125 int ret;
126 struct iovec iov;
127 struct msghdr msg;
128
129 memset(nlhdr, 0, NLMSG_SPACE(MAX_MSG_SIZE));
130 memset(&iov, 0, sizeof(iov));
131 memset(&msg, 0, sizeof(msg));
132
133 iov.iov_base = (void *)nlhdr;
134 iov.iov_len = NLMSG_SPACE(MAX_MSG_SIZE);
135
136 msg.msg_name = (void *)from;
137 msg.msg_namelen = sizeof(*from);
138 msg.msg_iov = &iov;
139 msg.msg_iovlen = 1;
140
141 ret = recvmsg(sd, &msg, 0);
142
143 return ret;
144 }
145
146 /*
147 * Send control message to PEC.
148 *
149 * @sd: socket descriptor
150 * @to: the destination sockaddr
151 * @op: control flag
152 */
control_pec(int sd,struct sockaddr_nl * to,enum proc_cn_mcast_op op)153 static int control_pec(int sd, struct sockaddr_nl *to, enum proc_cn_mcast_op op)
154 {
155 int ret;
156 char buf[PEC_CTRL_MSG_SIZE];
157 struct cn_msg *cnmsg;
158 enum proc_cn_mcast_op *pec_op;
159
160 memset(buf, 0, sizeof(buf));
161
162 cnmsg = (struct cn_msg *)buf;
163 cnmsg->id.idx = CN_IDX_PROC;
164 cnmsg->id.val = CN_VAL_PROC;
165 cnmsg->seq = seq++;
166 cnmsg->ack = 0;
167 cnmsg->len = sizeof(op);
168
169 pec_op = (enum proc_cn_mcast_op *)cnmsg->data;
170 *pec_op = op;
171
172 ret = netlink_send(sd, to, cnmsg);
173
174 return ret;
175 }
176
177 /*
178 * Process PEC event.
179 *
180 * @nlhdr: the netlinke pacakge
181 */
process_event(struct nlmsghdr * nlhdr)182 static void process_event(struct nlmsghdr *nlhdr)
183 {
184 struct cn_msg *msg;
185 struct proc_event *pe;
186
187 msg = (struct cn_msg *)NLMSG_DATA(nlhdr);
188
189 pe = (struct proc_event *)msg->data;
190
191 switch (pe->what) {
192 case PROC_EVENT_NONE:
193 printf("none err: %u\n", pe->event_data.ack.err);
194 break;
195 case PROC_EVENT_FORK:
196 printf("fork parent: %d, child: %d\n",
197 pe->event_data.fork.parent_pid,
198 pe->event_data.fork.child_pid);
199 break;
200 case PROC_EVENT_EXEC:
201 printf("exec pid: %d\n", pe->event_data.exec.process_pid);
202 break;
203 case PROC_EVENT_UID:
204 printf("uid pid: %d euid: %d ruid: %d\n",
205 pe->event_data.id.process_pid,
206 pe->event_data.id.e.euid, pe->event_data.id.r.ruid);
207 break;
208 case PROC_EVENT_GID:
209 printf("gid pid: %d egid: %d rgid: %d\n",
210 pe->event_data.id.process_pid,
211 pe->event_data.id.e.egid, pe->event_data.id.r.rgid);
212 break;
213 case PROC_EVENT_EXIT:
214 printf("exit pid: %d exit_code: %d exit_signal: %d\n",
215 pe->event_data.exit.process_pid,
216 pe->event_data.exit.exit_code,
217 pe->event_data.exit.exit_signal);
218 break;
219 default:
220 printf("unknown event\n");
221 break;
222 }
223 }
224
main(int argc,char ** argv)225 int main(int argc, char **argv)
226 {
227 int ret;
228 int sd;
229 struct sockaddr_nl l_local;
230 struct sockaddr_nl src_addr;
231 struct pollfd pfd;
232
233 sigint_action.sa_flags = SA_RESETHAND;
234 sigint_action.sa_handler = &sigint_handler;
235 sigaction(SIGINT, &sigint_action, NULL);
236
237 nlhdr = malloc(NLMSG_SPACE(MAX_MSG_SIZE));
238 if (!nlhdr) {
239 fprintf(stderr, "lack of memory\n");
240 exit(1);
241 }
242
243 sd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
244 if (sd == -1) {
245 fprintf(stderr, "failed to create socket\n");
246 exit(1);
247 }
248
249 memset(&src_addr, 0, sizeof(src_addr));
250 src_addr.nl_family = AF_NETLINK;
251 src_addr.nl_pid = 0;
252 src_addr.nl_groups = 0;
253
254 memset(&l_local, 0, sizeof(l_local));
255 l_local.nl_family = AF_NETLINK;
256 l_local.nl_pid = getpid();
257 l_local.nl_groups = CN_IDX_PROC;
258
259 ret = bind(sd, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl));
260 if (ret == -1) {
261 fprintf(stderr, "failed to bind socket\n");
262 exit(1);
263 }
264
265 /* Open PEC listening */
266 ret = control_pec(sd, &src_addr, PROC_CN_MCAST_LISTEN);
267 if (!ret) {
268 fprintf(stderr, "failed to open PEC listening\n");
269 exit(1);
270 }
271
272 /* Receive msg from PEC */
273 pfd.fd = sd;
274 pfd.events = POLLIN;
275 pfd.revents = 0;
276 while (!exit_flag) {
277
278 ret = poll(&pfd, 1, -1);
279 if (ret == 0 || (ret == -1 && errno != EINTR)) {
280 control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE);
281 fprintf(stderr, "failed to poll\n");
282 exit(1);
283 } else if (ret == -1 && errno == EINTR)
284 break;
285
286 ret = netlink_recv(sd, &src_addr);
287
288 if (ret == 0)
289 break;
290 else if (ret == -1 && errno == EINTR)
291 break;
292 else if (ret == -1 && errno != EINTR) {
293 control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE);
294 fprintf(stderr, "failed to receive from netlink\n");
295 exit(1);
296 } else {
297 switch (nlhdr->nlmsg_type) {
298 case NLMSG_ERROR:
299 fprintf(stderr, "err message received.\n");
300 exit(1);
301 break;
302 case NLMSG_DONE:
303 /* message sent from kernel */
304 if (nlhdr->nlmsg_pid == 0)
305 process_event(nlhdr);
306 break;
307 default:
308 break;
309 }
310 }
311 }
312
313 /* Close PEC listening */
314 ret = control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE);
315 if (!ret) {
316 fprintf(stderr, "failed to close PEC listening\n");
317 exit(1);
318 }
319
320 close(sd);
321 free(nlhdr);
322
323 while (fsync(STDOUT_FILENO) == -1) {
324 if (errno != EIO)
325 break;
326 /* retry once every 10 secodns */
327 sleep(10);
328 }
329
330 return 0;
331 }
332
333 #endif /* CN_IDX_PROC */
334
335 #endif /* NETLINK_CONNECTOR */
336