Home | History | Annotate | Download | only in pec
      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 (at) 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 
     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 
     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  */
     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  */
     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  */
    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  */
    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  */
    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 
    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 recieved.\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