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