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