• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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