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