/******************************************************************************/ /* */ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* */ /* Author: Li Zefan <lizf@cn.fujitsu.com> */ /* */ /******************************************************************************/ #include <unistd.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <pwd.h> #include <sys/types.h> #include <sys/wait.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; int status; 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); } else { /* Parent should wait for the child */ wait(&status); } } /** * 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) { int 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; signal(SIGCHLD, SIG_IGN); /* 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; }