Home | History | Annotate | Download | only in pan
      1 /*
      2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of version 2 of the GNU General Public License as
      6  * published by the Free Software Foundation.
      7  *
      8  * This program is distributed in the hope that it would be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * Further, this software is distributed without any warranty that it is
     13  * free of the rightful claim of any third person regarding infringement
     14  * or the like.  Any license provided herein, whether implied or
     15  * otherwise, applies only to this software file.  Patent licenses, if
     16  * any, provided herein do not apply to combinations of this program with
     17  * other software, or any other product whatsoever.
     18  *
     19  * You should have received a copy of the GNU General Public License along
     20  * with this program; if not, write the Free Software Foundation, Inc.,
     21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     22  *
     23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
     24  * Mountain View, CA  94043, or:
     25  *
     26  * http://www.sgi.com
     27  *
     28  * For further information regarding this notice, see:
     29  *
     30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
     31  *
     32  */
     33 /* $Id: zoolib.c,v 1.8 2009/06/09 17:59:46 subrata_modak Exp $ */
     34 /*
     35  * ZooLib
     36  *
     37  * A Zoo is a file used to record what test tags are running at the moment.
     38  * If the system crashes, we should be able to look at the zoo file to find out
     39  * what was currently running.  This is especially helpful when running multiple
     40  * tests at the same time.
     41  *
     42  * The zoo file is meant to be a text file that fits on a standard console.
     43  * You should be able to watch it with `cat zoofile`
     44  *
     45  * zoo file format:
     46  * 	80 characters per line, ending with a \n
     47  * 	available lines start with '#'
     48  * 	expected line fromat: pid_t,tag,cmdline
     49  *
     50  */
     51 
     52 #include <signal.h>
     53 #include <stdlib.h>		/* for getenv */
     54 #include <string.h>
     55 #include "zoolib.h"
     56 
     57 char zoo_error[ZELEN];
     58 
     59 #ifdef __linux__
     60 /* glibc2.2 definition needs -D_XOPEN_SOURCE, which breaks other things. */
     61 extern int sighold(int __sig);
     62 extern int sigrelse(int __sig);
     63 #endif
     64 
     65 /* zoo_mark(): private function to make an entry to the zoo
     66  * 	returns 0 on success, -1 on error */
     67 static int zoo_mark(zoo_t z, char *entry);
     68 static int zoo_lock(zoo_t z);
     69 static int zoo_unlock(zoo_t z);
     70 /* cat_args(): helper function to make cmdline from argc, argv */
     71 char *cat_args(int argc, char **argv);
     72 
     73 /* zoo_getname(): create a filename to use for the zoo */
     74 char *zoo_getname(void)
     75 {
     76 	char buf[1024];
     77 	char *zoo;
     78 
     79 	zoo = getenv("ZOO");
     80 	if (zoo) {
     81 		snprintf(buf, 1024, "%s/%s", zoo, "active");
     82 		return strdup(buf);
     83 	} else {
     84 		/* if there is no environment variable, we don't know where to put it */
     85 		return NULL;
     86 	}
     87 }
     88 
     89 /* zoo_open(): open a zoo for use */
     90 zoo_t zoo_open(char *zooname)
     91 {
     92 	zoo_t new_zoo;
     93 
     94 	new_zoo = (zoo_t) fopen(zooname, "r+");
     95 	if (!new_zoo) {
     96 		if (errno == ENOENT) {
     97 			/* file doesn't exist, try fopen(xxx, "a+") */
     98 			new_zoo = (zoo_t) fopen(zooname, "a+");
     99 			if (!new_zoo) {
    100 				/* total failure */
    101 				snprintf(zoo_error, ZELEN,
    102 					 "Could not open zoo as \"%s\", errno:%d %s",
    103 					 zooname, errno, strerror(errno));
    104 				return 0;
    105 			}
    106 			fclose(new_zoo);
    107 			new_zoo = fopen(zooname, "r+");
    108 		} else {
    109 			snprintf(zoo_error, ZELEN,
    110 				 "Could not open zoo as \"%s\", errno:%d %s",
    111 				 zooname, errno, strerror(errno));
    112 		}
    113 	}
    114 	return new_zoo;
    115 }
    116 
    117 int zoo_close(zoo_t z)
    118 {
    119 	int ret;
    120 
    121 	ret = fclose(z);
    122 	if (ret) {
    123 		snprintf(zoo_error, ZELEN,
    124 			 "closing zoo caused error, errno:%d %s",
    125 			 errno, strerror(errno));
    126 	}
    127 	return ret;
    128 }
    129 
    130 static int zoo_mark(zoo_t z, char *entry)
    131 {
    132 	FILE *fp = (FILE *) z;
    133 	int found = 0;
    134 	long pos;
    135 	char buf[BUFLEN];
    136 
    137 	if (fp == NULL)
    138 		return -1;
    139 
    140 	if (zoo_lock(z))
    141 		return -1;
    142 
    143 	/* first fit */
    144 	rewind(fp);
    145 
    146 	do {
    147 		pos = ftell(fp);
    148 
    149 		if (fgets(buf, BUFLEN, fp) == NULL)
    150 			break;
    151 
    152 		if (buf[0] == '#') {
    153 			rewind(fp);
    154 			if (fseek(fp, pos, SEEK_SET)) {
    155 				/* error */
    156 				snprintf(zoo_error, ZELEN,
    157 					 "seek error while writing to zoo file, errno:%d %s",
    158 					 errno, strerror(errno));
    159 				return -1;
    160 			}
    161 			/* write the entry, left justified, and padded/truncated to the
    162 			 * same size as the previous entry */
    163 			fprintf(fp, "%-*.*s\n", (int)strlen(buf) - 1,
    164 				(int)strlen(buf) - 1, entry);
    165 			found = 1;
    166 			break;
    167 		}
    168 	} while (1);
    169 
    170 	if (!found) {
    171 		if (fseek(fp, 0, SEEK_END)) {
    172 			snprintf(zoo_error, ZELEN,
    173 				 "error seeking to end of zoo file, errno:%d %s",
    174 				 errno, strerror(errno));
    175 			return -1;
    176 		}
    177 		fprintf(fp, "%-*.*s\n", 79, 79, entry);
    178 	}
    179 	fflush(fp);
    180 
    181 	if (zoo_unlock(z))
    182 		return -1;
    183 	return 0;
    184 }
    185 
    186 int zoo_mark_cmdline(zoo_t z, pid_t p, char *tag, char *cmdline)
    187 {
    188 	char new_entry[BUFLEN];
    189 
    190 	snprintf(new_entry, 80, "%d,%s,%s", p, tag, cmdline);
    191 	return zoo_mark(z, new_entry);
    192 }
    193 
    194 int zoo_mark_args(zoo_t z, pid_t p, char *tag, int ac, char **av)
    195 {
    196 	char *cmdline;
    197 	int ret;
    198 
    199 	cmdline = cat_args(ac, av);
    200 	ret = zoo_mark_cmdline(z, p, tag, cmdline);
    201 
    202 	free(cmdline);
    203 	return ret;
    204 }
    205 
    206 int zoo_clear(zoo_t z, pid_t p)
    207 {
    208 	FILE *fp = (FILE *) z;
    209 	long pos;
    210 	char buf[BUFLEN];
    211 	pid_t that_pid;
    212 	int found = 0;
    213 
    214 	if (fp == NULL)
    215 		return -1;
    216 
    217 	if (zoo_lock(z))
    218 		return -1;
    219 	rewind(fp);
    220 
    221 	do {
    222 		pos = ftell(fp);
    223 
    224 		if (fgets(buf, BUFLEN, fp) == NULL)
    225 			break;
    226 
    227 		if (buf[0] == '#')
    228 			continue;
    229 
    230 		that_pid = atoi(buf);
    231 		if (that_pid == p) {
    232 			if (fseek(fp, pos, SEEK_SET)) {
    233 				/* error */
    234 				snprintf(zoo_error, ZELEN,
    235 					 "seek error while writing to zoo file, errno:%d %s",
    236 					 errno, strerror(errno));
    237 				return -1;
    238 			}
    239 			if (ftell(fp) != pos) {
    240 				printf("fseek failed\n");
    241 			}
    242 			fputs("#", fp);
    243 			found = 1;
    244 			break;
    245 		}
    246 	} while (1);
    247 
    248 	fflush(fp);
    249 
    250 	/* FIXME: unlock zoo file */
    251 	if (zoo_unlock(z))
    252 		return -1;
    253 
    254 	if (!found) {
    255 		snprintf(zoo_error, ZELEN,
    256 			 "zoo_clear() did not find pid(%d)", p);
    257 		return 1;
    258 	}
    259 	return 0;
    260 
    261 }
    262 
    263 pid_t zoo_getpid(zoo_t z, char *tag)
    264 {
    265 	FILE *fp = (FILE *) z;
    266 	char buf[BUFLEN], *s;
    267 	pid_t this_pid = -1;
    268 
    269 	if (fp == NULL)
    270 		return -1;
    271 
    272 	if (zoo_lock(z))
    273 		return -1;
    274 
    275 	rewind(fp);
    276 	do {
    277 		if (fgets(buf, BUFLEN, fp) == NULL)
    278 			break;
    279 
    280 		if (buf[0] == '#')
    281 			continue;	/* recycled line */
    282 
    283 		if ((s = strchr(buf, ',')) == NULL)
    284 			continue;	/* line was not expected format */
    285 
    286 		if (strncmp(s + 1, tag, strlen(tag)))
    287 			continue;	/* tag does not match */
    288 
    289 		this_pid = atoi(buf);
    290 		break;
    291 	} while (1);
    292 
    293 	if (zoo_unlock(z))
    294 		return -1;
    295 	return this_pid;
    296 }
    297 
    298 int zoo_lock(zoo_t z)
    299 {
    300 	FILE *fp = (FILE *) z;
    301 	struct flock zlock;
    302 	sigset_t block_these;
    303 	int ret;
    304 
    305 	if (fp == NULL)
    306 		return -1;
    307 
    308 	zlock.l_whence = zlock.l_start = zlock.l_len = 0;
    309 	zlock.l_type = F_WRLCK;
    310 
    311 	sigemptyset(&block_these);
    312 	sigaddset(&block_these, SIGINT);
    313 	sigaddset(&block_these, SIGTERM);
    314 	sigaddset(&block_these, SIGHUP);
    315 	sigaddset(&block_these, SIGUSR1);
    316 	sigaddset(&block_these, SIGUSR2);
    317 	sigprocmask(SIG_BLOCK, &block_these, NULL);
    318 
    319 	do {
    320 		ret = fcntl(fileno(fp), F_SETLKW, &zlock);
    321 	} while (ret == -1 && errno == EINTR);
    322 
    323 	sigprocmask(SIG_UNBLOCK, &block_these, NULL);
    324 	if (ret == -1) {
    325 		snprintf(zoo_error, ZELEN,
    326 			 "failed to unlock zoo file, errno:%d %s",
    327 			 errno, strerror(errno));
    328 		return -1;
    329 	}
    330 	return 0;
    331 
    332 }
    333 
    334 int zoo_unlock(zoo_t z)
    335 {
    336 	FILE *fp = (FILE *) z;
    337 	struct flock zlock;
    338 	sigset_t block_these;
    339 	int ret;
    340 
    341 	if (fp == NULL)
    342 		return -1;
    343 
    344 	zlock.l_whence = zlock.l_start = zlock.l_len = 0;
    345 	zlock.l_type = F_UNLCK;
    346 
    347 	sigemptyset(&block_these);
    348 	sigaddset(&block_these, SIGINT);
    349 	sigaddset(&block_these, SIGTERM);
    350 	sigaddset(&block_these, SIGHUP);
    351 	sigaddset(&block_these, SIGUSR1);
    352 	sigaddset(&block_these, SIGUSR2);
    353 	sigprocmask(SIG_BLOCK, &block_these, NULL);
    354 
    355 	do {
    356 		ret = fcntl(fileno(fp), F_SETLKW, &zlock);
    357 	} while (ret == -1 && errno == EINTR);
    358 
    359 	sigprocmask(SIG_UNBLOCK, &block_these, NULL);
    360 
    361 	if (ret == -1) {
    362 		snprintf(zoo_error, ZELEN,
    363 			 "failed to lock zoo file, errno:%d %s",
    364 			 errno, strerror(errno));
    365 		return -1;
    366 	}
    367 	return 0;
    368 }
    369 
    370 char *cat_args(int argc, char **argv)
    371 {
    372 	int a, size;
    373 	char *cmd;
    374 
    375 	for (size = a = 0; a < argc; a++) {
    376 		size += strlen(argv[a]);
    377 		size++;
    378 	}
    379 
    380 	if ((cmd = malloc(size)) == NULL) {
    381 		snprintf(zoo_error, ZELEN,
    382 			 "Malloc Error, %s/%d", __FILE__, __LINE__);
    383 		return NULL;
    384 	}
    385 
    386 	*cmd = '\0';
    387 	for (a = 0; a < argc; a++) {
    388 		if (a != 0)
    389 			strcat(cmd, " ");
    390 		strcat(cmd, argv[a]);
    391 	}
    392 
    393 	return cmd;
    394 }
    395 
    396 #if defined(UNIT_TEST)
    397 
    398 void zt_add(zoo_t z, int n)
    399 {
    400 	char cmdline[200];
    401 	char tag[10];
    402 
    403 	snprintf(tag, 10, "%s%d", "test", n);
    404 	snprintf(cmdline, 200, "%s%d %s %s %s", "runtest", n, "one", "two",
    405 		 "three");
    406 
    407 	zoo_mark_cmdline(z, n, tag, cmdline);
    408 }
    409 
    410 int main(int argc, char *argv[])
    411 {
    412 
    413 	char *zooname;
    414 	zoo_t test_zoo;
    415 	char *test_tag = "unittest";
    416 	int i, j;
    417 
    418 	zooname = zoo_getname();
    419 
    420 	if (!zooname) {
    421 		zooname = strdup("test_zoo");
    422 	}
    423 	printf("Test zoo filename is %s\n", zooname);
    424 
    425 	if ((test_zoo = zoo_open(zooname)) == NULL) {
    426 		printf("Error opennning zoo\n");
    427 		exit(-1);
    428 	}
    429 
    430 	zoo_mark_args(test_zoo, getpid(), test_tag, argc, argv);
    431 
    432 	for (j = 0; j < 5; j++) {
    433 		for (i = 0; i < 20; i++) {
    434 			zt_add(test_zoo, i);
    435 		}
    436 
    437 		for (; i >= 0; i--) {
    438 			zoo_clear(test_zoo, i);
    439 		}
    440 	}
    441 
    442 	zoo_clear(test_zoo, getpid());
    443 
    444 	return 0;
    445 }
    446 
    447 #endif
    448