blob: 69bced70173d6e4e878d9fa475ebc5fe485cf69f [file] [log] [blame]
/******************************************************************************/
/* */
/* Copyright (c) 2008 FUJITSU LIMITED */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
/* the GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* Author: Li Zefan <lizf@cn.fujitsu.com> */
/* */
/******************************************************************************/
#include <sys/socket.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <linux/types.h>
#include <linux/netlink.h>
#ifndef NETLINK_CONNECTOR
int main(void)
{
return 2;
}
#else
#include <linux/connector.h>
#ifndef CN_IDX_PROC
int main(void)
{
return 2;
}
#else
#define _LINUX_TIME_H
#include <linux/cn_proc.h>
#define PEC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event))
#define PEC_CTRL_MSG_SIZE (sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op))
#define MAX_MSG_SIZE 256
static __u32 seq;
static int exit_flag;
static struct sigaction sigint_action;
struct nlmsghdr *nlhdr;
/*
* Handler for signal int. Set exit flag.
*
* @signo: the signal number, not used
*/
static void sigint_handler(int __attribute__((unused)) signo)
{
exit_flag = 1;
}
/*
* Send netlink package.
*
* @sd: socket descripor
* @to: the destination sockaddr
* @cnmsg: the pec control message
*/
static int netlink_send(int sd, struct sockaddr_nl *to, struct cn_msg *cnmsg)
{
int ret;
struct iovec iov;
struct msghdr msg;
memset(nlhdr, 0, NLMSG_SPACE(MAX_MSG_SIZE));
nlhdr->nlmsg_seq = seq++;
nlhdr->nlmsg_pid = getpid();
nlhdr->nlmsg_type = NLMSG_DONE;
nlhdr->nlmsg_len = NLMSG_LENGTH(sizeof(*cnmsg) + cnmsg->len);
nlhdr->nlmsg_flags = 0;
memcpy(NLMSG_DATA(nlhdr), cnmsg, sizeof(*cnmsg) + cnmsg->len);
memset(&iov, 0, sizeof(struct iovec));
iov.iov_base = (void *)nlhdr;
iov.iov_len = nlhdr->nlmsg_len;
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = (void *)to;
msg.msg_namelen = sizeof(*to);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
ret = sendmsg(sd, &msg, 0);
return ret;
}
/*
* Receive package from netlink.
*
* @sd: socket descripor
* @from: source sockaddr
*/
static int netlink_recv(int sd, struct sockaddr_nl *from)
{
int ret;
struct iovec iov;
struct msghdr msg;
memset(nlhdr, 0, NLMSG_SPACE(MAX_MSG_SIZE));
memset(&iov, 0, sizeof(iov));
memset(&msg, 0, sizeof(msg));
iov.iov_base = (void *)nlhdr;
iov.iov_len = NLMSG_SPACE(MAX_MSG_SIZE);
msg.msg_name = (void *)from;
msg.msg_namelen = sizeof(*from);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
ret = recvmsg(sd, &msg, 0);
return ret;
}
/*
* Send control message to PEC.
*
* @sd: socket descriptor
* @to: the destination sockaddr
* @op: control flag
*/
static int control_pec(int sd, struct sockaddr_nl *to, enum proc_cn_mcast_op op)
{
int ret;
char buf[PEC_CTRL_MSG_SIZE];
struct cn_msg *cnmsg;
enum proc_cn_mcast_op *pec_op;
memset(buf, 0, sizeof(buf));
cnmsg = (struct cn_msg *)buf;
cnmsg->id.idx = CN_IDX_PROC;
cnmsg->id.val = CN_VAL_PROC;
cnmsg->seq = seq++;
cnmsg->ack = 0;
cnmsg->len = sizeof(op);
pec_op = (enum proc_cn_mcast_op *)cnmsg->data;
*pec_op = op;
ret = netlink_send(sd, to, cnmsg);
return ret;
}
/*
* Process PEC event.
*
* @nlhdr: the netlinke pacakge
*/
static void process_event(struct nlmsghdr *nlhdr)
{
struct cn_msg *msg;
struct proc_event *pe;
msg = (struct cn_msg *)NLMSG_DATA(nlhdr);
pe = (struct proc_event *)msg->data;
switch (pe->what) {
case PROC_EVENT_NONE:
printf("none err: %u\n", pe->event_data.ack.err);
break;
case PROC_EVENT_FORK:
printf("fork parent: %d, child: %d\n",
pe->event_data.fork.parent_pid,
pe->event_data.fork.child_pid);
break;
case PROC_EVENT_EXEC:
printf("exec pid: %d\n",
pe->event_data.exec.process_pid);
break;
case PROC_EVENT_UID:
printf("uid pid: %d euid: %d ruid: %d\n",
pe->event_data.id.process_pid,
pe->event_data.id.e.euid,
pe->event_data.id.r.ruid);
break;
case PROC_EVENT_GID:
printf("gid pid: %d egid: %d rgid: %d\n",
pe->event_data.id.process_pid,
pe->event_data.id.e.egid,
pe->event_data.id.r.rgid);
break;
case PROC_EVENT_EXIT:
printf("exit pid: %d exit_code: %d exit_signal: %d\n",
pe->event_data.exit.process_pid,
pe->event_data.exit.exit_code,
pe->event_data.exit.exit_signal);
break;
default:
printf("unknown event\n");
break;
}
}
int main(int argc, char **argv)
{
int ret;
int sd;
struct sockaddr_nl l_local;
struct sockaddr_nl src_addr;
struct pollfd pfd;
sigint_action.sa_flags = SA_ONESHOT;
sigint_action.sa_handler = &sigint_handler;
sigaction(SIGINT, &sigint_action, NULL);
nlhdr = malloc(NLMSG_SPACE(MAX_MSG_SIZE));
if (!nlhdr) {
fprintf(stderr, "lack of memory\n");
exit(1);
}
sd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (sd == -1) {
fprintf(stderr, "failed to create socket\n");
exit(1);
}
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = 0;
src_addr.nl_groups = 0;
memset(&l_local, 0, sizeof(l_local));
l_local.nl_family = AF_NETLINK;
l_local.nl_pid = getpid();
l_local.nl_groups = CN_IDX_PROC;
ret = bind(sd, (struct sockaddr *)&l_local,
sizeof(struct sockaddr_nl));
if (ret == -1) {
fprintf(stderr, "failed to bind socket\n");
exit(1);
}
/* Open PEC listening */
ret = control_pec(sd, &src_addr, PROC_CN_MCAST_LISTEN);
if (!ret) {
fprintf(stderr, "failed to open PEC listening\n");
exit(1);
}
/* Receive msg from PEC */
pfd.fd = sd;
pfd.events = POLLIN;
pfd.revents = 0;
while (!exit_flag) {
ret = poll(&pfd, 1, -1);
if (ret == 0 || (ret == -1 && errno != EINTR)) {
control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE);
fprintf(stderr, "failed to poll\n");
exit(1);
} else if (ret == -1 && errno == EINTR)
break;
ret = netlink_recv(sd, &src_addr);
if (ret == 0)
break;
else if (ret == -1 && errno == EINTR)
break;
else if (ret == -1 && errno != EINTR) {
control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE);
fprintf(stderr, "failed to receive from netlink\n");
exit(1);
} else {
switch (nlhdr->nlmsg_type) {
case NLMSG_ERROR:
fprintf(stderr, "err message recieved.\n");
exit(1);
break;
case NLMSG_DONE:
/* message sent from kernel */
if (nlhdr->nlmsg_pid == 0)
process_event(nlhdr);
break;
default:
break;
}
}
}
/* Close PEC listening */
ret = control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE);
if (!ret) {
fprintf(stderr, "failed to close PEC listening\n");
exit(1);
}
close(sd);
free(nlhdr);
while (fsync(STDOUT_FILENO) == -1) {
if (errno != EIO)
break;
/* retry once every 10 secodns */
sleep(10);
}
return 0;
}
#endif /* CN_IDX_PROC */
#endif /* NETLINK_CONNECTOR */