From: Subrata M. <su...@li...> - 2008-06-12 08:55:00
|
Thanks for this. I will test and get back to you soon. Regards-- Subrata On Thu, 2008-06-12 at 14:18 +0800, Li Zefan wrote: > Process event connector is a netlink connector that reports process > events to userspace, and currently we have 5 kinds of process events, > i.e. fork, exit, exec, uid, gid. > > There are total 5 test cases to test its functionality. > > But the test is not run by default, because I don't find a way to > decide whether the underlying kernel supports this feather or not. > > Signed-off-by: Li Zefan <li...@cn...> > --- > runtest/connectors | 2 > testcases/kernel/connectors/Makefile | 10 > testcases/kernel/connectors/pec/Makefile | 13 > testcases/kernel/connectors/pec/README | 46 +++ > testcases/kernel/connectors/pec/event_generator.c | 227 ++++++++++++++++ > testcases/kernel/connectors/pec/pec_listener.c | 309 ++++++++++++++++++++++ > testcases/kernel/connectors/pec/run_pec_test | 92 ++++++ > 7 files changed, 699 insertions(+) > > diff -Nurp ltp-full-20080531.orig/runtest/connectors ltp-full-20080531/runtest/connectors > --- ltp-full-20080531.orig/runtest/connectors 1970-01-01 08:00:00.000000000 +0800 > +++ ltp-full-20080531/runtest/connectors 2008-06-12 13:46:44.000000000 +0800 > @@ -0,0 +1,2 @@ > +#DESCRIPTION:Netlink Connector tests > +Connectors run_pec_test > diff -Nurp ltp-full-20080531.orig/testcases/kernel/connectors/Makefile ltp-full-20080531/testcases/kernel/connectors/Makefile > --- ltp-full-20080531.orig/testcases/kernel/connectors/Makefile 1970-01-01 08:00:00.000000000 +0800 > +++ ltp-full-20080531/testcases/kernel/connectors/Makefile 2008-05-21 09:50:24.000000000 +0800 > @@ -0,0 +1,10 @@ > +SUBDIRS = pec > + > +all: > + @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i ; done > + > +install: > + @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i install ; done > + > +clean: > + @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean ; done > diff -Nurp ltp-full-20080531.orig/testcases/kernel/connectors/pec/event_generator.c ltp-full-20080531/testcases/kernel/connectors/pec/event_generator.c > --- ltp-full-20080531.orig/testcases/kernel/connectors/pec/event_generator.c 1970-01-01 08:00:00.000000000 +0800 > +++ ltp-full-20080531/testcases/kernel/connectors/pec/event_generator.c 2008-05-21 10:48:09.000000000 +0800 > @@ -0,0 +1,227 @@ > +/******************************************************************************/ > +/* */ > +/* 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 <li...@cn...> */ > +/* */ > +/******************************************************************************/ > + > +#include <unistd.h> > +#include <string.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <pwd.h> > +#include "test.h" > + > +#define DEFAULT_EVENT_NUM 1 > + > +unsigned long nr_event = DEFAULT_EVENT_NUM; > + > +uid_t ltp_uid; > +gid_t ltp_gid; > +const char *ltp_user = "nobody"; > + > +char **exec_argv; > + > +void (*gen_event)(void); > + > +/* > + * Show the usage > + * > + * @status: the exit status > + */ > +static void usage(int status) > +{ > + FILE *stream = (status ? stderr : stdout); > + > + fprintf(stream, "Usage: event_generator -e fork|exit|exec|uid|gid [-n nr_event]\n"); > + > + exit(status); > +} > + > +/* > + * Generate exec event. > + * > + * We can't just exec nr_event times, because the current process image > + * will be replaced with the new process image, so we use enviroment > + * viriable as event counters, as it will be inherited after exec. > + */ > +static void gen_exec(void) > +{ > + char *val; > + char buf[10]; > + unsigned long nr_exec; > + > + /* get the event counter */ > + val = getenv("NR_EXEC"); > + if (!val) { > + nr_exec = 0; > + setenv("NR_EXEC", "1", 1); > + } else { > + nr_exec = atoi(val); > + snprintf(buf, 10, "%lu", nr_exec + 1); > + setenv("NR_EXEC", buf, 1); > + } > + > + /* stop generate exec event */ > + if (nr_exec >= nr_event) > + return; > + > + /* fflush is needed before exec */ > + printf("exec pid: %d\n", getpid()); > + fflush(stdout); > + > + execv(exec_argv[0], exec_argv); > +} > + > +/* > + * Generate fork event. > + */ > +static inline void gen_fork(void) > +{ > + pid_t pid; > + > + pid = fork(); > + if (pid == 0) { > + printf("fork parent: %d, child: %d\n", getppid(), getpid()); > + exit(0); > + } else if (pid < 0) { > + fprintf(stderr, "fork() failed\n"); > + exit(1); > + } > +} > + > +/** > + * Generate exit event > + */ > +static inline void gen_exit(void) > +{ > + pid_t pid; > + > + pid = fork(); > + if (pid == 0) { > + printf("exit pid: %d exit_code: %d\n", getpid(), 0); > + exit(0); > + } else if (pid < 0){ > + fprintf(stderr, "fork() failed\n"); > + exit(1); > + } > +} > + > +/* > + * Generate uid event. > + */ > +static inline void gen_uid(void) > +{ > + setuid(ltp_uid); > + printf("uid pid: %d euid: %d\n", getpid(), ltp_uid); > +} > + > +/* > + * Generate gid event. > + */ > +static inline void gen_gid(void) > +{ > + setgid(ltp_gid); > + printf("gid pid: %d egid: %d\n", getpid(), ltp_gid); > +} > + > +/* > + * Read option from user input. > + * > + * @argc: number of arguments > + * @argv: argument list > + */ > +static void process_options(int argc, char **argv) > +{ > + char c; > + char *end; > + > + while ((c = getopt(argc, argv, "e:n:h")) != -1) { > + switch (c) { > + /* which event to generate */ > + case 'e': > + if (!strcmp(optarg, "exec")) > + gen_event = gen_exec; > + else if (!strcmp(optarg, "fork")) > + gen_event = gen_fork; > + else if (!strcmp(optarg, "exit")) > + gen_event = gen_exit; > + else if (!strcmp(optarg, "uid")) > + gen_event = gen_uid; > + else if (!strcmp(optarg, "gid")) > + gen_event = gen_gid; > + else { > + fprintf(stderr, "wrong -e argument!"); > + exit(1); > + } > + break; > + /* number of event to generate */ > + case 'n': > + nr_event = strtoul(optarg, &end, 10); > + if (*end != '\0' || nr_event == 0) { > + fprintf(stderr, "wrong -n argument!"); > + exit(1); > + } > + break; > + /* help */ > + case 'h': > + usage(0); > + default: > + fprintf(stderr, "unknown option!\n"); > + usage(1); > + } > + } > + > + if (!gen_event) { > + fprintf(stderr, "no event type specified!\n"); > + usage(1); > + } > +} > + > +int main(int argc, char **argv) > +{ > + unsigned long i; > + struct passwd *ent; > + > + process_options(argc, argv); > + > + ent = getpwnam(ltp_user); > + if (ent == NULL) { > + fprintf(stderr, "can't get password entry for %s", ltp_user); > + exit(1); > + } > + ltp_uid = ent->pw_uid; > + ltp_gid = ent->pw_gid; > + > + /* special processing for gen_exec, see comments above gen_exec() */ > + if (gen_event == gen_exec) { > + exec_argv = argv; > + > + gen_exec(); > + > + /* won't reach here */ > + return 0; > + } > + > + /* other events */ > + for (i = 0; i < nr_event; i++) > + gen_event(); > + > + return 0; > +} > + > diff -Nurp ltp-full-20080531.orig/testcases/kernel/connectors/pec/Makefile ltp-full-20080531/testcases/kernel/connectors/pec/Makefile > --- ltp-full-20080531.orig/testcases/kernel/connectors/pec/Makefile 1970-01-01 08:00:00.000000000 +0800 > +++ ltp-full-20080531/testcases/kernel/connectors/pec/Makefile 2008-05-20 10:33:55.000000000 +0800 > @@ -0,0 +1,13 @@ > +CFLAGS += -I../../../../include -Wall > +LOADLIBES+= -L../../../../lib -lltp > + > +SRCS:=$(wildcard *.c) > +TARGETS:=$(patsubst %.c,%,$(SRCS)) > + > +all: $(TARGETS) > + > +install: > + @set -e; for i in $(TARGETS) ; do ln -f $$i ../../../bin/$$i ; chmod +x run_pec_test ; done ; > + ln -f run_pec_test ../../../bin/ > +clean: > + rm -f $(TARGETS) > diff -Nurp ltp-full-20080531.orig/testcases/kernel/connectors/pec/pec_listener.c ltp-full-20080531/testcases/kernel/connectors/pec/pec_listener.c > --- ltp-full-20080531.orig/testcases/kernel/connectors/pec/pec_listener.c 1970-01-01 08:00:00.000000000 +0800 > +++ ltp-full-20080531/testcases/kernel/connectors/pec/pec_listener.c 2008-05-21 10:48:01.000000000 +0800 > @@ -0,0 +1,309 @@ > +/******************************************************************************/ > +/* */ > +/* 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 <li...@cn...> */ > +/* */ > +/******************************************************************************/ > + > +#include <unistd.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <errno.h> > +#include <signal.h> > +#include <sys/socket.h> > +#include <sys/poll.h> > + > +#include <linux/netlink.h> > +#include <linux/connector.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; > + > +/* > + * 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; > + char buf[MAX_MSG_SIZE]; > + struct nlmsghdr *nlhdr; > + struct iovec iov; > + struct msghdr msg; > + > + memset(buf, 0, MAX_MSG_SIZE); > + > + nlhdr = (struct nlmsghdr *)buf; > + > + 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 > + * @buf: buffer for storing the package > + */ > +static int netlink_recv(int sd, struct sockaddr_nl *from, char *buf) > +{ > + int ret; > + struct nlmsghdr *nlhdr = (struct nlmsghdr *)buf; > + 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; > + char buf[MAX_MSG_SIZE]; > + struct pollfd pfd; > + > + sigint_action.sa_flags = SA_ONESHOT; > + sigint_action.sa_handler = &sigint_handler; > + sigaction(SIGINT, &sigint_action, NULL); > + > + /* Create and bind socket */ > + 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) { > + struct nlmsghdr *nlhdr; > + > + 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, buf); > + > + 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 { > + nlhdr = (struct nlmsghdr *)buf; > + > + 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); > + > + return 0; > +} > + > diff -Nurp ltp-full-20080531.orig/testcases/kernel/connectors/pec/README ltp-full-20080531/testcases/kernel/connectors/pec/README > --- ltp-full-20080531.orig/testcases/kernel/connectors/pec/README 1970-01-01 08:00:00.000000000 +0800 > +++ ltp-full-20080531/testcases/kernel/connectors/pec/README 2008-05-20 10:07:44.000000000 +0800 > @@ -0,0 +1,46 @@ > + > +TEST SUITE: > + > +The directory pec contains the tests related to the process event connector. > + > +Process event connector is a netlink connector that reports process events > +to userspace. It sends events such as fork, exec, id change and exit. > + > +There are total 5 testcases. > + > +TESTS AIM: > + > +The aim of the tests is to test the functionality of process event connector. > + > +FILES DESCRIPTION: > + > +check_connector_enabled.c > +------------------ > +This program is used to check if the kernel supports netlink connector. > + > +event_generator.c > +------------------ > +This program is used to generate a specified process event (fork, exec, uid, > +gid or exit). > + > +run_pec_test > +------------------ > +This script runs all the 5 testcases. > + > +pec_listener.c > +------------------ > +This program is used to ilsten to process events received through the kernel > +connector and print them. > + > +Makefile > +------------------ > +The usual makefile for this directory > + > +$LTPROOT/output/pec/*.log > +------------------ > +The outputs of event_generator and pec_listeners. > + > +README: > +------------------ > +The one you have gone through. > + > diff -Nurp ltp-full-20080531.orig/testcases/kernel/connectors/pec/run_pec_test ltp-full-20080531/testcases/kernel/connectors/pec/run_pec_test > --- ltp-full-20080531.orig/testcases/kernel/connectors/pec/run_pec_test 1970-01-01 08:00:00.000000000 +0800 > +++ ltp-full-20080531/testcases/kernel/connectors/pec/run_pec_test 2008-06-12 13:42:07.000000000 +0800 > @@ -0,0 +1,92 @@ > +#! /bin/bash > + > +################################################################################ > +## ## > +## 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 <li...@cn...> ## > +## ## > +################################################################################ > + > +if [ -z $LTPROOT ]; then > + LTPROOT="`cd ../../../.. && pwd`" > + PATH="$PATH:$LTPROOT/testcases/bin" > + mkdir $LTPROOT/output 2> /dev/null > +fi > + > +cd $LTPROOT/testcases/bin > + > +export TCID="pec01" > +export TST_TOTAL=5 > + > +exit_status=0 > + > +# Run a test case > +# > +# $1: the test number > +# $2: type of event > +run_case() > +{ > + export TST_COUNT=$1 > + > + log="$LTPROOT/output/log" > + mkdir $log 2> /dev/null > + > + ./pec_listener > "$log/listener_$1.log" 2>&1 & > + pid=$! > + sleep 1 > + > + ./event_generator -e $2 > "$log/generator_$1.log" & > + > + wait $! > + ret1=$? > + > + sleep 1 > + kill -s SIGINT $pid 2> /dev/null > + wait $pid > + ret2=$? > + > + if [ $ret1 -ne 0 -o ! -s "$log/generator_$1.log" ]; then > + tst_resm TFAIL "failed to generate process events" > + exit_status=1 > + return 1 > + fi > + > + if [ $ret2 -ne 0 ]; then > + tst_resm TFAIL "failed to listen process events" > + exit_status=1 > + return 1 > + fi > + > + event="`cat $log/generator_$1.log`" > + cat "$log/listener_$1.log" | grep "$event" > /dev/null > + if [ $? -eq 0 ]; then > + tst_resm TPASS "get event - $event" > + else > + tst_resm TFAIL "expected event - $event" > + exit_status=1 > + fi > +} > + > +run_case 1 "fork" > +run_case 2 "exec" > +run_case 3 "exit" > +run_case 4 "uid" > +run_case 5 "gid" > + > +exit $exit_status > + |