1 /* zxbuslist.c  -  Utility for listening for events on zxbus
2  * Copyright (c) 2012 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3  * This is confidential unpublished proprietary source code of the author.
4  * NO WARRANTY, not even implied warranties. Contains trade secrets.
5  * Distribution prohibited unless authorized in writing.
6  * Licensed under Apache License 2.0, see file COPYING.
7  * $Id$
8  *
9  * 27.8.2012, created --Sampo
10  */
11 
12 #include "platform.h"  /* for dirent.h and unistd.h */
13 
14 #include <signal.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <sys/wait.h>
20 
21 #include "errmac.h"
22 #include "zx.h"
23 #include "zxid.h"
24 #include "zxidutil.h"
25 #include "zxidconf.h"
26 #include "c/zxidvers.h"
27 #include "c/zx-const.h"
28 #include "c/zx-ns.h"
29 #include "c/zx-data.h"
30 
31 char* help =
32 "zxbuslist  -  Listen to zxbus and send output to stdout R" ZXID_REL "\n\
33 zxbus is an Audit Bus for TAS3 or end2end Trus Assurance (e2eTA).\n\
34 Copyright (c) 2012 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.\n\
35 NO WARRANTY, not even implied warranties. Licensed under Apache License v2.0\n\
36 See http://www.apache.org/licenses/LICENSE-2.0\n\
37 Send well researched bug reports to the author. Home: zxid.org\n\
38 \n\
39 Usage: zxbuslist [options] > bus-traffic\n\
40   -c CONF          Optional configuration string (default -c PATH=/var/zxid/)\n\
41                    Most of the configuration is read from " ZXID_CONF_PATH "\n\
42   -c 'BUS_URL=stomps://localhost:2229/'   -- Typical invocation, indicates zxbusd to contact\n\
43   -ch CHAN         Indicate channel to subscribe to\n\
44   -o N             One-shot mode. Receive N messages and then exit. If -1, get all available.\n\
45   -it N            Number of threads launching parallel sessions, for benchmarking.\n\
46   -pid PATH        Write process id in the supplied path\n\
47   -p               Do not persist. Default is to persist in style similar to zxbus,\n\
48                    in /var/zxid/HOST/ch/DEST directory\n\
49   -v               Verbose messages.\n\
50   -q               Be extra quiet.\n\
51   -d               Turn on debugging.\n\
52   -dc              Dump config.\n\
53   -a -a            Turn on ascii coloring for stdout.\n\
54   -h               This help message\n\
55   --               End of options\n\
56 \n";
57 
58 extern int zxbus_ascii_color;
59 int dryrun  = 0;
60 extern int zxbus_verbose;
61 int n_thr = 1;
62 char* pid_path = 0;
63 char* chan = "default";
64 zxid_conf* cf;
65 int zxbus_oneshot = -2;  /* -2=Infinite listen (blocks as needed), -1=get all immediately available, >1, get specified number of messages (blocking if needed). */
66 extern int zxbus_persist_flag;
67 
68 /* Called by:  main x8, zxbusd_main, zxbuslist_main, zxbustailf_main, zxcall_main, zxcot_main, zxdecode_main */
opt(int * argc,char *** argv,char *** env)69 static void opt(int* argc, char*** argv, char*** env)
70 {
71   struct zx_str* ss;
72   if (*argc <= 1) return;
73 
74   while (1) {
75     ++(*argv); --(*argc);
76 
77     if (!(*argc) || ((*argv)[0][0] != '-')) break;  /* normal exit from options loop */
78 
79     switch ((*argv)[0][1]) {
80     case '-': if ((*argv)[0][2]) break;
81       ++(*argv); --(*argc);
82       DD("End of options by --");
83       return;  /* -- ends the options */
84 
85     case 'a':
86       switch ((*argv)[0][2]) {
87       case '\0':
88 	++zxbus_ascii_color;;
89 	continue;
90       }
91       break;
92 
93     case 'c':
94       switch ((*argv)[0][2]) {
95       case '\0':
96 	++(*argv); --(*argc);
97 	if ((*argc) < 1) break;
98 	zxid_parse_conf(cf, (*argv)[0]);
99 	continue;
100       case 'h':
101 	++(*argv); --(*argc);
102 	if ((*argc) < 1) break;
103 	chan = (*argv)[0];
104 	continue;
105       }
106       break;
107 
108     case 'd':
109       switch ((*argv)[0][2]) {
110       case '\0':
111 	++errmac_debug;
112 	if (errmac_debug == 2)
113 	  strncpy(errmac_instance, "\t\e[43mzxbuslist\e[0m", sizeof(errmac_instance));
114 	continue;
115       case 'c':
116 	ss = zxid_show_conf(cf);
117 	if (zxbus_verbose>1) {
118 	  fprintf(stdout, "\n======== CONF ========\n%.*s\n^^^^^^^^ CONF ^^^^^^^^\n",ss->len,ss->s);
119 	  exit(0);
120 	}
121 	fprintf(stderr, "\n======== CONF ========\n%.*s\n^^^^^^^^ CONF ^^^^^^^^\n",ss->len,ss->s);
122 	continue;
123       }
124       break;
125 
126     case 'i':
127       switch ((*argv)[0][2]) {
128       case 't':
129 	if ((*argv)[0][3]) break;
130 	++(*argv); --(*argc);
131 	if (!(*argc)) break;
132 	n_thr = atoi((*argv)[0]);
133 	continue;
134       }
135       break;
136 
137     case 'o':
138       switch ((*argv)[0][2]) {
139       case '\0':
140 	++(*argv); --(*argc);
141 	if (!(*argc)) break;
142 	zxbus_oneshot = atoi((*argv)[0]);
143 	continue;
144       }
145       break;
146 
147     case 'p':
148       switch ((*argv)[0][2]) {
149       case '\0':
150 	--zxbus_persist_flag;
151 	continue;
152       case 'i':
153 	if (!strcmp((*argv)[0],"-pid")) {
154 	  ++(*argv); --(*argc);
155 	  if (!(*argc)) break;
156 	  pid_path = (*argv)[0];
157 	  continue;
158 	}
159 	break;
160       }
161       break;
162 
163     case 'n':
164       switch ((*argv)[0][2]) {
165       case '\0':
166 	++dryrun;
167 	continue;
168       }
169       break;
170 
171     case 'q':
172       switch ((*argv)[0][2]) {
173       case '\0':
174 	zxbus_verbose = 0;
175 	continue;
176       }
177       break;
178 
179     case 'v':
180       switch ((*argv)[0][2]) {
181       case '\0':
182 	++zxbus_verbose;
183 	continue;
184       }
185       break;
186 
187     }
188     /* fall thru means unrecognized flag */
189     if (*argc)
190       fprintf(stderr, "Unrecognized flag `%s'\n", (*argv)[0]);
191 help:
192     if (zxbus_verbose>1) {
193       fprintf(stdout, "%s", help);
194       exit(0);
195     }
196     fprintf(stderr, "%s", help);
197     /*fprintf(stderr, "version=0x%06x rel(%s)\n", zxid_version(), zxid_version_str());*/
198     exit(3);
199   }
200 }
201 
202 /* Alias some struct fields for headers that can not be seen together. */
203 #define receipt   host
204 #define rcpt_id   host
205 #define acpt_vers vers
206 #define tx_id     vers
207 #define session   login
208 #define subs_id   login
209 #define subsc     login
210 #define server    pw
211 #define ack       pw
212 #define msg_id    pw
213 #define heart_bt  dest
214 
215 #ifndef zxbuslist_main
216 #define zxbuslist_main main
217 #endif
218 extern int zxid_suppress_vpath_warning;
219 
220 /* Called by: */
sig_alarm_to_stop_blocking_read(int signum)221 static void sig_alarm_to_stop_blocking_read(int signum)
222 {
223   D("blocking read interrupted signum(%d)", signum);
224   exit(0);
225 }
226 
227 /*() Audit Bus listening tool */
228 
229 /* Called by: */
zxbuslist_main(int argc,char ** argv,char ** env)230 int zxbuslist_main(int argc, char** argv, char** env)
231 {
232   int len,nt,pid;
233   struct zxid_bus_url* bu;
234   pid_t* kids;
235   strncpy(errmac_instance, "\tzxbuslist", sizeof(errmac_instance));
236   zxbus_verbose = 1;
237   zxid_suppress_vpath_warning = 1;
238   cf = zxid_new_conf_to_cf(0);
239   opt(&argc, &argv, &env);
240 
241   if (pid_path) {
242     int len;
243     char buf[INTSTRLEN];
244     len = sprintf(buf, "%d", (int)getpid());
245     DD("pid_path=`%s'", pid_path);
246     if (write2_or_append_lock_c_path(pid_path,0,0,len,buf, "write pid", SEEK_SET, O_TRUNC) <= 0) {
247       ERR("Failed to write PID file(%s). Exiting. (Do not supply -pid if you do not want pid file.)", pid_path);
248       exit(1);
249     }
250   }
251 
252   /* Cause exit(3) to be called with the intent that any gcov profiling will get
253    * written to disk before we die. If zxbusd is not stopped with `kill -USR1' and you
254    * use plain kill instead, the profile will indicate many unexecuted (#####) lines. */
255   if (signal(SIGUSR1, exit) == SIG_ERR) {
256     perror("signal USR1 exit");
257     exit(2);
258   }
259 
260   if (n_thr > 1) {
261     /* Fork test clients in great (specified) numbers. */
262     kids = ZX_ALLOC(cf->ctx, n_thr * sizeof(pid_t));
263 
264     for (nt = 0; nt < n_thr; ++nt) {
265       if ((kids[nt] = fork()) == -1) { perror("fork"); exit(1); }
266       if (!kids[n_thr])
267 	goto kid;
268     }
269     D("All forked (%d), now waiting...", n_thr);
270     for (nt = 0; nt < n_thr; ++nt) {
271       if ((pid = wait(&len))==-1) { perror("wait"); exit(1); }
272       if (WIFEXITED(len)) {
273 	if (WEXITSTATUS(len)) {
274 	  ERR("wait(%d): Process exited with nozero status %x.", pid, WEXITSTATUS(len));
275 	}
276       } else {
277 	ERR("wait(%d): Process died abnormally %x.", pid, len);
278       }
279     }
280     D("All waited (%d), done.", n_thr);
281     return 0;
282   } else {
283     nt = -1;
284   }
285  kid:
286 
287   bu = cf->bus_url;
288   if (!bu || !bu->s || !bu->s[0]) {
289     ERR("No bus_url configured means audit bus reporting is disabled. %p", bu);
290     return 1;
291   }
292 
293   /* *** implement intelligent lbfo algo */
294 
295   if (!bu->fd)
296     zxbus_open_bus_url(cf, bu);
297   if (!bu->fd)
298     return 1;
299   zxbus_send_cmdf(cf, bu, 0, 0, "SUBSCRIBE\ndestination:%s\nid:0\nack:client-individual\nreceipt:%d\n\n", chan, bu->cur_rcpt++);
300 
301   if (zxbus_oneshot == -1) {
302     /* In case we hit a blocking read, then this alarm will unblock us
303      * and allow return. */
304     signal(SIGALRM, (void*)sig_alarm_to_stop_blocking_read);
305     alarm(1);
306   }
307   while (zxbus_oneshot && zxbus_listen_msg(cf, bu))
308     --zxbus_oneshot;
309   zxbus_close_all(cf);
310   return 0;
311 }
312 
313 /* EOF  --  zxbuslist.c */
314