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 <unistd.h> 24 #include <string.h> 25 #include <stdlib.h> 26 #include <stdio.h> 27 #include <pwd.h> 28 #include <sys/types.h> 29 #include <sys/wait.h> 30 31 #include "test.h" 32 33 #define DEFAULT_EVENT_NUM 1 34 35 unsigned long nr_event = DEFAULT_EVENT_NUM; 36 37 uid_t ltp_uid; 38 gid_t ltp_gid; 39 const char *ltp_user = "nobody"; 40 41 char **exec_argv; 42 43 void (*gen_event) (void); 44 45 /* 46 * Show the usage 47 * 48 * @status: the exit status 49 */ 50 static void usage(int status) 51 { 52 FILE *stream = (status ? stderr : stdout); 53 54 fprintf(stream, 55 "Usage: event_generator -e fork|exit|exec|uid|gid [-n nr_event]\n"); 56 57 exit(status); 58 } 59 60 /* 61 * Generate exec event. 62 * 63 * We can't just exec nr_event times, because the current process image 64 * will be replaced with the new process image, so we use enviroment 65 * viriable as event counters, as it will be inherited after exec. 66 */ 67 static void gen_exec(void) 68 { 69 char *val; 70 char buf[10]; 71 unsigned long nr_exec; 72 73 /* get the event counter */ 74 val = getenv("NR_EXEC"); 75 if (!val) { 76 nr_exec = 0; 77 setenv("NR_EXEC", "1", 1); 78 } else { 79 nr_exec = atoi(val); 80 snprintf(buf, 10, "%lu", nr_exec + 1); 81 setenv("NR_EXEC", buf, 1); 82 } 83 84 /* stop generate exec event */ 85 if (nr_exec >= nr_event) 86 return; 87 88 /* fflush is needed before exec */ 89 printf("exec pid: %d\n", getpid()); 90 fflush(stdout); 91 92 execv(exec_argv[0], exec_argv); 93 } 94 95 /* 96 * Generate fork event. 97 */ 98 static inline void gen_fork(void) 99 { 100 pid_t pid; 101 int status; 102 103 pid = fork(); 104 if (pid == 0) { 105 printf("fork parent: %d, child: %d\n", getppid(), getpid()); 106 exit(0); 107 } else if (pid < 0) { 108 fprintf(stderr, "fork() failed\n"); 109 exit(1); 110 } else { /* Parent should wait for the child */ 111 wait(&status); 112 } 113 } 114 115 /** 116 * Generate exit event 117 */ 118 static inline void gen_exit(void) 119 { 120 pid_t pid; 121 122 pid = fork(); 123 if (pid == 0) { 124 printf("exit pid: %d exit_code: %d\n", getpid(), 0); 125 exit(0); 126 } else if (pid < 0) { 127 fprintf(stderr, "fork() failed\n"); 128 exit(1); 129 } 130 } 131 132 /* 133 * Generate uid event. 134 */ 135 static inline void gen_uid(void) 136 { 137 setuid(ltp_uid); 138 printf("uid pid: %d euid: %d\n", getpid(), ltp_uid); 139 } 140 141 /* 142 * Generate gid event. 143 */ 144 static inline void gen_gid(void) 145 { 146 setgid(ltp_gid); 147 printf("gid pid: %d egid: %d\n", getpid(), ltp_gid); 148 } 149 150 /* 151 * Read option from user input. 152 * 153 * @argc: number of arguments 154 * @argv: argument list 155 */ 156 static void process_options(int argc, char **argv) 157 { 158 int c; 159 char *end; 160 161 while ((c = getopt(argc, argv, "e:n:h")) != -1) { 162 switch (c) { 163 /* which event to generate */ 164 case 'e': 165 if (!strcmp(optarg, "exec")) 166 gen_event = gen_exec; 167 else if (!strcmp(optarg, "fork")) 168 gen_event = gen_fork; 169 else if (!strcmp(optarg, "exit")) 170 gen_event = gen_exit; 171 else if (!strcmp(optarg, "uid")) 172 gen_event = gen_uid; 173 else if (!strcmp(optarg, "gid")) 174 gen_event = gen_gid; 175 else { 176 fprintf(stderr, "wrong -e argument!"); 177 exit(1); 178 } 179 break; 180 /* number of event to generate */ 181 case 'n': 182 nr_event = strtoul(optarg, &end, 10); 183 if (*end != '\0' || nr_event == 0) { 184 fprintf(stderr, "wrong -n argument!"); 185 exit(1); 186 } 187 break; 188 /* help */ 189 case 'h': 190 usage(0); 191 default: 192 fprintf(stderr, "unknown option!\n"); 193 usage(1); 194 } 195 } 196 197 if (!gen_event) { 198 fprintf(stderr, "no event type specified!\n"); 199 usage(1); 200 } 201 } 202 203 int main(int argc, char **argv) 204 { 205 unsigned long i; 206 struct passwd *ent; 207 208 process_options(argc, argv); 209 210 ent = getpwnam(ltp_user); 211 if (ent == NULL) { 212 fprintf(stderr, "can't get password entry for %s", ltp_user); 213 exit(1); 214 } 215 ltp_uid = ent->pw_uid; 216 ltp_gid = ent->pw_gid; 217 218 signal(SIGCHLD, SIG_IGN); 219 220 /* special processing for gen_exec, see comments above gen_exec() */ 221 if (gen_event == gen_exec) { 222 exec_argv = argv; 223 224 gen_exec(); 225 226 /* won't reach here */ 227 return 0; 228 } 229 230 /* other events */ 231 for (i = 0; i < nr_event; i++) 232 gen_event(); 233 234 return 0; 235 } 236