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