xref: /illumos-gate/usr/src/cmd/busstat/busstat.c (revision e75b2cb0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright (c) 2018, Joyent, Inc.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <time.h>
35 #include <signal.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/modctl.h>
40 #include <sys/systeminfo.h>
41 #include <limits.h>
42 #include <signal.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <stropts.h>
46 #include <locale.h>
47 #include <libintl.h>
48 #include <libgen.h>
49 #include <nl_types.h>
50 #include <kstat.h>
51 #include <ctype.h>
52 #include <signal.h>
53 #include <errno.h>
54 #include <time.h>
55 
56 #include "busstat.h"
57 
58 
59 /* Global defines */
60 static int		delta = TRUE;
61 static int		banner = TRUE;
62 static int		max_pic_num = 1;
63 static int		initial_read = TRUE;
64 static char		*pgmname;
65 static kstat_ctl_t	*kc;			/* libkstat cookie */
66 static dev_node_t	*dev_list_head	= NULL;
67 static dev_node_t	*dev_list_tail	= NULL;
68 
69 /*
70  * Global flags.
71  */
72 static char	curr_dev_name[KSTAT_STRLEN];
73 static int	curr_inst_num;
74 
75 static void print_evt(void);
76 static void print_dev(int, char *);
77 static void parse_cmd(int);
78 static void parse_dev_inst(char *);
79 static void parse_pic_evt(char *);
80 static void add_dev_node(char *, int);
81 static void add_all_dev_node(char *);
82 static void add_evt_node(dev_node_t *);
83 static void modify_evt_node(dev_node_t *, char *);
84 static void prune_evt_nodes(dev_node_t *);
85 static void setup_evts(void);
86 static void set_evt(dev_node_t *);
87 static void read_evts(void);
88 static void read_r_evt_node(dev_node_t *, int, kstat_named_t *);
89 static void read_w_evt_node(dev_node_t *, int, kstat_named_t *);
90 static void check_dr_ops(void);
91 static void remove_dev_node(dev_node_t *);
92 static dev_node_t *find_dev_node(char *, int, int);
93 static kstat_t *find_pic_kstat(char *, int, char *);
94 static int64_t is_num(char *);
95 static void print_banner(void);
96 static void print_timestamp(void);
97 static void usage(void);
98 static void *safe_malloc(size_t);
99 static void set_timer(int);
100 static void handle_sig(int);
101 static int strisnum(const char *);
102 
103 int
104 main(int argc, char **argv)
105 {
106 	int		c, i;
107 	int		interval = 1;	/* Interval between displays */
108 	int		count = 0;	/* Number of times to sample */
109 	int		write_evts = FALSE;
110 	int		pos = 0;
111 
112 #if !defined(TEXT_DOMAIN)
113 #define	TEXT_DOMAIN	"SYS_TEST"
114 #endif
115 
116 	/* For I18N */
117 	(void) setlocale(LC_ALL, "");
118 	(void) textdomain(TEXT_DOMAIN);
119 
120 	pgmname = basename(argv[0]);
121 
122 	if ((kc = kstat_open()) == NULL) {
123 		(void) fprintf(stderr, gettext("%s: could not "
124 			"open /dev/kstat\n"), pgmname);
125 		exit(1);
126 	}
127 
128 	while ((c = getopt(argc, argv, "e:w:r:ahln")) != EOF) {
129 		switch (c) {
130 		case 'a':
131 			delta = FALSE;
132 			break;
133 		case 'e':
134 			(void) print_evt();
135 			break;
136 		case 'h':
137 			usage();
138 			break;
139 		case 'l':
140 			(void) print_dev(argc, argv[argc-1]);
141 			break;
142 		case 'n':
143 			banner = FALSE;
144 			break;
145 		case 'r':
146 			(void) parse_cmd(READ_EVT);
147 			break;
148 		case 'w':
149 			(void) parse_cmd(WRITE_EVT);
150 			write_evts = TRUE;
151 			break;
152 		default:
153 			(void) fprintf(stderr, gettext("%s: invalid "
154 				"option\n"), pgmname);
155 			usage();
156 			break;
157 		}
158 	}
159 
160 	if ((argc == 1) || (dev_list_head == NULL))
161 		usage();
162 
163 	/*
164 	 * validate remaining operands are numeric.
165 	 */
166 	pos = optind;
167 	while (pos < argc) {
168 		if (strisnum(argv[pos]) == 0) {
169 			(void) fprintf(stderr,
170 				gettext("%s: syntax error\n"),
171 				pgmname);
172 			usage();
173 		}
174 		pos++;
175 	}
176 
177 	if (optind < argc) {
178 		if ((interval = atoi(argv[optind])) == 0) {
179 			(void) fprintf(stderr, gettext("%s: invalid "
180 				"interval value\n"), pgmname);
181 			exit(1);
182 		}
183 
184 		optind++;
185 		if (optind < argc)
186 			if ((count = atoi(argv[optind])) <= 0) {
187 				(void) fprintf(stderr, gettext("%s: "
188 					"invalid iteration value.\n"),
189 					    pgmname);
190 				exit(1);
191 			}
192 	}
193 
194 	set_timer(interval);
195 
196 	/*
197 	 * Set events for the first time.
198 	 */
199 	if (write_evts == TRUE)
200 		setup_evts();
201 
202 
203 	if (count > 0) {
204 		for (i = 0; i < count; i++) {
205 			if (banner)
206 				print_banner();
207 
208 			check_dr_ops();
209 			read_evts();
210 			(void) fflush(stdout);
211 			(void) pause();
212 		}
213 	} else {
214 		for (;;) {
215 			if (banner)
216 				print_banner();
217 
218 			check_dr_ops();
219 			read_evts();
220 			(void) fflush(stdout);
221 			(void) pause();
222 		}
223 	}
224 
225 	read_evts();
226 	return (0);
227 }
228 
229 
230 /*
231  * Display all the events that can be set on a device.
232  */
233 void
234 print_evt()
235 {
236 	kstat_t		*cnt_ksp;
237 	kstat_t		*pic_ksp;
238 	kstat_named_t	*cnt_data;
239 	kstat_named_t	*pic_data;
240 	char		*device = NULL;
241 	char		*value;
242 	int		inst_num = -1;
243 	int		i = 0;
244 	int		j;
245 
246 	value = optarg;
247 
248 	/*
249 	 * Search through the value string for a numeric char which will
250 	 * be the device instance number, if the user specified one. If
251 	 * the user did not specify an instance then the return value from
252 	 * strscpn will be equal to the string length. In this case we
253 	 * use a default value of -1 for the kstat_lookup which causes
254 	 * the device number to be ignored during the search.
255 	 */
256 	if (((i = strcspn(value, "0123456789")) > 0) && (i != strlen(value))) {
257 
258 		device = safe_malloc(sizeof (char) * i+1);
259 		device[i] = '\0';
260 		(void) strncpy(device, value, i);
261 
262 		value = value + i;
263 		inst_num = atoi(value);
264 	}
265 
266 	/*
267 	 * No instance specified.
268 	 */
269 	if (device == NULL)
270 		device = value;
271 
272 	/*
273 	 * Get the "counters" kstat, so that we can get
274 	 * the names of the "picN" kstats, which hold the
275 	 * event names.
276 	 */
277 	if ((cnt_ksp = kstat_lookup(kc, device, inst_num, "counters"))
278 								== NULL) {
279 		(void) fprintf(stderr, gettext("%s: invalid device "
280 			"name or instance (%s)\n"), pgmname, device);
281 		exit(1);
282 	}
283 
284 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
285 		(void) fprintf(stderr, gettext("%s: could not read "
286 			"kstat.\n"), pgmname);
287 		exit(1);
288 	}
289 
290 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
291 
292 	/*
293 	 * Start at 1 as the first entry in the "counters"
294 	 * kstat is the pcr value/name. We are looking for the
295 	 * name of the "picN" kstats. For each one found store
296 	 * a pointer to it in pic_data[].
297 	 */
298 	if (cnt_ksp->ks_ndata <= 1) {
299 		(void) fprintf(stderr, gettext("%s: invalid kstat "
300 			"structure.\n"), pgmname);
301 		exit(1);
302 	}
303 
304 	for (i = 1; i < cnt_ksp->ks_ndata; i++) {
305 		if ((pic_ksp = find_pic_kstat(device, inst_num,
306 			cnt_data[i].name)) == NULL) {
307 
308 			(void) fprintf(stderr, gettext("%s: could not read "
309 				"pic kstat data structure for %s\n"),
310 				    pgmname, cnt_ksp->ks_module);
311 
312 			exit(1);
313 		}
314 
315 		if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
316 			(void) fprintf(stderr, gettext("%s: could not read "
317 				"pic kstat.\n"), pgmname);
318 
319 			exit(1);
320 		}
321 
322 		pic_data = (kstat_named_t *)pic_ksp->ks_data;
323 
324 		(void) printf(gettext("pic%-8d\n"), i-1);
325 
326 		for (j = 0; j < pic_ksp->ks_ndata-1; j++) {
327 			(void) printf("%-30s\n", pic_data[j].name);
328 		}
329 
330 		(void) printf("\n");
331 	}
332 
333 	exit(0);
334 }
335 
336 
337 /*
338  * Display the names and instances of the devices on the system
339  * which can support performance monitoring.
340  */
341 void
342 print_dev(int argc, char *str)
343 {
344 	kstat_t	*ksp;
345 	static int first_time = 1;
346 
347 	if ((argc > 2) || (strcmp(str, "-l") != 0)) {
348 		(void) fprintf(stderr, gettext("%s: no arguments "
349 			"permitted with -l option.\n"),
350 			    pgmname);
351 		usage();
352 		exit(1);
353 	}
354 
355 	/*
356 	 * For each device node, print the node name (device
357 	 * name) and the instance numbers.
358 	 */
359 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
360 		if ((strcmp(ksp->ks_class, "bus") == 0) &&
361 			(strcmp(ksp->ks_name, "counters") == 0)) {
362 					if (first_time) {
363 						(void) printf(gettext("Busstat "
364 							"Device(s):\n"));
365 						first_time = 0;
366 					}
367 					(void) printf("%s%d ", ksp->ks_module,
368 						ksp->ks_instance);
369 		}
370 	}
371 
372 	if (first_time)
373 		(void) fprintf(stderr, gettext("%s: No devices available "
374 			"in system."), pgmname);
375 
376 	(void) printf("\n");
377 
378 	exit(0);
379 }
380 
381 /*
382  * Parses the cmd line, checks all the values and
383  * creates the appropiate data structures.
384  */
385 void
386 parse_cmd(int mode)
387 {
388 	char		*options = optarg, *value;
389 	int		arg_num	= 0;
390 
391 	while ((value = (char *)strtok(options, ",=")) != NULL) {
392 		/*
393 		 * First arg must be device name.
394 		 */
395 		if (!arg_num) {
396 			parse_dev_inst(value);
397 		} else {
398 			if (mode == READ_EVT) {
399 				(void) fprintf(stderr, gettext("%s: "
400 					"event names or pic values not "
401 					"permitted with -r option.\n"),
402 					    pgmname);
403 				usage();
404 				exit(1);
405 			}
406 			/*
407 			 * Now dealing with pic values.
408 			 */
409 			parse_pic_evt(value);
410 		}
411 		/*
412 		 * After first strtok call, must set first arg
413 		 * to null if wish to parse rest of string.
414 		 * See strtok man page.
415 		 */
416 		if (options != NULL)
417 			options = NULL;
418 		arg_num++;
419 	}
420 }
421 
422 
423 /*
424  * Parse the device name/instance section of the
425  * command line.
426  */
427 void
428 parse_dev_inst(char *value)
429 {
430 	int		i;
431 	char		*device	= NULL;
432 	int		malloc_flag = FALSE;
433 
434 	if (strlen(value) == 0) {
435 		(void) fprintf(stderr, gettext("%s: No device name given.\n"),
436 			pgmname);
437 		exit(1);
438 	}
439 
440 	/*
441 	 * Break string into device name and
442 	 * instance number (if given).
443 	 */
444 	if ((i = strcspn(value, "0123456789")) > 0) {
445 		if (i != strlen(value)) {
446 			device = safe_malloc(sizeof (char) * i+1);
447 			device[i] = '\0';
448 
449 			(void) strncpy(device, value, i);
450 			malloc_flag = TRUE;
451 
452 			value = value + i;
453 		}
454 	}
455 
456 	/*
457 	 * No instance was specified so we assume
458 	 * the user wants to use ALL instances.
459 	 */
460 	if (device == NULL) {
461 		if ((device = value) == NULL) {
462 			(void) fprintf(stderr, gettext("%s: no device "
463 				"specified\n"), pgmname);
464 			exit(1);
465 		}
466 
467 		/*
468 		 * Set global flags.
469 		 */
470 		(void) strcpy(curr_dev_name, device);
471 		curr_inst_num = -1;
472 
473 		add_all_dev_node(device);
474 		goto clean_up;
475 	}
476 
477 	/*
478 	 * Set global flags.
479 	 */
480 	(void) strcpy(curr_dev_name, device);
481 	curr_inst_num = atoi(value);
482 
483 	add_dev_node(device, curr_inst_num);
484 
485 clean_up:
486 	if (malloc_flag) {
487 		free(device);
488 	}
489 }
490 
491 
492 /*
493  * Adds new event nodes to existing ones, modifies existing ones, or
494  * prunes existing ones.
495  *
496  * A specific instance call will overwrite an earlier all
497  * instances call, but *not* vice-versa.
498  *
499  * All the state transitions are given below.
500  *
501  *
502  *                       Call Type
503  * STATE |  Specific Instance          All Instances.
504  * ======================================================
505  * INIT  | Change state to       | Change state to ALL,
506  *       | INST, add events      | add events.
507  *       |                       |
508  * INST  | State unchanged,      | No change.
509  *       | Add events.           |
510  *       |                       |
511  * ALL   | Change state to       | State unchanged,
512  *       | INST, replace events. | add events.
513  */
514 void
515 parse_pic_evt(char *value)
516 {
517 	dev_node_t	*dev_node;
518 	char		*evt_name;
519 	int		pic_num;
520 
521 	if (strlen(value) <= PIC_STR_LEN) {
522 		(void) fprintf(stderr, gettext("%s: no pic number "
523 			"specified.\n"), pgmname);
524 		exit(1);
525 	}
526 
527 	if (strncmp(value, "pic", PIC_STR_LEN) != 0) {
528 		(void) fprintf(stderr, gettext("%s: missing pic "
529 			"specifier\n"), pgmname);
530 		usage();
531 	}
532 
533 	/*
534 	 * Step over the 'pic' part of the string to
535 	 * get the pic number.
536 	 */
537 	value = value + PIC_STR_LEN;
538 	pic_num = atoi(value);
539 
540 	if ((pic_num == -1) || (pic_num > max_pic_num -1)) {
541 		(void) fprintf(stderr, gettext("%s: invalid pic "
542 			"number.\n"), pgmname);
543 		exit(1);
544 	}
545 
546 	if ((evt_name = (char *)strtok(NULL, "=,")) == NULL) {
547 		(void) fprintf(stderr, gettext("%s: no event "
548 			"specified.\n"), pgmname);
549 		exit(1);
550 	}
551 
552 	/*
553 	 * Dealing with a specific instance.
554 	 */
555 	if (curr_inst_num >= 0) {
556 		if ((dev_node = find_dev_node(curr_dev_name,
557 			curr_inst_num, pic_num)) == NULL) {
558 			(void) fprintf(stderr, gettext("%s: could not find "
559 				"data structures for %s\n"),
560 				    pgmname, curr_dev_name);
561 			exit(1);
562 		}
563 
564 		if (dev_node->r_w == EVT_READ) {
565 			modify_evt_node(dev_node, evt_name);
566 			dev_node->r_w = EVT_WRITE;
567 			dev_node->state = STATE_INST;
568 
569 		} else if ((dev_node->r_w == EVT_WRITE) &&
570 			(dev_node->state == STATE_ALL)) {
571 
572 			prune_evt_nodes(dev_node);
573 			modify_evt_node(dev_node, evt_name);
574 			dev_node->state = STATE_INST;
575 
576 		} else if ((dev_node->r_w == EVT_WRITE) &&
577 			(dev_node->state == STATE_INST)) {
578 
579 			add_evt_node(dev_node);
580 			modify_evt_node(dev_node, evt_name);
581 		}
582 
583 		return;
584 	}
585 
586 	/*
587 	 * Dealing with all instances of a specific device.
588 	 */
589 	dev_node = dev_list_head;
590 	while (dev_node != NULL) {
591 		if ((strcmp(dev_node->name, curr_dev_name) == 0) &&
592 			(dev_node->pic_num == pic_num)) {
593 
594 			if (dev_node->r_w == EVT_READ) {
595 				modify_evt_node(dev_node,
596 					evt_name);
597 
598 				dev_node->r_w = EVT_WRITE;
599 				dev_node->state = STATE_ALL;
600 
601 			} else if ((dev_node->r_w == EVT_WRITE) &&
602 				(dev_node->state == STATE_ALL)) {
603 
604 				add_evt_node(dev_node);
605 				modify_evt_node(dev_node, evt_name);
606 
607 			}
608 		}
609 		dev_node = dev_node->next;
610 	}
611 }
612 
613 
614 /*
615  * Create a dev_node structure for this device if one does not
616  * already exist.
617  */
618 void
619 add_dev_node(char *dev_name, int inst_num)
620 {
621 	dev_node_t	*new_dev_node;
622 	kstat_named_t	*cnt_data;
623 	kstat_t		*cnt_ksp;
624 	kstat_t		*pic_ksp;
625 	int		pic_num;
626 
627 
628 	if ((cnt_ksp = kstat_lookup(kc, dev_name,
629 		inst_num, "counters")) == NULL) {
630 		(void) fprintf(stderr, gettext("%s: invalid device "
631 			"name or instance (%s%d)\n"), pgmname,
632 				dev_name, inst_num);
633 		exit(1);
634 	}
635 
636 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
637 		(void) fprintf(stderr, gettext("%s : could not read counters "
638 			"kstat for device %s.\n"), pgmname, dev_name);
639 		exit(1);
640 	}
641 
642 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
643 
644 	if (cnt_ksp->ks_ndata <= 1) {
645 		(void) fprintf(stderr, gettext("%s : invalid "
646 			"kstat structure.\n"), pgmname);
647 		exit(1);
648 	}
649 
650 	/*
651 	 * max_pic_num used to format headers correctly
652 	 * for printing.
653 	 */
654 	if (cnt_ksp->ks_ndata-1 > max_pic_num)
655 		max_pic_num = cnt_ksp->ks_ndata-1;
656 
657 	/* for each pic... */
658 	for (pic_num = 0; pic_num < cnt_ksp->ks_ndata-1; pic_num++) {
659 		if (find_dev_node(dev_name, inst_num, pic_num) != NULL) {
660 			/* Node already exists */
661 			continue;
662 		}
663 
664 		new_dev_node = safe_malloc(sizeof (dev_node_t));
665 		bzero(new_dev_node, sizeof (dev_node_t));
666 
667 		(void) strcpy(new_dev_node->name, dev_name);
668 		new_dev_node->dev_inst = inst_num;
669 		new_dev_node->pic_num = pic_num;
670 
671 		new_dev_node->cnt_ksp = cnt_ksp;
672 
673 		if ((pic_ksp = find_pic_kstat(dev_name, inst_num,
674 			cnt_data[pic_num+1].name)) == NULL) {
675 
676 			(void) fprintf(stderr, gettext("%s: could not find "
677 				"pic kstat structure for %s.\n"),
678 				    pgmname, cnt_ksp->ks_module);
679 			exit(1);
680 		}
681 
682 		new_dev_node->pic_ksp = pic_ksp;
683 
684 		add_evt_node(new_dev_node);
685 
686 		new_dev_node->state = STATE_INIT;
687 		new_dev_node->r_w = EVT_READ;
688 
689 		if (dev_list_head == NULL) {
690 			dev_list_head = new_dev_node;
691 			dev_list_tail = new_dev_node;
692 
693 		} else if (find_dev_node(dev_name, inst_num, pic_num) == NULL) {
694 			dev_list_tail->next = new_dev_node;
695 			dev_list_tail = new_dev_node;
696 		}
697 	}
698 }
699 
700 
701 /*
702  * Add all possible instances of a device.
703  */
704 void
705 add_all_dev_node(char *dev_name)
706 {
707 	kstat_t	*ksp;
708 	int	match = 0;
709 
710 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
711 		if ((strcmp(ksp->ks_class, "bus") == 0) &&
712 			(strcmp(ksp->ks_name, "counters") == 0) &&
713 			(strcmp(ksp->ks_module, dev_name) == 0)) {
714 				match = 1;
715 				add_dev_node(dev_name, ksp->ks_instance);
716 		}
717 	}
718 
719 	if (match == 0) {
720 		(void) fprintf(stderr,
721 			gettext("%s: invalid device name (%s)\n"),
722 			pgmname, dev_name);
723 		exit(1);
724 	}
725 }
726 
727 
728 /*
729  * Add an event node to a specified device node.
730  */
731 void
732 add_evt_node(dev_node_t *dev_node)
733 {
734 	evt_node_t	*new_evt_node;
735 	evt_node_t	*curr_evt_node;
736 
737 	new_evt_node = safe_malloc(sizeof (evt_node_t));
738 	bzero(new_evt_node, sizeof (evt_node_t));
739 
740 	(void) strcpy(new_evt_node->evt_name, "");
741 
742 	if (dev_node->evt_node == NULL) {
743 		dev_node->evt_node = new_evt_node;
744 		new_evt_node->next = new_evt_node;
745 		return;
746 	} else {
747 		curr_evt_node = dev_node->evt_node;
748 		while (curr_evt_node->next != dev_node->evt_node)
749 			curr_evt_node = curr_evt_node->next;
750 
751 		curr_evt_node->next = new_evt_node;
752 		new_evt_node->next = dev_node->evt_node;
753 	}
754 }
755 
756 
757 /*
758  * Fill in or change the fields of an evt node.
759  */
760 void
761 modify_evt_node(dev_node_t *dev_node, char *evt_name)
762 {
763 	evt_node_t	*evt_node;
764 	kstat_t		*pic_ksp;
765 	kstat_named_t	*pic_data;
766 	int64_t		evt_num = 0;
767 	int		evt_match = 0;
768 	int		i;
769 
770 	evt_node = dev_node->evt_node;
771 
772 	/*
773 	 * Find the last event node.
774 	 */
775 	if (evt_node->next != evt_node) {
776 		while (evt_node->next != dev_node->evt_node) {
777 			evt_node = evt_node->next;
778 		}
779 	}
780 
781 	evt_node->prev_count = 0;
782 	evt_node->total = 0;
783 
784 	pic_ksp = dev_node->pic_ksp;
785 
786 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
787 		(void) fprintf(stderr, gettext("%s: could not read "
788 			"pic kstat.\n"), pgmname);
789 		exit(1);
790 	}
791 
792 	pic_data = (kstat_named_t *)dev_node->pic_ksp->ks_data;
793 
794 	/*
795 	 * The event can either be given as a event name (string) or
796 	 * as a pcr mask. If given as pcr mask, we try to match it
797 	 * to an event name, and use that name. Otherwise we just use
798 	 * the pcr mask value.
799 	 */
800 	if ((evt_num = is_num(evt_name)) == EVT_STR) {
801 		(void) strcpy(evt_node->evt_name, evt_name);
802 
803 		for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
804 			if (strcmp(evt_name, pic_data[i].name) == 0) {
805 				evt_node->evt_pcr_mask = pic_data[i].value.ui64;
806 				return;
807 			}
808 		}
809 
810 		(void) fprintf(stderr,
811 			gettext("%s: %s is not a valid event name.\n"),
812 			pgmname, evt_name);
813 		exit(1);
814 
815 	} else {
816 		/*
817 		 * See if the pcr mask given by the user matches that for any
818 		 * existing event.
819 		 */
820 		for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
821 			if (evt_num == pic_data[i].value.ui64) {
822 				(void) strcpy(evt_node->evt_name,
823 					pic_data[i].name);
824 				evt_match = 1;
825 				break;
826 			}
827 		}
828 
829 		if (evt_match == 0)
830 			(void) sprintf(evt_node->evt_name, "%llx", evt_num);
831 
832 		evt_node->evt_pcr_mask = evt_num;
833 	}
834 }
835 
836 
837 /*
838  * Removes all bar one of the evt_nodes that are hanging off the
839  * specified dev_node.
840  */
841 void
842 prune_evt_nodes(dev_node_t *dev_node)
843 {
844 	evt_node_t	*next_evt_node;
845 	evt_node_t	*curr_evt_node;
846 
847 	/*
848 	 * Only one evt node, nothing for us to do.
849 	 */
850 	if (dev_node->evt_node->next == dev_node->evt_node) {
851 		return;
852 	}
853 
854 	curr_evt_node = dev_node->evt_node->next;
855 	dev_node->evt_node->next = dev_node->evt_node;
856 
857 	while (curr_evt_node != dev_node->evt_node) {
858 		next_evt_node = curr_evt_node->next;
859 		free(curr_evt_node);
860 		curr_evt_node = next_evt_node;
861 	}
862 }
863 
864 
865 /*
866  * Set the events for each pic on each device instance.
867  */
868 void
869 setup_evts()
870 {
871 	dev_node_t	*dev_node;
872 
873 	dev_node = dev_list_head;
874 
875 	while (dev_node != NULL) {
876 		if (dev_node->r_w == EVT_WRITE)
877 			set_evt(dev_node);
878 
879 		dev_node = dev_node->next;
880 	}
881 }
882 
883 
884 /*
885  * Set the appropiate events. Only called for event nodes
886  * that are marked EVT_WRITE.
887  */
888 void
889 set_evt(dev_node_t *dev_node)
890 {
891 	kstat_named_t	*cnt_data;
892 	kstat_named_t	*pic_data;
893 	kstat_t		*cnt_ksp;
894 	kstat_t		*pic_ksp;
895 	evt_node_t	*evt_node;
896 	uint64_t	clear_pcr_mask;
897 	uint64_t	pcr;
898 	int		pic_num;
899 
900 	cnt_ksp = dev_node->cnt_ksp;
901 	pic_ksp = dev_node->pic_ksp;
902 	pic_num = dev_node->pic_num;
903 	evt_node = dev_node->evt_node;
904 
905 	/* Read the "counters" kstat */
906 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
907 		(void) fprintf(stderr, gettext("%s: could "
908 			"not set event's.\n"), pgmname);
909 		exit(1);
910 	}
911 
912 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
913 
914 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
915 		(void) fprintf(stderr, gettext("%s: could "
916 			"not set event's.\n"), pgmname);
917 		exit(1);
918 	}
919 
920 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
921 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
922 
923 	if ((pic_num < 0) || (pic_num > cnt_ksp->ks_ndata-1)) {
924 		(void) fprintf(stderr,
925 			gettext("%s: invalid pic #%d.\n"),
926 			pgmname, pic_num);
927 		exit(1);
928 	}
929 
930 	/*
931 	 * Store the previous value that is on the pic
932 	 * so that we can calculate the delta value
933 	 * later.
934 	 */
935 	evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
936 
937 
938 	/*
939 	 * Read the current pcr value from device.
940 	 */
941 	pcr = cnt_data[0].value.ui64;
942 
943 	/*
944 	 * Clear the section of the pcr which corresponds to the
945 	 * pic we are setting events on. Also clear the pcr value
946 	 * which is stored in the instance node.
947 	 *
948 	 */
949 	pcr = pcr & clear_pcr_mask;
950 
951 	/*
952 	 * Set the event.
953 	 */
954 	pcr = pcr | evt_node->evt_pcr_mask;
955 	cnt_data[0].value.ui64 = pcr;
956 
957 	/*
958 	 * Write the value back to the kstat, to make it
959 	 * visible to the underlying driver.
960 	 */
961 	if (kstat_write(kc, cnt_ksp, NULL) == FAIL) {
962 		(void) fprintf(stderr, gettext("%s: could not set events "
963 					"(setting events requires root "
964 					    "permission).\n"), pgmname);
965 		exit(1);
966 	}
967 }
968 
969 
970 /*
971  * Works through the list of device nodes, reading events
972  * and where appropiate setting new events (multiplexing).
973  */
974 void
975 read_evts()
976 {
977 	dev_node_t	*dev_node;
978 	kstat_t		*cnt_ksp;
979 	kstat_named_t	*cnt_data;
980 	char		tmp_str[30];
981 	int		iter = 0;
982 
983 	dev_node = dev_list_head;
984 
985 	while (dev_node != NULL) {
986 		if (iter == 0)
987 			print_timestamp();
988 		/*
989 		 * First read of all the counters is done
990 		 * to establish a baseline for the counts.
991 		 * This data is not printed.
992 		 */
993 		if ((!initial_read) && (iter == 0)) {
994 			(void) snprintf(tmp_str, sizeof (tmp_str), "%s%d",
995 				dev_node->name, dev_node->dev_inst);
996 			(void) printf("%-7s", tmp_str);
997 		}
998 
999 		cnt_ksp = (kstat_t *)dev_node->cnt_ksp;
1000 
1001 		if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
1002 			(void) fprintf(stderr, gettext("%s: device %s%d "
1003 				"(pic %d) no longer valid.\n"),
1004 				    pgmname, dev_node->name,
1005 				    dev_node->dev_inst,
1006 				    dev_node->pic_num);
1007 			remove_dev_node(dev_node);
1008 			dev_node = dev_list_head;
1009 			continue;
1010 		}
1011 
1012 		cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
1013 
1014 		if (dev_node->r_w == EVT_READ) {
1015 			read_r_evt_node(dev_node, dev_node->pic_num, cnt_data);
1016 			iter++;
1017 		} else {
1018 			read_w_evt_node(dev_node, dev_node->pic_num, cnt_data);
1019 			iter++;
1020 		}
1021 
1022 		if ((!initial_read) && (iter == max_pic_num)) {
1023 			iter = 0;
1024 			(void) printf("\n");
1025 		}
1026 
1027 		/*
1028 		 * If there is more than one event node
1029 		 * per-pic then we are multiplexing.
1030 		 */
1031 		if ((dev_node->evt_node->next != dev_node->evt_node) &&
1032 			(!initial_read)) {
1033 				dev_node->evt_node = dev_node->evt_node->next;
1034 				set_evt(dev_node);
1035 		}
1036 		dev_node = dev_node->next;
1037 	}
1038 	initial_read = FALSE;
1039 }
1040 
1041 
1042 /*
1043  * Read a node that is marked as EVT_READ
1044  */
1045 void
1046 read_r_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
1047 {
1048 	evt_node_t	*evt_node;
1049 	kstat_t		*pic_ksp;
1050 	kstat_named_t	*pic_data;
1051 	uint64_t	pcr_read;
1052 	uint64_t	clear_pcr_mask;
1053 	uint64_t	delta_count;
1054 	int		i;
1055 	int		match = 0;
1056 	int		evt_blank = 1;
1057 
1058 	evt_node = dev_node->evt_node;
1059 
1060 	pic_ksp = (kstat_t *)dev_node->pic_ksp;
1061 
1062 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
1063 		(void) fprintf(stderr, gettext("%s: device %s%d "
1064 			"(pic %d) no longer valid.\n"), pgmname,
1065 			    dev_node->name, dev_node->dev_inst,
1066 			    dev_node->pic_num);
1067 		remove_dev_node(dev_node);
1068 		return;
1069 	}
1070 
1071 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
1072 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
1073 
1074 	/*
1075 	 * Get PCR value from device. We extract the portion
1076 	 * of the PCR relating to the pic we are interested by
1077 	 * AND'ing the inverse of the clear mask for this pic.
1078 	 *
1079 	 * The clear mask is usually used to clear the appropiate
1080 	 * section of the PCR before we write events into it. So
1081 	 * by using the inverse of the mask, we zero everything
1082 	 * *but* the section we are interested in.
1083 	 */
1084 	pcr_read = cnt_data[0].value.ui64;
1085 	pcr_read = pcr_read & ~(clear_pcr_mask);
1086 
1087 	/*
1088 	 * If the event name is blank this is the first time that
1089 	 * this node has been accessed, so we read the pcr and
1090 	 * from that we get the event name if it exists.
1091 	 *
1092 	 * If the pcr read from the device does not match that
1093 	 * stored in the node, then it means that the event has
1094 	 * changed from its previous value, so we need to re-read
1095 	 * all the values.
1096 	 */
1097 	if ((strcmp(evt_node->evt_name, "") == 0) ||
1098 		(pcr_read != evt_node->evt_pcr_mask)) {
1099 
1100 		for (i = 0; i < pic_ksp->ks_ndata-1; i++) {
1101 			if (pcr_read == pic_data[i].value.ui64) {
1102 				match = TRUE;
1103 				break;
1104 			}
1105 		}
1106 
1107 		/*
1108 		 * Able to resolve pcr value to a event name.
1109 		 */
1110 		if (match) {
1111 			(void) strcpy(evt_node->evt_name, pic_data[i].name);
1112 			evt_node->evt_pcr_mask = pcr_read;
1113 			evt_node->total = 0;
1114 			evt_node->prev_count =
1115 				cnt_data[pic_num+1].value.ui64;
1116 
1117 			if ((evt_blank) && (!initial_read)) {
1118 				(void) printf("%s\t%-8d\t",
1119 					evt_node->evt_name, 0);
1120 				evt_blank = 0;
1121 			}
1122 
1123 		} else {
1124 			(void) sprintf(evt_node->evt_name, "0x%llx", pcr_read);
1125 			evt_node->evt_pcr_mask = pcr_read;
1126 			evt_node->total = 0;
1127 			evt_node->prev_count =
1128 				cnt_data[pic_num+1].value.ui64;
1129 
1130 			if ((evt_blank) && (!initial_read)) {
1131 				(void) printf("%s\t%-8d\t",
1132 					evt_node->evt_name, 0);
1133 				evt_blank = 0;
1134 			}
1135 
1136 		}
1137 	} else {
1138 		/* Deal with wraparound of the counters */
1139 		if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
1140 
1141 			delta_count = (UINT32_MAX-evt_node->prev_count) +
1142 				cnt_data[pic_num+1].value.ui64;
1143 		} else {
1144 			/* Calcalate delta value */
1145 			delta_count = cnt_data[pic_num+1].value.ui64
1146 						- evt_node->prev_count;
1147 		}
1148 
1149 
1150 		/*
1151 		 * Store value so that we can calculate delta next
1152 		 * time through.
1153 		 */
1154 		evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
1155 
1156 		/* Update count total */
1157 		evt_node->total += delta_count;
1158 
1159 		if (delta) {
1160 			(void) printf("%-20s %-9lld   ",
1161 				evt_node->evt_name, delta_count);
1162 		} else {
1163 
1164 			(void) printf("%-20s %-9lld   ",
1165 				evt_node->evt_name, evt_node->total);
1166 		}
1167 	}
1168 }
1169 
1170 
1171 /*
1172  * Read event nodes marked as EVT_WRITE
1173  */
1174 void
1175 read_w_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
1176 {
1177 	kstat_t		*pic_ksp;
1178 	kstat_named_t	*pic_data;
1179 	evt_node_t	*evt_node;
1180 	uint64_t	delta_count;
1181 	uint64_t	pcr_read;
1182 	uint64_t	clear_pcr_mask;
1183 
1184 	evt_node = dev_node->evt_node;
1185 
1186 	pic_ksp = (kstat_t *)dev_node->pic_ksp;
1187 
1188 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
1189 		(void) fprintf(stderr, gettext("%s: could not read "
1190 			"%s%d\n"), pgmname, dev_node->name,
1191 			    dev_node->dev_inst);
1192 		remove_dev_node(dev_node);
1193 		return;
1194 	}
1195 
1196 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
1197 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
1198 
1199 	/*
1200 	 * Get PCR value from device. We extract the portion
1201 	 * of the PCR relating to the pic we are interested by
1202 	 * AND'ing the inverse of the clear mask for this pic.
1203 	 *
1204 	 * The clear mask is usually used to clear the appropiate
1205 	 * section of the PCR before we write events into it. So
1206 	 * by using the inverse of the mask, we zero everything
1207 	 * *but* the section we are interested in.
1208 	 */
1209 	pcr_read = cnt_data[0].value.ui64;
1210 	pcr_read = pcr_read & ~(clear_pcr_mask);
1211 
1212 	/*
1213 	 * If the pcr value from the device does not match the
1214 	 * stored value, then the events on at least one of the
1215 	 * pics must have been change by another busstat instance.
1216 	 *
1217 	 * Regard this as a fatal error.
1218 	 */
1219 	if (pcr_read != evt_node->evt_pcr_mask) {
1220 		(void) fprintf(stderr, gettext("%s: events changed (possibly "
1221 			"by another busstat).\n"), pgmname);
1222 		exit(2);
1223 	}
1224 
1225 	/*
1226 	 * Calculate delta, and then store value just read to allow us to
1227 	 * calculate delta next time around.
1228 	 */
1229 	/* Deal with wraparound of the counters */
1230 	if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
1231 
1232 		delta_count = (UINT32_MAX-evt_node->prev_count) +
1233 			cnt_data[pic_num+1].value.ui64;
1234 	} else {
1235 		/* Calcalate delta value */
1236 		delta_count = cnt_data[pic_num+1].value.ui64
1237 			- evt_node->prev_count;
1238 	}
1239 
1240 	evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
1241 
1242 	if (initial_read) {
1243 		evt_node->total = 0;
1244 
1245 	} else {
1246 		/* Update count total */
1247 		evt_node->total += delta_count;
1248 
1249 		if (delta) {
1250 			(void) printf("%-20s %-9lld   ",
1251 				evt_node->evt_name, delta_count);
1252 		} else {
1253 			(void) printf("%-20s %-9lld   ",
1254 				evt_node->evt_name, evt_node->total);
1255 		}
1256 	}
1257 }
1258 
1259 
1260 /*
1261  * Check to see if any DR operations have occured, and deal with the
1262  * consequences.
1263  *
1264  * Use the Kstat chain ID to check for DR operations. If the ID has
1265  * changed then some kstats on system have been modified, we check
1266  * all the data structures to see are they still valid. If they are
1267  * not we remove them.
1268  */
1269 void
1270 check_dr_ops()
1271 {
1272 	dev_node_t	*dev_node;
1273 	kid_t		new_id;
1274 	kstat_t		*ksp;
1275 	int		match = 0;
1276 
1277 	if ((new_id = kstat_chain_update(kc)) < 0) {
1278 		(void) fprintf(stderr, gettext("%s: could not get "
1279 			"kstat chain id\n"), pgmname);
1280 		exit(1);
1281 	}
1282 
1283 	if (new_id == 0) {
1284 		/* Kstat chain has not changed. */
1285 		return;
1286 	}
1287 
1288 	/*
1289 	 * Scan the chain of device nodes, making sure that their associated
1290 	 * kstats are still present. If not we remove the appropiate node.
1291 	 */
1292 	dev_node = dev_list_head;
1293 
1294 	while (dev_node != NULL) {
1295 		for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1296 			if ((strcmp("bus", ksp->ks_class) == 0) &&
1297 				(strcmp("counters", ksp->ks_name) == 0) &&
1298 				(strcmp(dev_node->name, ksp->ks_module) == 0) &&
1299 				(ksp->ks_instance == dev_node->dev_inst)) {
1300 					match = 1;
1301 					break;
1302 			}
1303 		}
1304 		if (match == 0) {
1305 			(void) fprintf(stderr, gettext("%s: device %s%d"
1306 				" (pic %d) no longer valid.\n"), pgmname,
1307 				    dev_node->name, dev_node->dev_inst,
1308 				    dev_node->pic_num);
1309 
1310 			remove_dev_node(dev_node);
1311 		}
1312 		dev_node = dev_node->next;
1313 	}
1314 }
1315 
1316 
1317 
1318 /*
1319  * Remove a device node and its associated event nodes.
1320  */
1321 void
1322 remove_dev_node(dev_node_t *dev_node)
1323 {
1324 	dev_node_t	*curr_node;
1325 	dev_node_t	*prev_node;
1326 	evt_node_t	*curr_evt_node;
1327 	evt_node_t	*next_evt_node;
1328 	evt_node_t	*start_pos;
1329 
1330 	curr_node = dev_list_head;
1331 
1332 	if (curr_node == dev_node) {
1333 		dev_list_head = dev_node->next;
1334 
1335 		if (dev_list_head == NULL) {
1336 			(void) fprintf(stderr, gettext("%s: no "
1337 				"devices left to monitor.\n"),
1338 				    pgmname);
1339 			exit(1);
1340 		}
1341 
1342 		/* Remove each event node first */
1343 		start_pos = dev_node->evt_node;
1344 		curr_evt_node = start_pos->next;
1345 
1346 		while (curr_evt_node != start_pos) {
1347 			next_evt_node = curr_evt_node->next;
1348 
1349 			free(curr_evt_node);
1350 			curr_evt_node = next_evt_node;
1351 		}
1352 
1353 		free(start_pos);
1354 		free(dev_node);
1355 		return;
1356 	}
1357 
1358 	/* Find the device node */
1359 	prev_node = dev_list_head;
1360 	curr_node = prev_node->next;
1361 
1362 	while (curr_node != NULL) {
1363 		if (curr_node == dev_node) {
1364 			prev_node->next = curr_node->next;
1365 
1366 			/* Remove each event node first */
1367 			start_pos = dev_node->evt_node;
1368 			curr_evt_node = start_pos->next;
1369 
1370 			while (curr_evt_node != start_pos) {
1371 				next_evt_node = curr_evt_node->next;
1372 
1373 				free(curr_evt_node);
1374 				curr_evt_node = next_evt_node;
1375 			}
1376 			free(start_pos);
1377 
1378 			free(dev_node);
1379 			return;
1380 		}
1381 		prev_node = curr_node;
1382 		curr_node = curr_node->next;
1383 	}
1384 }
1385 
1386 
1387 /*
1388  * Find a device node in the linked list of dev_nodes. Match
1389  * is done on device name, and instance number.
1390  */
1391 dev_node_t *
1392 find_dev_node(char *name, int inst_num, int pic_num)
1393 {
1394 	dev_node_t	*curr_node;
1395 
1396 	curr_node = dev_list_head;
1397 
1398 	while (curr_node != NULL) {
1399 		if ((strcmp(curr_node->name, name) == 0) &&
1400 			(curr_node->dev_inst == inst_num) &&
1401 			(curr_node->pic_num == pic_num)) {
1402 				return (curr_node);
1403 		}
1404 
1405 		curr_node = curr_node->next;
1406 	}
1407 
1408 	return (NULL);
1409 }
1410 
1411 
1412 /*
1413  * Determines whether the string represents a event name
1414  * or a numeric value. Numeric value can be dec, hex
1415  * or octal. All are converted to long int.
1416  */
1417 int64_t
1418 is_num(char *name)
1419 {
1420 	char	*remainder = NULL;
1421 	int64_t	num;
1422 
1423 	num = (int64_t)strtol(name, &remainder, 0);
1424 
1425 	if (name == remainder) {
1426 		return (EVT_STR);
1427 	} else {
1428 		return (num);
1429 	}
1430 }
1431 
1432 
1433 /*
1434  * Find a pointer to the specified picN kstat. First
1435  * search for the specific kstat, and if that can't
1436  * be found search for any picN kstat belonging to this device.
1437  */
1438 kstat_t *
1439 find_pic_kstat(char *dev_name, int inst_num, char *pic)
1440 {
1441 	kstat_t	*ksp;
1442 	kstat_t	*p_ksp;
1443 
1444 	/* Look for specific picN kstat */
1445 	if ((p_ksp = kstat_lookup(kc, dev_name, inst_num, pic)) == NULL) {
1446 
1447 		for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1448 			if ((strcmp(ksp->ks_class, "bus") == 0) &&
1449 				(strcmp(ksp->ks_name, pic) == 0) &&
1450 				(strcmp(ksp->ks_module, dev_name) == 0)) {
1451 
1452 						return (ksp);
1453 			}
1454 		}
1455 	}
1456 	return (p_ksp);
1457 }
1458 
1459 
1460 /*
1461  * Print column titles.
1462  * Can be turned off by -n option.
1463  */
1464 void
1465 print_banner()
1466 {
1467 	int		i;
1468 
1469 	(void) printf("time dev    ");
1470 
1471 	for (i = 0; i < max_pic_num; i++)
1472 		(void) printf("event%d               "
1473 			"pic%d        ", i, i);
1474 
1475 	(void) printf("\n");
1476 
1477 	banner = FALSE;
1478 }
1479 
1480 
1481 /*
1482  * Print the elapsed time in seconds, since the last call.
1483  */
1484 void
1485 print_timestamp()
1486 {
1487 	static hrtime_t	curr_time = 0;
1488 	static hrtime_t total_elapsed = 0;
1489 	hrtime_t	new_time = 0;
1490 	hrtime_t	elapsed = 0;
1491 	hrtime_t	rem = 0;
1492 
1493 	if (initial_read)	{
1494 		curr_time = (uint64_t)gethrtime();
1495 		return;
1496 	}
1497 
1498 	new_time = gethrtime();
1499 
1500 	elapsed = (new_time - curr_time)/NANO;
1501 
1502 	/* Round up time value if necessary */
1503 	rem = (new_time - curr_time)%NANO;
1504 	if (rem >= NANO/2)
1505 		elapsed += 1;
1506 
1507 	total_elapsed += elapsed;
1508 
1509 	(void) printf("%-4llu ", total_elapsed);
1510 
1511 	curr_time = new_time;
1512 }
1513 
1514 
1515 void
1516 usage()
1517 {
1518 	(void) printf(gettext("Usage : busstat [-a] [-h] [-l] [-n]\n"
1519 		"                [-e device-inst]\n"
1520 		"                [-w device-inst "
1521 					"[,pic0=<event>] [,picN=<event>] ]\n"
1522 		"                [-r device-inst]\n"
1523 		"                [ interval [count] ]\n"));
1524 
1525 	exit(2);
1526 }
1527 
1528 
1529 void *
1530 safe_malloc(size_t size)
1531 {
1532 	void *a;
1533 
1534 	if ((a = malloc(size)) == NULL) {
1535 		(void) fprintf(stderr,
1536 			gettext("%s: out of memory.\n"), pgmname);
1537 		exit(1);
1538 	}
1539 
1540 	return (a);
1541 }
1542 
1543 /*
1544  * Create and arm the timer.
1545  */
1546 void
1547 set_timer(int interval)
1548 {
1549 	timer_t		t_id;		/* Timer id */
1550 	itimerspec_t	time_struct;
1551 	struct sigevent	sig_struct;
1552 	struct sigaction act;
1553 
1554 	bzero(&sig_struct, sizeof (struct sigevent));
1555 	bzero(&act, sizeof (struct sigaction));
1556 
1557 	/* Create timer */
1558 	sig_struct.sigev_notify = SIGEV_SIGNAL;
1559 	sig_struct.sigev_signo = SIGUSR1;
1560 	sig_struct.sigev_value.sival_int = 0;
1561 
1562 	if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) {
1563 		(void) fprintf(stderr, gettext("%s: Timer creation failed.\n"),
1564 			pgmname);
1565 		exit(1);
1566 	}
1567 
1568 	act.sa_handler = handle_sig;
1569 
1570 	if (sigaction(SIGUSR1, &act, NULL) != 0) {
1571 		(void) fprintf(stderr, gettext("%s: could not setup signal "
1572 			"handler"), pgmname);
1573 		exit(1);
1574 	}
1575 
1576 	time_struct.it_value.tv_sec = interval;
1577 	time_struct.it_value.tv_nsec = 0;
1578 	time_struct.it_interval.tv_sec = interval;
1579 	time_struct.it_interval.tv_nsec = 0;
1580 
1581 	/* Arm timer */
1582 	if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) {
1583 		(void) fprintf(stderr, gettext("%s: Setting timer failed.\n"),
1584 			pgmname);
1585 		exit(1);
1586 	}
1587 }
1588 
1589 
1590 /* ARGSUSED */
1591 void
1592 handle_sig(int x)
1593 {
1594 }
1595 
1596 /*
1597  * return a boolean value indicating whether or not
1598  * a string consists solely of characters which are
1599  * digits 0..9
1600  */
1601 int
1602 strisnum(const char *s)
1603 {
1604 	for (; *s != '\0'; s++) {
1605 		if (*s < '0' || *s > '9')
1606 			return (0);
1607 	}
1608 	return (1);
1609 }
1610