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@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 */
usage(int status)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 */
gen_exec(void)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 */
gen_fork(void)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 */
gen_exit(void)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 */
gen_uid(void)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 */
gen_gid(void)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 */
process_options(int argc,char ** argv)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
main(int argc,char ** argv)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