You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
9.1 KiB
448 lines
9.1 KiB
/*
|
|
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* Further, this software is distributed without any warranty that it is
|
|
* free of the rightful claim of any third person regarding infringement
|
|
* or the like. Any license provided herein, whether implied or
|
|
* otherwise, applies only to this software file. Patent licenses, if
|
|
* any, provided herein do not apply to combinations of this program with
|
|
* other software, or any other product whatsoever.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
|
* Mountain View, CA 94043, or:
|
|
*
|
|
* http://www.sgi.com
|
|
*
|
|
* For further information regarding this notice, see:
|
|
*
|
|
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
|
|
*
|
|
*/
|
|
/* $Id: zoolib.c,v 1.8 2009/06/09 17:59:46 subrata_modak Exp $ */
|
|
/*
|
|
* ZooLib
|
|
*
|
|
* A Zoo is a file used to record what test tags are running at the moment.
|
|
* If the system crashes, we should be able to look at the zoo file to find out
|
|
* what was currently running. This is especially helpful when running multiple
|
|
* tests at the same time.
|
|
*
|
|
* The zoo file is meant to be a text file that fits on a standard console.
|
|
* You should be able to watch it with `cat zoofile`
|
|
*
|
|
* zoo file format:
|
|
* 80 characters per line, ending with a \n
|
|
* available lines start with '#'
|
|
* expected line fromat: pid_t,tag,cmdline
|
|
*
|
|
*/
|
|
|
|
#include <signal.h>
|
|
#include <stdlib.h> /* for getenv */
|
|
#include <string.h>
|
|
#include "zoolib.h"
|
|
|
|
char zoo_error[ZELEN];
|
|
|
|
#ifdef __linux__
|
|
/* glibc2.2 definition needs -D_XOPEN_SOURCE, which breaks other things. */
|
|
extern int sighold(int __sig);
|
|
extern int sigrelse(int __sig);
|
|
#endif
|
|
|
|
/* zoo_mark(): private function to make an entry to the zoo
|
|
* returns 0 on success, -1 on error */
|
|
static int zoo_mark(zoo_t z, char *entry);
|
|
static int zoo_lock(zoo_t z);
|
|
static int zoo_unlock(zoo_t z);
|
|
/* cat_args(): helper function to make cmdline from argc, argv */
|
|
char *cat_args(int argc, char **argv);
|
|
|
|
/* zoo_getname(): create a filename to use for the zoo */
|
|
char *zoo_getname(void)
|
|
{
|
|
char buf[1024];
|
|
char *zoo;
|
|
|
|
zoo = getenv("ZOO");
|
|
if (zoo) {
|
|
snprintf(buf, 1024, "%s/%s", zoo, "active");
|
|
return strdup(buf);
|
|
} else {
|
|
/* if there is no environment variable, we don't know where to put it */
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* zoo_open(): open a zoo for use */
|
|
zoo_t zoo_open(char *zooname)
|
|
{
|
|
zoo_t new_zoo;
|
|
|
|
new_zoo = (zoo_t) fopen(zooname, "r+");
|
|
if (!new_zoo) {
|
|
if (errno == ENOENT) {
|
|
/* file doesn't exist, try fopen(xxx, "a+") */
|
|
new_zoo = (zoo_t) fopen(zooname, "a+");
|
|
if (!new_zoo) {
|
|
/* total failure */
|
|
snprintf(zoo_error, ZELEN,
|
|
"Could not open zoo as \"%s\", errno:%d %s",
|
|
zooname, errno, strerror(errno));
|
|
return 0;
|
|
}
|
|
fclose(new_zoo);
|
|
new_zoo = fopen(zooname, "r+");
|
|
} else {
|
|
snprintf(zoo_error, ZELEN,
|
|
"Could not open zoo as \"%s\", errno:%d %s",
|
|
zooname, errno, strerror(errno));
|
|
}
|
|
}
|
|
return new_zoo;
|
|
}
|
|
|
|
int zoo_close(zoo_t z)
|
|
{
|
|
int ret;
|
|
|
|
ret = fclose(z);
|
|
if (ret) {
|
|
snprintf(zoo_error, ZELEN,
|
|
"closing zoo caused error, errno:%d %s",
|
|
errno, strerror(errno));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int zoo_mark(zoo_t z, char *entry)
|
|
{
|
|
FILE *fp = (FILE *) z;
|
|
int found = 0;
|
|
long pos;
|
|
char buf[BUFLEN];
|
|
|
|
if (fp == NULL)
|
|
return -1;
|
|
|
|
if (zoo_lock(z))
|
|
return -1;
|
|
|
|
/* first fit */
|
|
rewind(fp);
|
|
|
|
do {
|
|
pos = ftell(fp);
|
|
|
|
if (fgets(buf, BUFLEN, fp) == NULL)
|
|
break;
|
|
|
|
if (buf[0] == '#') {
|
|
rewind(fp);
|
|
if (fseek(fp, pos, SEEK_SET)) {
|
|
/* error */
|
|
snprintf(zoo_error, ZELEN,
|
|
"seek error while writing to zoo file, errno:%d %s",
|
|
errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
/* write the entry, left justified, and padded/truncated to the
|
|
* same size as the previous entry */
|
|
fprintf(fp, "%-*.*s\n", (int)strlen(buf) - 1,
|
|
(int)strlen(buf) - 1, entry);
|
|
found = 1;
|
|
break;
|
|
}
|
|
} while (1);
|
|
|
|
if (!found) {
|
|
if (fseek(fp, 0, SEEK_END)) {
|
|
snprintf(zoo_error, ZELEN,
|
|
"error seeking to end of zoo file, errno:%d %s",
|
|
errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
fprintf(fp, "%-*.*s\n", 79, 79, entry);
|
|
}
|
|
fflush(fp);
|
|
|
|
if (zoo_unlock(z))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
int zoo_mark_cmdline(zoo_t z, pid_t p, char *tag, char *cmdline)
|
|
{
|
|
char new_entry[BUFLEN];
|
|
|
|
snprintf(new_entry, 80, "%d,%s,%s", p, tag, cmdline);
|
|
return zoo_mark(z, new_entry);
|
|
}
|
|
|
|
int zoo_mark_args(zoo_t z, pid_t p, char *tag, int ac, char **av)
|
|
{
|
|
char *cmdline;
|
|
int ret;
|
|
|
|
cmdline = cat_args(ac, av);
|
|
ret = zoo_mark_cmdline(z, p, tag, cmdline);
|
|
|
|
free(cmdline);
|
|
return ret;
|
|
}
|
|
|
|
int zoo_clear(zoo_t z, pid_t p)
|
|
{
|
|
FILE *fp = (FILE *) z;
|
|
long pos;
|
|
char buf[BUFLEN];
|
|
pid_t that_pid;
|
|
int found = 0;
|
|
|
|
if (fp == NULL)
|
|
return -1;
|
|
|
|
if (zoo_lock(z))
|
|
return -1;
|
|
rewind(fp);
|
|
|
|
do {
|
|
pos = ftell(fp);
|
|
|
|
if (fgets(buf, BUFLEN, fp) == NULL)
|
|
break;
|
|
|
|
if (buf[0] == '#')
|
|
continue;
|
|
|
|
that_pid = atoi(buf);
|
|
if (that_pid == p) {
|
|
if (fseek(fp, pos, SEEK_SET)) {
|
|
/* error */
|
|
snprintf(zoo_error, ZELEN,
|
|
"seek error while writing to zoo file, errno:%d %s",
|
|
errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
if (ftell(fp) != pos) {
|
|
printf("fseek failed\n");
|
|
}
|
|
fputs("#", fp);
|
|
found = 1;
|
|
break;
|
|
}
|
|
} while (1);
|
|
|
|
fflush(fp);
|
|
|
|
/* FIXME: unlock zoo file */
|
|
if (zoo_unlock(z))
|
|
return -1;
|
|
|
|
if (!found) {
|
|
snprintf(zoo_error, ZELEN,
|
|
"zoo_clear() did not find pid(%d)", p);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
pid_t zoo_getpid(zoo_t z, char *tag)
|
|
{
|
|
FILE *fp = (FILE *) z;
|
|
char buf[BUFLEN], *s;
|
|
pid_t this_pid = -1;
|
|
|
|
if (fp == NULL)
|
|
return -1;
|
|
|
|
if (zoo_lock(z))
|
|
return -1;
|
|
|
|
rewind(fp);
|
|
do {
|
|
if (fgets(buf, BUFLEN, fp) == NULL)
|
|
break;
|
|
|
|
if (buf[0] == '#')
|
|
continue; /* recycled line */
|
|
|
|
if ((s = strchr(buf, ',')) == NULL)
|
|
continue; /* line was not expected format */
|
|
|
|
if (strncmp(s + 1, tag, strlen(tag)))
|
|
continue; /* tag does not match */
|
|
|
|
this_pid = atoi(buf);
|
|
break;
|
|
} while (1);
|
|
|
|
if (zoo_unlock(z))
|
|
return -1;
|
|
return this_pid;
|
|
}
|
|
|
|
int zoo_lock(zoo_t z)
|
|
{
|
|
FILE *fp = (FILE *) z;
|
|
struct flock zlock;
|
|
sigset_t block_these;
|
|
int ret;
|
|
|
|
if (fp == NULL)
|
|
return -1;
|
|
|
|
zlock.l_whence = zlock.l_start = zlock.l_len = 0;
|
|
zlock.l_type = F_WRLCK;
|
|
|
|
sigemptyset(&block_these);
|
|
sigaddset(&block_these, SIGINT);
|
|
sigaddset(&block_these, SIGTERM);
|
|
sigaddset(&block_these, SIGHUP);
|
|
sigaddset(&block_these, SIGUSR1);
|
|
sigaddset(&block_these, SIGUSR2);
|
|
sigprocmask(SIG_BLOCK, &block_these, NULL);
|
|
|
|
do {
|
|
ret = fcntl(fileno(fp), F_SETLKW, &zlock);
|
|
} while (ret == -1 && errno == EINTR);
|
|
|
|
sigprocmask(SIG_UNBLOCK, &block_these, NULL);
|
|
if (ret == -1) {
|
|
snprintf(zoo_error, ZELEN,
|
|
"failed to unlock zoo file, errno:%d %s",
|
|
errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
int zoo_unlock(zoo_t z)
|
|
{
|
|
FILE *fp = (FILE *) z;
|
|
struct flock zlock;
|
|
sigset_t block_these;
|
|
int ret;
|
|
|
|
if (fp == NULL)
|
|
return -1;
|
|
|
|
zlock.l_whence = zlock.l_start = zlock.l_len = 0;
|
|
zlock.l_type = F_UNLCK;
|
|
|
|
sigemptyset(&block_these);
|
|
sigaddset(&block_these, SIGINT);
|
|
sigaddset(&block_these, SIGTERM);
|
|
sigaddset(&block_these, SIGHUP);
|
|
sigaddset(&block_these, SIGUSR1);
|
|
sigaddset(&block_these, SIGUSR2);
|
|
sigprocmask(SIG_BLOCK, &block_these, NULL);
|
|
|
|
do {
|
|
ret = fcntl(fileno(fp), F_SETLKW, &zlock);
|
|
} while (ret == -1 && errno == EINTR);
|
|
|
|
sigprocmask(SIG_UNBLOCK, &block_these, NULL);
|
|
|
|
if (ret == -1) {
|
|
snprintf(zoo_error, ZELEN,
|
|
"failed to lock zoo file, errno:%d %s",
|
|
errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *cat_args(int argc, char **argv)
|
|
{
|
|
int a, size;
|
|
char *cmd;
|
|
|
|
for (size = a = 0; a < argc; a++) {
|
|
size += strlen(argv[a]);
|
|
size++;
|
|
}
|
|
|
|
if ((cmd = malloc(size)) == NULL) {
|
|
snprintf(zoo_error, ZELEN,
|
|
"Malloc Error, %s/%d", __FILE__, __LINE__);
|
|
return NULL;
|
|
}
|
|
|
|
*cmd = '\0';
|
|
for (a = 0; a < argc; a++) {
|
|
if (a != 0)
|
|
strcat(cmd, " ");
|
|
strcat(cmd, argv[a]);
|
|
}
|
|
|
|
return cmd;
|
|
}
|
|
|
|
#if defined(UNIT_TEST)
|
|
|
|
void zt_add(zoo_t z, int n)
|
|
{
|
|
char cmdline[200];
|
|
char tag[10];
|
|
|
|
snprintf(tag, 10, "%s%d", "test", n);
|
|
snprintf(cmdline, 200, "%s%d %s %s %s", "runtest", n, "one", "two",
|
|
"three");
|
|
|
|
zoo_mark_cmdline(z, n, tag, cmdline);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
|
|
char *zooname;
|
|
zoo_t test_zoo;
|
|
char *test_tag = "unittest";
|
|
int i, j;
|
|
|
|
zooname = zoo_getname();
|
|
|
|
if (!zooname) {
|
|
zooname = strdup("test_zoo");
|
|
}
|
|
printf("Test zoo filename is %s\n", zooname);
|
|
|
|
if ((test_zoo = zoo_open(zooname)) == NULL) {
|
|
printf("Error opennning zoo\n");
|
|
exit(-1);
|
|
}
|
|
|
|
zoo_mark_args(test_zoo, getpid(), test_tag, argc, argv);
|
|
|
|
for (j = 0; j < 5; j++) {
|
|
for (i = 0; i < 20; i++) {
|
|
zt_add(test_zoo, i);
|
|
}
|
|
|
|
for (; i >= 0; i--) {
|
|
zoo_clear(test_zoo, i);
|
|
}
|
|
}
|
|
|
|
zoo_clear(test_zoo, getpid());
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|