tevc.c 5.93 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
2
3
4
5
6
/*
 * EMULAB-COPYRIGHT
 * Copyright (c) 2000-2002 University of Utah and the Flux Group.
 * All rights reserved.
 */

7
8
9
10
/*
 * This is used to send Testbed events (reboot, ready, etc.) to the
 * testbed event client. It is intended to be wrapped up by a perl
 * script that will use the tmcc to figure out where the event server
11
12
13
14
15
16
 * lives (host/port) to construct the server string.
 *
 * Issues: key and pid/eid.
 *         valid events, names, types.
 *         valid arguments.
 *         vname to ipaddr mapping.
17
18
19
20
21
22
 */

#include <stdio.h>
#include <ctype.h>
#include <netdb.h>
#include <unistd.h>
23
24
#include <time.h>
#include <math.h>
25
26
27
28
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
29
30
#include "config.h"
#include "tbdefs.h"
31
32
#include "event.h"

33
static int debug;
34
35

void
36
usage(char *progname)
37
{
38
39
40
41
42
43
44
45
46
47
    fprintf(stderr,
	"Usage: %s [-s server] [-c] event\n"
	"       %s [-s server] -e pid/eid time objname event [args ...]\n"
	"       time: 'now' or '+seconds' or [[[[yy]mm]dd]HH]MMss\n"
	"Examples:\n"
	"       %s -e pid/eid now cbr0 set interval_=0.2\n"
	"       %s -e pid/eid +10 cbr0 start\n"
	"       %s -e pid/eid +20 cbr0 stop\n",
	progname, progname, progname, progname, progname);
    exit(-1);
48
49
50
51
52
53
54
55
}

