xref: /titanic_51/usr/src/cmd/tnf/prex/main.c (revision 06e46062ef4f5f4b687cbafb4518fb123fe23920)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Includes
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <locale.h>
40 #include <libintl.h>
41 #include <fcntl.h>
42 #include <limits.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/procfs.h>
47 #include <libelf.h>
48 #include <gelf.h>
49 #include <sys/systeminfo.h>
50 
51 #include <tnf/tnfctl.h>
52 
53 #include "set.h"
54 #include "cmd.h"
55 #include "spec.h"
56 #include "expr.h"
57 #include "source.h"
58 #include "list.h"
59 #include "prbk.h"
60 
61 /*
62  * Defines - Project private interfaces
63  */
64 
65 #define	DEBUG_ENTRY		"tnf_probe_debug"
66 #ifdef TESTING
67 #define	EMPTY_ENTRY		"tnf_probe_empty"
68 #endif
69 
70 #define	USER_OUTSIZE		(4*1024*1024)
71 #define	KERNEL_OUTSIZE		(384*1024)
72 
73 #if defined(__sparc)
74 #define	PREX32DIR	"/sparcv7/"
75 #elif defined(__i386) || defined(__amd64)
76 #define	PREX32DIR	"/i86/"
77 #endif
78 #define	PREX32EXEC	"/usr/bin" PREX32DIR "prex"
79 
80 /*
81  * Globals
82  */
83 
84 char			**g_argv;	/* copy of argv pointer */
85 tnfctl_handle_t		*g_hndl;	/* handle on target or kernel */
86 
87 static int		g_verbose;	/* debugging to stderr */
88 static char		*g_cmdname;	/* target command name */
89 static char		**g_cmdargs;	/* target command args */
90 static pid_t		g_targetpid;	/* target process id */
91 static volatile boolean_t g_getcmds;	/* accept input flag */
92 static boolean_t	g_testflag;	/* asserted in test mode */
93 static char		*g_preload;	/* objects to preload */
94 static char		*g_outname;	/* tracefile name */
95 static char		*tracefile;	/* tracefile name used by list cmd */
96 int			g_outsize;	/* tracefile size */
97 boolean_t		g_kernelmode;	/* -k flag: kernel mode */
98 static int		prex_dmodel;	/* prex data model */
99 /*
100  * Local Declarations
101  */
102 
103 static void usage(char **argv, const char *msg);
104 static void scanargs(int argc, char **argv);
105 static int set_signal(void);
106 static int get_data_model(pid_t pid);
107 static int get_elf_class(char *filename);
108 static int get_executable(char *);
109 static void prex_isaexec(char **argv, char **envp);
110 static void check_pid_model(char **argv, char **envp);
111 static void check_exec_model(char **argv, char **envp);
112 
113 /* #### - FIXME - need to put this in a private header file */
114 extern void err_fatal(char *s, ...);
115 
116 extern int	  yyparse(void);
117 
118 static tnfctl_errcode_t check_trace_error(tnfctl_handle_t *hndl);
119 static void set_default_cmd(void);
120 static void get_commands(void);
121 static tnfctl_errcode_t set_tracefile(tnfctl_handle_t *hndl);
122 static tnfctl_errcode_t set_probe_discovery_callback(tnfctl_handle_t *hndl);
123 static void * perprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p);
124 static tnfctl_errcode_t perprobe2(tnfctl_handle_t *hndl,
125 	tnfctl_probe_t *probe_p, void *ignored);
126 static tnfctl_errcode_t percmd(expr_t *expr_p, cmd_kind_t kind, fcn_t *fcn_p,
127 	boolean_t isnew, void *calldata_p);
128 void quit(boolean_t killtarget, boolean_t runtarget);
129 void cmd_listtracefile();
130 
131 
132 /*
133  * usage() - gives a description of the arguments, and exits
134  */
135 
136 static void
137 usage(char *argv[], const char *msg)
138 {
139 	if (msg)
140 		(void) fprintf(stderr,
141 			gettext("%s: %s\n"), argv[0], msg);
142 
143 	(void) fprintf(stderr, gettext(
144 		"usage: %s [options] <cmd> [cmd-args...]\n"), argv[0]);
145 	(void) fprintf(stderr, gettext(
146 		"usage: %s [options] -p <pid>\n"), argv[0]);
147 	(void) fprintf(stderr, gettext(
148 		"usage: %s -s <kbytes-size> -k\n"), argv[0]);
149 	(void) fprintf(stderr, gettext(
150 		"options:\n"));
151 	(void) fprintf(stderr, gettext(
152 		"	-o <outfilename>   set trace output file name\n"));
153 	(void) fprintf(stderr, gettext(
154 		"	-s <kbytes-size>   set trace file size\n"));
155 	(void) fprintf(stderr, gettext(
156 		"	-l <sharedobjs>    shared objects to "
157 		"be preloaded (cmd only)\n"));
158 
159 	exit(1);
160 }
161 
162 
163 /*
164  * main() -
165  */
166 
167 int
168 main(int argc, char **argv, char **envp)
169 {
170 	tnfctl_errcode_t	err = TNFCTL_ERR_NONE;
171 	int			sys_err;
172 	tnfctl_trace_attrs_t	trace_attrs;
173 	tnfctl_event_t		event = TNFCTL_EVENT_EINTR;
174 	pid_t			prex_pid;
175 
176 	/* internationalization stuff */
177 	(void) setlocale(LC_ALL, "");
178 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
179 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
180 #endif
181 	(void) textdomain(TEXT_DOMAIN);
182 
183 	g_argv = argv;
184 
185 	prex_pid = getpid();
186 #if defined(DEBUG)
187 	fprintf(stderr, "### prex_pid = %d ###\n", prex_pid);
188 #endif
189 	prex_dmodel = get_data_model(prex_pid);
190 #if defined(DEBUG)
191 	fprintf(stderr, "### prex_dmodel = %d ###\n", prex_dmodel);
192 #endif
193 	scanargs(argc, argv);
194 
195 	if (g_kernelmode) {
196 		/* prexing the kernel */
197 		err = tnfctl_kernel_open(&g_hndl);
198 		if (err) {
199 			err_fatal(gettext(
200 				"%s: trouble attaching to the kernel: %s\n"),
201 				argv[0], tnfctl_strerror(err));
202 		}
203 	} else {
204 		/* prexing a user process */
205 		if (g_targetpid != 0) {
206 			/* check data model */
207 			check_pid_model(argv, envp);
208 			/* attach case */
209 			err = tnfctl_pid_open(g_targetpid, &g_hndl);
210 			if (err == TNFCTL_ERR_NOLIBTNFPROBE) {
211 				err_fatal(gettext(
212 					"%s: missing symbols, is "
213 					"libtnfprobe.so loaded in target?\n"),
214 					argv[0], tnfctl_strerror(err));
215 			} else if (err) {
216 				err_fatal(gettext(
217 					"%s: trouble attaching to target "
218 					"process: %s\n"),
219 					argv[0], tnfctl_strerror(err));
220 			}
221 		} else {
222 			/* check elf class model */
223 			check_exec_model(argv, envp);
224 			/* exec case */
225 			err = tnfctl_exec_open(g_cmdname, g_cmdargs, NULL,
226 					g_preload, NULL, &g_hndl);
227 			if (err == TNFCTL_ERR_NONE)
228 				err = tnfctl_trace_attrs_get(g_hndl,
229 						&trace_attrs);
230 			if (err) {
231 				err_fatal(gettext(
232 					"%s: trouble creating target process: "
233 					"%s\n"),
234 					argv[0], tnfctl_strerror(err));
235 			}
236 			g_targetpid = trace_attrs.targ_pid;
237 		}
238 
239 		sys_err = set_signal();
240 		if (sys_err)
241 			err_fatal(gettext(
242 				"%s: trouble setting up signal handler: %s\n"),
243 				argv[0], strerror(err));
244 	}
245 
246 	/* initialize the source stack for the parser */
247 	source_init();
248 
249 	if (!g_kernelmode) {
250 		/* set the tracefile name and size */
251 		err = set_tracefile(g_hndl);
252 		if (err) {
253 			(void) fprintf(stderr, gettext(
254 				"%s: trouble initializing tracefile: %s\n"),
255 				argv[0], tnfctl_strerror(err));
256 			goto Cleanup;
257 		}
258 		err = check_trace_error(g_hndl);
259 		if (err) {
260 			(void) fprintf(stderr, gettext(
261 				"%s: cannot read tracing status : %s\n"),
262 				argv[0], tnfctl_strerror(err));
263 			goto Cleanup;
264 		}
265 	}
266 
267 	/* accept commands from stdin the first time through */
268 	g_getcmds = B_TRUE;
269 
270 	/* set up default aliases */
271 	set_default_cmd();
272 
273 	/* set up creator/destructor function to call for new probes */
274 	err = set_probe_discovery_callback(g_hndl);
275 	if (err) {
276 		(void) fprintf(stderr, gettext(
277 			"%s: error in probe discovery : %s\n"),
278 			argv[0], tnfctl_strerror(err));
279 		goto Cleanup;
280 	}
281 
282 	if (g_kernelmode) {
283 		prbk_warn_pfilter_empty();
284 	}
285 
286 	while (err == TNFCTL_ERR_NONE) {
287 
288 		if (g_kernelmode || g_getcmds) {
289 			g_getcmds = B_FALSE;
290 			get_commands();
291 		}
292 
293 		if (!g_kernelmode && (g_getcmds == B_FALSE)) {
294 		    err = tnfctl_continue(g_hndl, &event, NULL);
295 		    if (err) {
296 			(void) fprintf(stderr, gettext(
297 				"%s: cannot continue target : %s\n"),
298 				argv[0], tnfctl_strerror(err));
299 			goto Cleanup;
300 		    }
301 		}
302 		err = check_trace_error(g_hndl);
303 		if (err) {
304 			(void) fprintf(stderr, gettext(
305 				"%s: cannot read tracing status : %s\n"),
306 				argv[0], tnfctl_strerror(err));
307 			goto Cleanup;
308 		}
309 		if (!g_kernelmode) {
310 			if (event == TNFCTL_EVENT_EXEC) {
311 			    (void) printf(gettext(
312 				"Target process exec'd\n"));
313 			    quit(B_FALSE, B_TRUE);	/* quit resume */
314 			} else if (event == TNFCTL_EVENT_EXIT) {
315 			    /* target exited */
316 			    (void) fprintf(stderr, gettext(
317 				"%s: target process exited\n"),
318 				g_argv[0]);
319 			    goto Cleanup;
320 			} else if (event == TNFCTL_EVENT_TARGGONE) {
321 				/* target terminated */
322 			    (void) fprintf(stderr,
323 	gettext("%s: target process disappeared (without calling exit)\n"),
324 				g_argv[0]);
325 			    goto Cleanup;
326 			}
327 		}
328 	}
329 
330 Cleanup:
331 	err = tnfctl_close(g_hndl, TNFCTL_TARG_DEFAULT);
332 	if (err)
333 		(void) fprintf(stderr, gettext(
334 			"%s: error on closing : %s\n"),
335 			argv[0], tnfctl_strerror(err));
336 
337 	exit(0);
338 
339 	return (0);
340 
341 }
342 
343 /*
344  * check_trace_error() - checks whether there was an error in tracing
345  */
346 static tnfctl_errcode_t
347 check_trace_error(tnfctl_handle_t *hndl)
348 {
349 	tnfctl_trace_attrs_t	trace_attrs;
350 	tnfctl_errcode_t	err;
351 
352 	err = tnfctl_trace_attrs_get(hndl, &trace_attrs);
353 	if (err)
354 		return (err);
355 
356 	if (trace_attrs.trace_buf_state == TNFCTL_BUF_BROKEN) {
357 		(void) printf(gettext("Tracing shut down in target program "
358 			"due to an internal error - Please restart prex "
359 			"and target\n"));
360 	}
361 
362 	return (TNFCTL_ERR_NONE);
363 }
364 
365 /*
366  * set_default_cmd() - set the default debug entry and $all
367  */
368 static void
369 set_default_cmd(void)
370 {
371 	if (!g_kernelmode)
372 		fcn(strdup("debug"), DEBUG_ENTRY);
373 #ifdef TESTING
374 	fcn(strdup("empty"), EMPTY_ENTRY);
375 #endif
376 	(void) set(strdup("all"), expr(spec(strdup("keys"), SPEC_EXACT),
377 				spec(strdup(".*"), SPEC_REGEXP)));
378 
379 }
380 
381 /*
382  * process() - enable and disable selected probes
383  */
384 
385 typedef struct {
386 	tnfctl_probe_t	*probe_p;
387 	tnfctl_handle_t	*hndl;
388 } process_args_t;
389 
390 static tnfctl_errcode_t
391 percmd(expr_t *expr_p, cmd_kind_t kind, fcn_t *fcn_p, boolean_t isnew,
392 	void *calldata_p)
393 {
394 	process_args_t *args_p = (process_args_t *)calldata_p;
395 	tnfctl_handle_t	*hndl = args_p->hndl;
396 	tnfctl_probe_t	*probe_p = args_p->probe_p;
397 	tnfctl_errcode_t err = TNFCTL_ERR_NONE;
398 	char *attrs;
399 
400 	attrs = list_getattrs(probe_p);
401 
402 	if (expr_match(expr_p, attrs)) {
403 #if defined(DEBUG) || defined(lint)
404 		if (g_verbose) {
405 			char		   *cmdstr[] = {
406 				"enable", "disable",
407 				"connect", "clear",
408 				"trace", "untrace"};
409 
410 			(void) fprintf(stderr, ": %s command: %s ",
411 				(isnew) ? "new" : "old", cmdstr[kind]);
412 			expr_print(stderr, expr_p);
413 		}
414 #endif
415 
416 		switch (kind) {
417 		case CMD_ENABLE:
418 			err = tnfctl_probe_enable(hndl, probe_p, NULL);
419 			break;
420 		case CMD_DISABLE:
421 			err = tnfctl_probe_disable(hndl, probe_p, NULL);
422 			break;
423 		case CMD_TRACE:
424 			err = tnfctl_probe_trace(hndl, probe_p, NULL);
425 			break;
426 		case CMD_UNTRACE:
427 			err = tnfctl_probe_untrace(hndl, probe_p, NULL);
428 			break;
429 		case CMD_CONNECT:
430 			err = tnfctl_probe_connect(hndl, probe_p, NULL,
431 				fcn_p->entry_name_p);
432 			break;
433 		case CMD_CLEAR:
434 			err = tnfctl_probe_disconnect_all(hndl, probe_p, NULL);
435 			break;
436 		}
437 
438 #if defined(DEBUG) || defined(lint)
439 		if (g_verbose)
440 			(void) fprintf(stderr, "\n");
441 #endif
442 
443 	}
444 	if (attrs)
445 		free(attrs);
446 
447 	return (err);
448 
449 }
450 
451 /*ARGSUSED*/
452 static void *
453 perprobe(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p)
454 {
455 	process_args_t  args;
456 	tnfctl_errcode_t err;
457 
458 	args.probe_p = probe_p;
459 	args.hndl = hndl;
460 	err = cmd_traverse(percmd, &args);
461 	if (err) {
462 		(void) fprintf(stderr, gettext(
463 				"%s: error on new (dlopened) probe : %s\n"),
464 				g_argv[0], tnfctl_strerror(err));
465 	}
466 	return (NULL);
467 }
468 
469 static tnfctl_errcode_t
470 set_probe_discovery_callback(tnfctl_handle_t *hndl)
471 {
472 	tnfctl_errcode_t err;
473 
474 	err = tnfctl_register_funcs(hndl, perprobe, NULL);
475 	if (err)
476 		return (err);
477 
478 	return (TNFCTL_ERR_NONE);
479 }
480 
481 static tnfctl_errcode_t
482 perprobe2(tnfctl_handle_t *hndl, tnfctl_probe_t *probe_p, void *cd)
483 {
484 	cmd_t		*cmd = cd;
485 	process_args_t  args;
486 	tnfctl_errcode_t err;
487 
488 	args.probe_p = probe_p;
489 	args.hndl = hndl;
490 	err = cmd_callback(cmd, percmd, &args);
491 	if (err) {
492 		(void) fprintf(stderr, gettext(
493 				"%s: error on probe operation: %s\n"),
494 				g_argv[0], tnfctl_strerror(err));
495 	}
496 	return (err);
497 }
498 
499 void
500 process_cmd(tnfctl_handle_t *hndl, cmd_t *cmd)
501 {
502 #if defined(DEBUG) || defined(lint)
503 	if (g_verbose)
504 		(void) fprintf(stderr, "processing commands\n");
505 #endif
506 	(void) tnfctl_probe_apply(hndl, perprobe2, cmd);
507 }
508 
509 /*
510  * get_commands() - process commands from stdin
511  */
512 static void
513 get_commands(void)
514 {
515 	/* Read commands from STDIN */
516 	if (g_kernelmode) {
517 		(void) printf(gettext("Type \"help\" for help ...\n"));
518 	} else {
519 		if (g_testflag)
520 			(void) printf("prex(%ld), target(%ld): ",
521 					getpid(), g_targetpid);
522 		(void) printf(gettext("Target process stopped\n"));
523 		(void) printf(gettext(
524 			"Type \"continue\" to resume the target, "
525 			"\"help\" for help ...\n"));
526 	}
527 
528 	while (yyparse());
529 }
530 
531 
532 /*
533  * quit() - called to quit the controlling process. The boolean argument
534  * specifies whether to terminate the target as well.
535  */
536 
537 void
538 quit(boolean_t killtarget, boolean_t runtarget)
539 {
540 	tnfctl_errcode_t err;
541 
542 	if (killtarget && runtarget)
543 		err = tnfctl_close(g_hndl, TNFCTL_TARG_DEFAULT);
544 	else if (killtarget && !runtarget)
545 		err = tnfctl_close(g_hndl, TNFCTL_TARG_KILL);
546 	else if (!killtarget && runtarget)
547 		err = tnfctl_close(g_hndl, TNFCTL_TARG_RESUME);
548 	else if (!killtarget && !runtarget)
549 		err = tnfctl_close(g_hndl, TNFCTL_TARG_SUSPEND);
550 	if (err) {
551 		(void) fprintf(stderr, gettext(
552 				"%s: trouble quitting : %s\n"),
553 				g_argv[0], tnfctl_strerror(err));
554 		exit(1);
555 	}
556 	exit(0);
557 }
558 
559 
560 /*
561  * scanargs() - processes the command line arguments
562  */
563 
564 #define	strneq(s1, s2, n) 	(strncmp(s1, s2, n) == 0)
565 
566 static void
567 scanargs(int argc,
568 	char **argv)
569 {
570 	int			 c;
571 #if defined(DEBUG) || defined(lint)
572 	char		   *optstr = "l:o:p:s:tkv:";	/* debugging options */
573 #else
574 	char		   *optstr = "l:o:p:s:tk";	/* production options */
575 #endif
576 
577 	/* set up some defaults */
578 	g_targetpid = 0;
579 	g_cmdname = NULL;
580 	g_cmdargs = NULL;
581 	g_preload = NULL;
582 	g_outname = NULL;
583 	g_outsize = -1;
584 
585 	while ((c = getopt(argc, argv, optstr)) != EOF) {
586 		switch (c) {
587 		case 'l':	/* preload objects */
588 			g_preload = optarg;
589 			break;
590 		case 'o':	/* tracefile name */
591 			g_outname = optarg;
592 			break;
593 		case 'p':	/* target pid (attach case) */
594 			g_targetpid = atoi(optarg);
595 			break;
596 		case 's':	/* tracefile size */
597 			g_outsize = atoi(optarg) * 1024;
598 			break;
599 		case 't':	/* test flag */
600 			g_testflag = B_TRUE;
601 			(void) setvbuf(stdout, NULL, _IOLBF, 0);
602 			break;
603 		case 'k':	/* kernel mode */
604 			g_kernelmode = B_TRUE;
605 			break;
606 #if defined(DEBUG) || defined(lint)
607 		case 'v':	/* verbose flag */
608 			g_verbose = atoi(optarg);
609 			break;
610 #endif
611 		case '?':	/* error case */
612 			usage(argv, gettext("unrecognized argument"));
613 		}
614 	}
615 
616 	if (optind < argc) {
617 		g_cmdname = strdup(argv[optind]);
618 		g_cmdargs = &argv[optind];
619 	}
620 	/* sanity clause */
621 	if (!g_kernelmode && (g_cmdname == NULL && g_targetpid == 0))
622 		usage(argv, gettext("need to specify cmd or pid"));
623 	if (g_cmdname != NULL && g_targetpid != 0)
624 		usage(argv, gettext("can't specify both cmd and pid"));
625 	if (g_targetpid && g_preload)
626 		usage(argv, gettext("can't use preload option with attach"));
627 	if (g_kernelmode) {
628 		if (g_outname)
629 			usage(argv, "can't specify a filename in kernel mode");
630 		if (g_cmdname)
631 			usage(argv, "can't specify a command in kernel mode");
632 		if (g_targetpid)
633 			usage(argv, "can't specify pid in kernel mode");
634 		if (g_preload)
635 			usage(argv, "can't use preload option in kernel mode");
636 	}
637 	/* default output size */
638 	if (g_outsize == -1)
639 		g_outsize = g_kernelmode ? KERNEL_OUTSIZE : USER_OUTSIZE;
640 
641 #ifdef OLD
642 	int			 i;
643 
644 	for (i = 1; i < argc; i++) {
645 		if (strneq(argv[i], "-v", 2)) {
646 			int			 vlevel;
647 
648 			vlevel = (strlen(argv[i]) > 2)? atoi(&argv[i][2]) : 1;
649 			g_verbose = B_TRUE;
650 			prb_verbose_set(vlevel);
651 		} else if (strneq(argv[i], "-pid", 2)) {
652 			if (++i >= argc)
653 				usage(argv, gettext("missing pid argument"));
654 			g_targetpid = atoi(argv[i]);
655 		} else if (strneq(argv[i], "-t", 2)) {
656 			g_testflag = B_TRUE;
657 			(void) setvbuf(stdout, NULL, _IOLBF, 0);
658 		} else if (argv[i][0] != '-') {
659 			g_cmdname = strdup(argv[i]);
660 			if (!g_cmdname) {
661 				err_fatal(gettext(
662 					"%s: out of memory"), argv[0]);
663 			}
664 			if (g_verbose >= 2) {
665 				(void) fprintf(stderr,
666 					"cmdname=%s\n", g_cmdname);
667 			}
668 			/*
669 			 * rest of arguments are the args to the executable -
670 			 * by convention argv[0] should be name of
671 			 * executable, so we don't increment i
672 			 */
673 			g_cmdargs = &argv[i];
674 			break;
675 		} else {
676 			usage(argv, gettext("unrecognized argument"));
677 		}
678 	}
679 #endif
680 
681 }				/* end scanargs */
682 
683 
684 /*
685  * sig_handler() - cleans up if a signal is received
686  */
687 
688 /*ARGSUSED*/
689 static void
690 sig_handler(int signo)
691 {
692 	g_getcmds = B_TRUE;
693 }				/* end sig_handler */
694 
695 
696 /*
697  * set_signal() -  sets up function to call for clean up
698  */
699 
700 static int
701 set_signal(void)
702 {
703 	struct sigaction newact;
704 
705 	newact.sa_handler = sig_handler;
706 	(void) sigemptyset(&newact.sa_mask);
707 	newact.sa_flags = 0;
708 	if (sigaction(SIGINT, &newact, NULL) < 0) {
709 		return (errno);
710 	}
711 	return (0);
712 }
713 
714 
715 /*
716  * set_tracefile() - initializes tracefile, sets the tracefile name and size
717  */
718 static tnfctl_errcode_t
719 set_tracefile(tnfctl_handle_t *hndl)
720 {
721 	tnfctl_errcode_t	err;
722 	tnfctl_trace_attrs_t	attrs;
723 	size_t			minoutsize;
724 	char			path[MAXPATHLEN];
725 	char			*outfile_name;
726 	char			*tmpdir;
727 
728 	/* Init tracefile name used by list cmd */
729 	tracefile = NULL;
730 	err = tnfctl_trace_attrs_get(hndl, &attrs);
731 	if (err)
732 		return (err);
733 
734 	if (attrs.trace_buf_state == TNFCTL_BUF_BROKEN)
735 		return (TNFCTL_ERR_BUFBROKEN);
736 	if (attrs.trace_buf_state == TNFCTL_BUF_OK) {
737 		/* trace file set already - can't change it */
738 		return (TNFCTL_ERR_NONE);
739 	}
740 
741 	minoutsize = attrs.trace_min_size;
742 	if (g_outsize < minoutsize)	{
743 		(void) fprintf(stderr,
744 			gettext("specified tracefile size smaller then "
745 				"minimum; setting to %d kbytes\n"),
746 				minoutsize / 1024);
747 		g_outsize = minoutsize;
748 	}
749 
750 	/* where is $TMPDIR? */
751 	tmpdir = getenv("TMPDIR");
752 	if (!tmpdir || *tmpdir == '\0') {
753 		tmpdir = "/tmp";
754 	}
755 
756 	/* do we have an absolute, relative or no pathname specified? */
757 	if (g_outname == NULL) {
758 		/* default, no tracefile specified */
759 		if ((strlen(tmpdir) + 1 + 20) > (size_t)MAXPATHLEN) {
760 			(void) fprintf(stderr, gettext(
761 				"%s: $TMPDIR too long\n"), g_argv[0]);
762 			exit(1);
763 		}
764 		(void) sprintf(path, "%s/trace-%ld", tmpdir, g_targetpid);
765 		outfile_name = path;
766 	} else {
767 		/* filename specified */
768 		outfile_name = g_outname;
769 	}
770 	tracefile = strdup(outfile_name);
771 	if (tracefile == NULL) {
772 		if ((errno == ENOMEM) || (errno == EAGAIN)) {
773 			return (TNFCTL_ERR_ALLOCFAIL);
774 		} else {
775 			return (TNFCTL_ERR_INTERNAL);
776 		}
777 	}
778 
779 #if defined(DEBUG) || defined(lint)
780 	if (g_verbose)
781 		(void) fprintf(stderr,
782 			"setting tracefile name=\"%s\", size=%d\n",
783 			path, g_outsize);
784 #endif
785 	err = tnfctl_buffer_alloc(hndl, outfile_name, g_outsize);
786 	return (err);
787 }
788 /*
789  * get_data_model() - get the process data model from psinfo
790  *		      structure.
791  */
792 #define	PROCFORMAT	"/proc/%d"
793 static int
794 get_data_model(pid_t pid)
795 {
796 	char	path[MAXPATHLEN];
797 	int	fd, dmodel = -1;
798 	prpsinfo_t	psinfo;
799 
800 	(void) sprintf(path, PROCFORMAT, (int)pid);
801 	fd = open(path, O_RDONLY);
802 	if (fd == -1)
803 	    return (dmodel);
804 	if ((dmodel = ioctl(fd, PIOCPSINFO, &psinfo)) == -1)
805 	    return (dmodel);
806 	return ((int)psinfo.pr_dmodel);
807 }
808 /*
809  * get_executable - return file descriptor for PATH-resolved
810  *		    target file.
811  *
812  */
813 static int
814 get_executable(char *name) {
815     int fd = -1;
816 
817     if (name != NULL) {
818 	char path[PATH_MAX + 1];
819 	char line[MAX_INPUT + 1];
820 	char *p = line;
821 	char *fname = name;
822 	int N = sizeof (line);
823 	struct stat file_att;
824 
825 	while (*fname == ' ') fname++;
826 	if (fname[0] == '-' || strchr(fname, '/')) {
827 	    fd = open(fname, O_RDONLY);
828 	} else {
829 	    int len = strlen(fname);
830 	    char *dirlist = getenv("PATH");
831 	    char *dir = NULL;
832 
833 	    if (dirlist != NULL) {
834 		dirlist = strdup(dirlist);
835 		dir = strtok(dirlist, ":");
836 	    }
837 	    while (fd < 0 && dir != NULL) {
838 		if ((strlen(dir) + len + 1) < sizeof (path)) {
839 		    strcat(strcat(strcpy(path, dir), "/"), fname);
840 		    fd = open(path, O_RDONLY);
841 		}
842 		dir = strtok(NULL, ":");
843 	    }
844 	    if (dirlist != NULL) free(dirlist);
845 	}
846 	if (fstat(fd, &file_att) || !S_ISREG(file_att.st_mode)) {
847 	    if (fd >= 0)
848 		close(fd);
849 	    return (-1);
850 	}
851 	if (read(fd, p, 2) && p[0] == '#' && p[1] == '!') {
852 	    while (N-- > 1 && read(fd, p, 1) && *p != '\n')
853 		p++;
854 	    *p = '\0';
855 	    close(fd);
856 	    return (get_executable(line));
857 	}
858 	if (fd >= 0) lseek(fd, 0, SEEK_SET);
859 	} /* %$#@! cstyle complaint */
860     return (fd);
861 }
862 
863 /*
864  * get_elf_class - get the target executable elf class
865  *                 i.e. ELFCLASS64 or ELFCLASS32.
866  */
867 static int
868 get_elf_class(char *filename)
869 {
870 	int	elfclass = -1;
871 	int	elffd = get_executable(filename);
872 	Elf	*elf;
873 	size_t	size;
874 	char	*ident;
875 	GElf_Ehdr	ehdr;
876 
877 	if (elffd < 0)
878 		return (elfclass);
879 	if (elf_version(EV_CURRENT) == EV_NONE) {
880 		(void) close(elffd);
881 		return (elfclass);
882 	}
883 	elf = elf_begin(elffd, ELF_C_READ, (Elf *) 0);
884 	/*
885 	 * verify information in file header
886 	 */
887 	if (gelf_getehdr(elf, &ehdr) == (GElf_Ehdr *) 0) {
888 		close(elffd);
889 		return (elfclass);
890 	}
891 	ident = elf_getident(elf, &size);
892 	if (ident[EI_CLASS] == ELFCLASS32)
893 		elfclass = ELFCLASS32;
894 	if (ident[EI_CLASS] == ELFCLASS64)
895 		elfclass = ELFCLASS64;
896 	close(elffd);
897 	return (elfclass);
898 }
899 /*
900  * check_exec_model() - check the consistency between prex data model
901  *                      and target elf class and act accordingly
902  */
903 static void
904 check_exec_model(char **argv, char **envp)
905 {
906 	int	elfclass;
907 
908 	elfclass = get_elf_class(g_cmdname);
909 	if (((elfclass == ELFCLASS32) && (prex_dmodel == PR_MODEL_ILP32)) ||
910 	    ((elfclass == ELFCLASS64) && (prex_dmodel == PR_MODEL_LP64)))
911 	    return;
912 	if ((prex_dmodel == PR_MODEL_ILP32) &&
913 	    (elfclass == ELFCLASS64)) {
914 	    (void) fprintf(stderr, gettext(
915 		"Error: 32 bit prex can not exec 64 bit target\n"));
916 	    exit(1);
917 	}
918 	if ((prex_dmodel == PR_MODEL_LP64) &&
919 	    (elfclass == ELFCLASS32))
920 	    prex_isaexec(argv, envp);
921 }
922 
923 /*
924  * check_pid_model() - check the consistency between prex data model
925  *                     and target data model and act accordingly
926  */
927 static void
928 check_pid_model(char **argv, char **envp)
929 {
930 	int	dmodel;
931 
932 	dmodel = get_data_model(g_targetpid);
933 	if (prex_dmodel == dmodel)
934 		return;
935 	if ((prex_dmodel == PR_MODEL_ILP32) &&
936 		(dmodel == PR_MODEL_LP64)) {
937 		(void) fprintf(stderr, gettext(
938 		    "Error: 32 bit prex can not exec 64 bit target\n"));
939 		exit(1);
940 	}
941 	if ((prex_dmodel == PR_MODEL_LP64) &&
942 		(dmodel == PR_MODEL_ILP32))
943 		prex_isaexec(argv, envp);
944 }
945 /*
946  * prex_isaexec() - there is only one case this function get called
947  *                  64 bit prex, 32 bit target, need to exec 32 bit
948  *                  prex here.
949  */
950 static void
951 prex_isaexec(char **argv, char **envp)
952 {
953 	char path[PATH_MAX + sizeof (PREX32DIR)];
954 	strcat(strcat(strcpy(path, dirname(dirname(argv[0]))), PREX32DIR),
955 	    basename(argv[0]));
956 	if (get_elf_class(path) != ELFCLASS32)
957 	    strcpy(path, PREX32EXEC);
958 	argv[0] = path;
959 	(void) execve(path, argv, envp);
960 	(void) fprintf(stderr,
961 	    gettext("%s: execve(\"%s\") failed\n"),
962 	    argv[0], path);
963 }
964 void
965 cmd_listtracefile()
966 {
967 
968 	if (g_kernelmode) {
969 	    (void) fprintf(stderr,
970 		    gettext("There is no trace file in kernel mode!\n"));
971 	} else {
972 	    (void) printf(gettext("Current trace file is: %s\n"), tracefile);
973 	}
974 }
975