/* * 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; }