int
main(int argc, char **argv)
{
	event_handle_t handle;
	event_notification_t notification;
	address_tuple_t	tuple;
56
	char *progname;
57
58
	char *server = NULL;
	char *port = NULL;
59
60
61
62
	int control = 0;
	char *myeid = NULL;
	char buf[BUFSIZ], *bp;
	char *evtime = NULL, *objname = NULL, *event;
63
64
65
66
	int c;

	progname = argv[0];
	
67
	while ((c = getopt(argc, argv, "ds:p:ce:")) != -1) {
68
		switch (c) {
69
70
71
		case 'd':
			debug++;
			break;
72
73
74
75
76
77
		case 's':
			server = optarg;
			break;
		case 'p':
			port = optarg;
			break;
78
79
80
81
82
		case 'c':
			control = 1;
			break;
		case 'e':
			myeid = optarg;
83
84
			break;
		default:
85
			usage(progname);
86
87
88
89
90
		}
	}
	argc -= optind;
	argv += optind;

91
92
93
94
95
96
97
98
99
100
101
102
103
104
	if (control) {
		if (geteuid())
			fatal("Only root can send TBCONTROL events");
		
		if (argc != 1)
			usage(progname);
		
		event = argv[0];
		argc -= 1;
		argv += 1;
	}
	else {
		if (argc < 3)
			usage(progname);
105

106
107
108
109
110
111
		evtime  = argv[0];
		objname = argv[1];
		event   = argv[2];

		argc -= 3;
		argv += 3;
112
	}
113
	loginit(0, 0);
114
115

	/*
116
117
118
	 * If server is not specified, then it defaults to BOSSNODE.
	 * This allows the client to work on either users.emulab.net
	 * or on a client node. 
119
	 */
120
121
	if (!server)
		server = BOSSNODE;
122
123
124
125
126
127

	/*
	 * Convert server/port to elvin thing.
	 *
	 * XXX This elvin string stuff should be moved down a layer. 
	 */
128
129
130
131
132
	snprintf(buf, sizeof(buf), "elvin://%s%s%s",
		 server,
		 (port ? ":"  : ""),
		 (port ? port : ""));
	server = buf;
133
134
135
136
137
138

	/*
	 * Construct an address tuple for generating the event.
	 */
	tuple = address_tuple_alloc();
	if (tuple == NULL) {
139
		fatal("could not allocate an address tuple");
140
	}
141
	
142
143
144
	/* Register with the event system: */
	handle = event_register(server, 0);
	if (handle == NULL) {
145
		fatal("could not register with event system");
146
147
	}

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
	if (control) {
		/*
		 * Send a control event.
		 */
		bp = event;
		while (*bp) {
			*bp = toupper(*bp);
			bp++;
		}
		if (! tbdb_valideventtype(event))
			fatal("Unknown %s event: %s",
			      OBJECTTYPE_TESTBED, event);
		
		tuple->objtype  = OBJECTTYPE_TESTBED;
		tuple->eventtype= event;
	}
	else {
		/*
		 * A dynamic event. 
		 */
		if (! myeid)
			fatal("Must provide pid/eid");

		bp = event;
		while (*bp) {
			*bp = toupper(*bp);
			bp++;
		}
		if (!strcmp(event, "SET"))
			event = TBDB_EVENTTYPE_MODIFY;
		else if (! tbdb_valideventtype(event))
			fatal("Unknown event: %s", event);
		
		tuple->objname   = objname;
		tuple->eventtype = event;
		tuple->expt      = myeid;
		tuple->site      = ADDRESSTUPLE_ANY;
		tuple->host      = ADDRESSTUPLE_ANY;
		tuple->group     = ADDRESSTUPLE_ANY;
	}

189
190
191
192
	/* Generate the event */
	notification = event_notification_alloc(handle, tuple);
	
	if (notification == NULL) {
193
		fatal("could not allocate notification");
194
195
	}

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
	/*
	 * If there are any extra arguments, insert them into
	 * the notification as an arg string.
	 *
	 * XXX For now, uppercase the strings, and remove trailing _.
	 */
	if (argc) {
		buf[0] = NULL;
		while (argc) {
			if (strlen(*argv) + strlen(buf) >= sizeof(buf)-2)
				fatal("Too many event argument strings!");

			bp = *argv;
			while (*bp && *bp != '=') {
				*bp = toupper(*bp);
				bp++;
			}
			if (*bp != '=')
				fatal("Malformed argument: %s!", *argv);
			if (*(bp-1) == '_')
				*(bp-1) = NULL;
			*bp++ = NULL;

			sprintf(&buf[strlen(buf)], "%s=%s ", *argv, bp);
			argc--;
			argv++;
		}
		event_notification_set_arguments(handle, notification, buf);
	}

	if (control) {
		if (event_notify(handle, notification) == 0) {
			fatal("could not send test event notification");
		}
	}
	else {
		struct timeval when;
		
		/*
		 * Parse the time. Now is special; set the time to 0.
		 */
		if (!strcmp(evtime, "now")) {
			gettimeofday(&when, NULL);
		}
		else if (evtime[0] == '+') {
			gettimeofday(&when, NULL);

			if (strchr(evtime, '.')) {
				double	val = atof(evtime);

				when.tv_sec  += (int) rint(val);
				when.tv_usec +=
					(int) (1000000 * (val - rint(val)));

				if (when.tv_usec > 1000000) {
					when.tv_sec  += 1;
					when.tv_usec -= 1000000;
				}
			}
			else
				when.tv_sec += atoi(evtime);
		}
		else {
			char	 *format = "%y%m%d%H%M%S";
			int	  len = strlen(evtime);
			struct tm tm;
			
			if ((len & 1) || (len > strlen(format)) || (len < 4))
				usage(progname);
			format += strlen(format) - len;

			gettimeofday(&when, NULL);
			localtime_r(&when.tv_sec, &tm);
			if (!strptime(evtime, format, &tm))
				usage(progname);

			when.tv_sec  = mktime(&tm);
			when.tv_usec = 0;
		}

		if (debug) {
			struct timeval now;
			
			gettimeofday(&now, NULL);
			
		}
		
		if (event_schedule(handle, notification, &when) == 0) {
			fatal("could not send test event notification");
		}
286
287
288
289
290
291
	}

	event_notification_free(handle, notification);

	/* Unregister with the event system: */
	if (event_unregister(handle) == 0) {
292
		fatal("could not unregister with event system");
293
294
295
296
	}
	
	return 0;
}