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 */
zoo_getname(void)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 */
zoo_open(char * zooname)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
zoo_close(zoo_t z)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
zoo_mark(zoo_t z,char * entry)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
zoo_mark_cmdline(zoo_t z,pid_t p,char * tag,char * cmdline)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
zoo_mark_args(zoo_t z,pid_t p,char * tag,int ac,char ** av)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
zoo_clear(zoo_t z,pid_t p)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
zoo_getpid(zoo_t z,char * tag)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
zoo_lock(zoo_t z)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
zoo_unlock(zoo_t z)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
cat_args(int argc,char ** argv)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
zt_add(zoo_t z,int n)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
main(int argc,char * argv[])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