aboutsummaryrefslogtreecommitdiff
path: root/tests/fs-tests/stress/atoms/gcd_hupper.c
blob: 31c175da6e43e1a2755ac02b52cf7d9849e19eb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*
 * Copyright (C) 2007 Nokia Corporation.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * 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 St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 * Author: Adrian Hunter
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <mntent.h>
#include <signal.h>

#include "tests.h"

#define MAX_NAME_SIZE 1024

struct gcd_pid
{
	struct gcd_pid *next;
	int pid;
	char *name;
	int mtd_index;
};

struct gcd_pid *gcd_pid_list = NULL;

int add_gcd_pid(const char *number)
{
	int pid;
	FILE *f;
	char file_name[MAX_NAME_SIZE];
	char program_name[MAX_NAME_SIZE];

	pid = atoi(number);
	if (pid <= 0)
		return 0;
	snprintf(file_name, MAX_NAME_SIZE, "/proc/%s/stat", number);
	f = fopen(file_name, "r");
	if (f == NULL)
		return 0;
	if (fscanf(f, "%d %s", &pid, program_name) != 2) {
		fclose(f);
		return 0;
	}
	if (strncmp(program_name, "(jffs2_gcd_mtd", 14) != 0)
		pid = 0;
	if (pid) {
		size_t sz;
		struct gcd_pid *g;

		sz = sizeof(struct gcd_pid);
		g = (struct gcd_pid *) malloc(sz);
		g->pid = pid;
		g->name = (char *) malloc(strlen(program_name) + 1);
		if (g->name)
			strcpy(g->name, program_name);
		else
			exit(1);
		g->mtd_index = atoi(program_name + 14);
		g->next = gcd_pid_list;
		gcd_pid_list = g;
	}
	fclose(f);
	return pid;
}

int get_pid_list(void)
{
	DIR *dir;
	struct dirent *entry;

	dir = opendir("/proc");
	if (dir == NULL)
		return 1;
	for (;;) {
		entry = readdir(dir);
		if (entry) {
			if (strcmp(".",entry->d_name) != 0 &&
					strcmp("..",entry->d_name) != 0)
				add_gcd_pid(entry->d_name);
		} else
			break;
	}
	closedir(dir);
	return 0;
}

int parse_index_number(const char *name)
{
	const char *p, *q;
	int all_zero;
	int index;

	p = name;
	while (*p && !isdigit(*p))
		++p;
	if (!*p)
		return -1;
	all_zero = 1;
	for (q = p; *q; ++q) {
		if (!isdigit(*q))
			return -1;
		if (*q != '0')
			all_zero = 0;
	}
	if (all_zero)
		return 0;
	index = atoi(p);
	if (index <= 0)
		return -1;
	return index;
}

int get_mtd_index(void)
{
	FILE *f;
	struct mntent *entry;
	struct stat f_info;
	struct stat curr_f_info;
	int found;
	int mtd_index = -1;

	if (stat(tests_file_system_mount_dir, &f_info) == -1)
		return -1;
	f = fopen("/proc/mounts", "rb");
	if (!f)
		f = fopen("/etc/mtab", "rb");
	if (f == NULL)
		return -1;
	found = 0;
	for (;;) {
		entry = getmntent(f);
		if (!entry)
			break;
		if (stat(entry->mnt_dir, &curr_f_info) == -1)
			continue;
		if (f_info.st_dev == curr_f_info.st_dev) {
			int i;

			i = parse_index_number(entry->mnt_fsname);
			if (i != -1) {
				if (found && i != mtd_index)
					return -1;
				found = 1;
				mtd_index = i;
			}
		}
	}
	fclose(f);
	return mtd_index;
}

int get_gcd_pid()
{
	struct gcd_pid *g;
	int mtd_index;

	if (get_pid_list())
		return 0;
	mtd_index = get_mtd_index();
	if (mtd_index == -1)
		return 0;
	for (g = gcd_pid_list; g; g = g->next)
		if (g->mtd_index == mtd_index)
			return g->pid;
	return 0;
}

void gcd_hupper(void)
{
	int64_t repeat;
	int pid;

	pid = get_gcd_pid();
	CHECK(pid != 0);
	repeat = tests_repeat_parameter;
	for (;;) {
		CHECK(kill(pid, SIGHUP) != -1);
		/* Break if repeat count exceeded */
		if (tests_repeat_parameter > 0 && --repeat <= 0)
			break;
		/* Sleep */
		if (tests_sleep_parameter > 0) {
			unsigned us = tests_sleep_parameter * 1000;
			unsigned rand_divisor = RAND_MAX / us;
			unsigned s = (us / 2) + (rand() / rand_divisor);
			usleep(s);
		}
	}
}

/* Title of this test */

const char *gcd_hupper_get_title(void)
{
	return "Send HUP signals to gcd";
}

/* Description of this test */

const char *gcd_hupper_get_description(void)
{
	return
		"Determine the PID of the gcd process. " \
		"Send it SIGHUP (may require root privileges). " \
		"If a sleep value is specified, the process sleeps. " \
		"If a repeat count is specified, then the task repeats " \
		"that number of times. " \
		"The repeat count is given by the -n or --repeat option, " \
		"otherwise it defaults to 1. " \
		"A repeat count of zero repeats forever. " \
		"The sleep value is given by the -p or --sleep option, " \
		"otherwise it defaults to 1. "
		"Sleep is specified in milliseconds.";
}

int main(int argc, char *argv[])
{
	int run_test;

	/* Set default test repetition */
	tests_repeat_parameter = 1;

	/* Set default test sleep */
	tests_sleep_parameter = 1;

	/* Handle common arguments */
	run_test = tests_get_args(argc, argv, gcd_hupper_get_title(),
			gcd_hupper_get_description(), "np");
	if (!run_test)
		return 1;
	/* Change directory to the file system and check it is ok for testing */
	tests_check_test_file_system();
	/* Do the actual test */
	gcd_hupper();
	return 0;
}