xref: /illumos-gate/usr/src/cmd/ptools/pargs/pargs.c (revision 56726c7e321b6e5ecb2f10215f5386016547e68c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59acbbeafSnn35248  * Common Development and Distribution License (the "License").
69acbbeafSnn35248  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2207678296Ssl108498  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
25ebb8ac07SRobert Mustacchi /*
26d0158222SRobert Mustacchi  * Copyright (c) 2018, Joyent, Inc.
27*56726c7eSRobert Mustacchi  * Copyright 2022 Oxide Computer Company
28ebb8ac07SRobert Mustacchi  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * pargs examines and prints the arguments (argv), environment (environ),
327c478bd9Sstevel@tonic-gate  * and auxiliary vector of another process.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * This utility is made more complex because it must run in internationalized
357c478bd9Sstevel@tonic-gate  * environments.  The two key cases for pargs to manage are:
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * 1. pargs and target run in the same locale: pargs must respect the
387c478bd9Sstevel@tonic-gate  * locale, but this case is straightforward.  Care is taken to correctly
397c478bd9Sstevel@tonic-gate  * use wide characters in order to print results properly.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * 2. pargs and target run in different locales: in this case, pargs examines
427c478bd9Sstevel@tonic-gate  * the string having assumed the victim's locale.  Unprintable (but valid)
437c478bd9Sstevel@tonic-gate  * characters are escaped.  Next, iconv(3c) is used to convert between the
447c478bd9Sstevel@tonic-gate  * target and pargs codeset.  Finally, a second pass to escape unprintable
457c478bd9Sstevel@tonic-gate  * (but valid) characters is made.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * In any case in which characters are encountered which are not valid in
487c478bd9Sstevel@tonic-gate  * their purported locale, the string "fails" and is treated as a traditional
497c478bd9Sstevel@tonic-gate  * 7-bit ASCII encoded string, and escaped accordingly.
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <stdio.h>
537c478bd9Sstevel@tonic-gate #include <stdlib.h>
547c478bd9Sstevel@tonic-gate #include <locale.h>
557c478bd9Sstevel@tonic-gate #include <wchar.h>
567c478bd9Sstevel@tonic-gate #include <iconv.h>
577c478bd9Sstevel@tonic-gate #include <langinfo.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
597c478bd9Sstevel@tonic-gate #include <ctype.h>
607c478bd9Sstevel@tonic-gate #include <fcntl.h>
617c478bd9Sstevel@tonic-gate #include <string.h>
627c478bd9Sstevel@tonic-gate #include <strings.h>
637c478bd9Sstevel@tonic-gate #include <limits.h>
647c478bd9Sstevel@tonic-gate #include <pwd.h>
657c478bd9Sstevel@tonic-gate #include <grp.h>
667c478bd9Sstevel@tonic-gate #include <errno.h>
677c478bd9Sstevel@tonic-gate #include <setjmp.h>
687c478bd9Sstevel@tonic-gate #include <sys/types.h>
697c478bd9Sstevel@tonic-gate #include <sys/auxv.h>
707c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
717c478bd9Sstevel@tonic-gate #include <sys/proc.h>
727c478bd9Sstevel@tonic-gate #include <sys/elf.h>
737c478bd9Sstevel@tonic-gate #include <libproc.h>
747c478bd9Sstevel@tonic-gate #include <wctype.h>
757c478bd9Sstevel@tonic-gate #include <widec.h>
767c478bd9Sstevel@tonic-gate #include <elfcap.h>
77ffec1fd1SRobert Mustacchi #include <libgen.h>
78ffec1fd1SRobert Mustacchi 
79ffec1fd1SRobert Mustacchi typedef enum pargs_cmd {
80ffec1fd1SRobert Mustacchi 	PARGS_ARGV,
81ffec1fd1SRobert Mustacchi 	PARGS_ENV,
82ffec1fd1SRobert Mustacchi 	PARGS_AUXV
83ffec1fd1SRobert Mustacchi } pargs_cmd_t;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate typedef struct pargs_data {
867c478bd9Sstevel@tonic-gate 	struct ps_prochandle *pd_proc;	/* target proc handle */
877c478bd9Sstevel@tonic-gate 	psinfo_t *pd_psinfo;		/* target psinfo */
887c478bd9Sstevel@tonic-gate 	char *pd_locale;		/* target process locale */
897c478bd9Sstevel@tonic-gate 	int pd_conv_flags;		/* flags governing string conversion */
907c478bd9Sstevel@tonic-gate 	iconv_t pd_iconv;		/* iconv conversion descriptor */
917c478bd9Sstevel@tonic-gate 	size_t pd_argc;
927c478bd9Sstevel@tonic-gate 	uintptr_t *pd_argv;
937c478bd9Sstevel@tonic-gate 	char **pd_argv_strs;
947c478bd9Sstevel@tonic-gate 	size_t pd_envc;
95b0801aa3SMarcel Telka 	size_t pd_env_space;
967c478bd9Sstevel@tonic-gate 	uintptr_t *pd_envp;
977c478bd9Sstevel@tonic-gate 	char **pd_envp_strs;
987c478bd9Sstevel@tonic-gate 	size_t pd_auxc;
997c478bd9Sstevel@tonic-gate 	auxv_t *pd_auxv;
1007c478bd9Sstevel@tonic-gate 	char **pd_auxv_strs;
1017c478bd9Sstevel@tonic-gate 	char *pd_execname;
1027c478bd9Sstevel@tonic-gate } pargs_data_t;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #define	CONV_USE_ICONV		0x01
1057c478bd9Sstevel@tonic-gate #define	CONV_STRICT_ASCII	0x02
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate static char *command;
1087c478bd9Sstevel@tonic-gate static int dmodel;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #define	EXTRACT_BUFSZ 128		/* extract_string() initial size */
1117c478bd9Sstevel@tonic-gate #define	ENV_CHUNK 16			/* #env ptrs to read at a time */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static jmp_buf env;			/* malloc failure handling */
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static void *
safe_zalloc(size_t size)1167c478bd9Sstevel@tonic-gate safe_zalloc(size_t size)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate 	void *p;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/*
1217c478bd9Sstevel@tonic-gate 	 * If the malloc fails we longjmp out to allow the code to Prelease()
1227c478bd9Sstevel@tonic-gate 	 * a stopped victim if needed.
1237c478bd9Sstevel@tonic-gate 	 */
1247c478bd9Sstevel@tonic-gate 	if ((p = malloc(size)) == NULL) {
1257c478bd9Sstevel@tonic-gate 		longjmp(env, errno);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	bzero(p, size);
1297c478bd9Sstevel@tonic-gate 	return (p);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static char *
safe_strdup(const char * s1)1337c478bd9Sstevel@tonic-gate safe_strdup(const char *s1)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate 	char	*s2;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	s2 = safe_zalloc(strlen(s1) + 1);
1387c478bd9Sstevel@tonic-gate 	(void) strcpy(s2, s1);
1397c478bd9Sstevel@tonic-gate 	return (s2);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /*
1437c478bd9Sstevel@tonic-gate  * Given a wchar_t which might represent an 'escapable' sequence (see
144bbf21555SRichard Lowe  * formats(7)), return the base ascii character needed to print that
1457c478bd9Sstevel@tonic-gate  * sequence.
1467c478bd9Sstevel@tonic-gate  *
1477c478bd9Sstevel@tonic-gate  * The comparisons performed may look suspect at first, but all are valid;
1487c478bd9Sstevel@tonic-gate  * the characters below all appear in the "Portable Character Set."  The
1497c478bd9Sstevel@tonic-gate  * Single Unix Spec says: "The wide-character value for each member of the
1507c478bd9Sstevel@tonic-gate  * Portable Character Set will equal its value when used as the lone
1517c478bd9Sstevel@tonic-gate  * character in an integer character constant."
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate static uchar_t
get_interp_char(wchar_t wc)1547c478bd9Sstevel@tonic-gate get_interp_char(wchar_t wc)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	switch (wc) {
1577c478bd9Sstevel@tonic-gate 	case L'\a':
1587c478bd9Sstevel@tonic-gate 		return ('a');
1597c478bd9Sstevel@tonic-gate 	case L'\b':
1607c478bd9Sstevel@tonic-gate 		return ('b');
1617c478bd9Sstevel@tonic-gate 	case L'\f':
1627c478bd9Sstevel@tonic-gate 		return ('f');
1637c478bd9Sstevel@tonic-gate 	case L'\n':
1647c478bd9Sstevel@tonic-gate 		return ('n');
1657c478bd9Sstevel@tonic-gate 	case L'\r':
1667c478bd9Sstevel@tonic-gate 		return ('r');
1677c478bd9Sstevel@tonic-gate 	case L'\t':
1687c478bd9Sstevel@tonic-gate 		return ('t');
1697c478bd9Sstevel@tonic-gate 	case L'\v':
1707c478bd9Sstevel@tonic-gate 		return ('v');
1717c478bd9Sstevel@tonic-gate 	case L'\\':
1727c478bd9Sstevel@tonic-gate 		return ('\\');
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 	return ('\0');
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static char *
unctrl_str_strict_ascii(const char * src,int escape_slash,int * unprintable)1787c478bd9Sstevel@tonic-gate unctrl_str_strict_ascii(const char *src, int escape_slash, int *unprintable)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	uchar_t *uc, *ucp, c, ic;
1817c478bd9Sstevel@tonic-gate 	uc = ucp = safe_zalloc((strlen(src) * 4) + 1);
1827c478bd9Sstevel@tonic-gate 	while ((c = *src++) != '\0') {
1837c478bd9Sstevel@tonic-gate 		/*
1847c478bd9Sstevel@tonic-gate 		 * Call get_interp_char *first*, since \ will otherwise not
1857c478bd9Sstevel@tonic-gate 		 * be escaped as \\.
1867c478bd9Sstevel@tonic-gate 		 */
1877c478bd9Sstevel@tonic-gate 		if ((ic = get_interp_char((wchar_t)c)) != '\0') {
1887c478bd9Sstevel@tonic-gate 			if (escape_slash || ic != '\\')
1897c478bd9Sstevel@tonic-gate 				*ucp++ = '\\';
1907c478bd9Sstevel@tonic-gate 			*ucp++ = ic;
1917c478bd9Sstevel@tonic-gate 		} else if (isascii(c) && isprint(c)) {
1927c478bd9Sstevel@tonic-gate 			*ucp++ = c;
1937c478bd9Sstevel@tonic-gate 		} else {
1947c478bd9Sstevel@tonic-gate 			*ucp++ = '\\';
1957c478bd9Sstevel@tonic-gate 			*ucp++ = ((c >> 6) & 7) + '0';
1967c478bd9Sstevel@tonic-gate 			*ucp++ = ((c >> 3) & 7) + '0';
1977c478bd9Sstevel@tonic-gate 			*ucp++ = (c & 7) + '0';
1987c478bd9Sstevel@tonic-gate 			*unprintable = 1;
1997c478bd9Sstevel@tonic-gate 		}
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 	*ucp = '\0';
2027c478bd9Sstevel@tonic-gate 	return ((char *)uc);
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*
206bbf21555SRichard Lowe  * Convert control characters as described in formats(7) to their readable
2077c478bd9Sstevel@tonic-gate  * representation; special care is taken to handle multibyte character sets.
2087c478bd9Sstevel@tonic-gate  *
2097c478bd9Sstevel@tonic-gate  * If escape_slash is true, escaping of '\' occurs.  The first time a string
2107c478bd9Sstevel@tonic-gate  * is unctrl'd, this should be '1'.  Subsequent iterations over the same
2117c478bd9Sstevel@tonic-gate  * string should set escape_slash to 0.  Otherwise you'll wind up with
2127c478bd9Sstevel@tonic-gate  * \ --> \\ --> \\\\.
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate static char *
unctrl_str(const char * src,int escape_slash,int * unprintable)2157c478bd9Sstevel@tonic-gate unctrl_str(const char *src, int escape_slash, int *unprintable)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate 	wchar_t wc;
2187c478bd9Sstevel@tonic-gate 	wchar_t *wide_src, *wide_srcp;
2197c478bd9Sstevel@tonic-gate 	wchar_t *wide_dest, *wide_destp;
2207c478bd9Sstevel@tonic-gate 	char *uc;
2217c478bd9Sstevel@tonic-gate 	size_t srcbufsz = strlen(src) + 1;
2227c478bd9Sstevel@tonic-gate 	size_t destbufsz = srcbufsz * 4;
2237c478bd9Sstevel@tonic-gate 	size_t srclen, destlen;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	wide_srcp = wide_src = safe_zalloc(srcbufsz * sizeof (wchar_t));
2267c478bd9Sstevel@tonic-gate 	wide_destp = wide_dest = safe_zalloc(destbufsz * sizeof (wchar_t));
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	if ((srclen = mbstowcs(wide_src, src, srcbufsz - 1)) == (size_t)-1) {
2297c478bd9Sstevel@tonic-gate 		/*
2307c478bd9Sstevel@tonic-gate 		 * We can't trust the string, since in the locale in which
2317c478bd9Sstevel@tonic-gate 		 * this call is operating, the string contains an invalid
2327c478bd9Sstevel@tonic-gate 		 * multibyte sequence.  There isn't much to do here, so
2337c478bd9Sstevel@tonic-gate 		 * convert the string byte by byte to wide characters, as
2347c478bd9Sstevel@tonic-gate 		 * if it came from a C locale (char) string.  This isn't
2357c478bd9Sstevel@tonic-gate 		 * perfect, but at least the characters will make it to
2367c478bd9Sstevel@tonic-gate 		 * the screen.
2377c478bd9Sstevel@tonic-gate 		 */
2387c478bd9Sstevel@tonic-gate 		free(wide_src);
2397c478bd9Sstevel@tonic-gate 		free(wide_dest);
2407c478bd9Sstevel@tonic-gate 		return (unctrl_str_strict_ascii(src, escape_slash,
2417c478bd9Sstevel@tonic-gate 		    unprintable));
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	if (srclen == (srcbufsz - 1)) {
2447c478bd9Sstevel@tonic-gate 		wide_src[srclen] = L'\0';
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	while ((wc = *wide_srcp++) != L'\0') {
2487c478bd9Sstevel@tonic-gate 		char cvt_buf[MB_LEN_MAX];
2497c478bd9Sstevel@tonic-gate 		int len, i;
2507c478bd9Sstevel@tonic-gate 		char c = get_interp_char(wc);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 		if ((c != '\0') && (escape_slash || c != '\\')) {
2537c478bd9Sstevel@tonic-gate 			/*
2547c478bd9Sstevel@tonic-gate 			 * Print "interpreted version" (\n, \a, etc).
2557c478bd9Sstevel@tonic-gate 			 */
2567c478bd9Sstevel@tonic-gate 			*wide_destp++ = L'\\';
2577c478bd9Sstevel@tonic-gate 			*wide_destp++ = (wchar_t)c;
2587c478bd9Sstevel@tonic-gate 			continue;
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 		if (iswprint(wc)) {
2627c478bd9Sstevel@tonic-gate 			*wide_destp++ = wc;
2637c478bd9Sstevel@tonic-gate 			continue;
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		/*
2677c478bd9Sstevel@tonic-gate 		 * Convert the wide char back into (potentially several)
2687c478bd9Sstevel@tonic-gate 		 * multibyte characters, then escape out each of those bytes.
2697c478bd9Sstevel@tonic-gate 		 */
2707c478bd9Sstevel@tonic-gate 		bzero(cvt_buf, sizeof (cvt_buf));
2717c478bd9Sstevel@tonic-gate 		if ((len = wctomb(cvt_buf, wc)) == -1) {
2727c478bd9Sstevel@tonic-gate 			/*
2737c478bd9Sstevel@tonic-gate 			 * This is a totally invalid wide char; discard it.
2747c478bd9Sstevel@tonic-gate 			 */
2757c478bd9Sstevel@tonic-gate 			continue;
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 		for (i = 0; i < len; i++) {
2787c478bd9Sstevel@tonic-gate 			uchar_t c = cvt_buf[i];
2797c478bd9Sstevel@tonic-gate 			*wide_destp++ = L'\\';
2807c478bd9Sstevel@tonic-gate 			*wide_destp++ = (wchar_t)('0' + ((c >> 6) & 7));
2817c478bd9Sstevel@tonic-gate 			*wide_destp++ = (wchar_t)('0' + ((c >> 3) & 7));
2827c478bd9Sstevel@tonic-gate 			*wide_destp++ = (wchar_t)('0' + (c & 7));
2837c478bd9Sstevel@tonic-gate 			*unprintable = 1;
2847c478bd9Sstevel@tonic-gate 		}
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	*wide_destp = '\0';
2887c478bd9Sstevel@tonic-gate 	destlen = (wide_destp - wide_dest) * MB_CUR_MAX + 1;
2897c478bd9Sstevel@tonic-gate 	uc = safe_zalloc(destlen);
2907c478bd9Sstevel@tonic-gate 	if (wcstombs(uc, wide_dest, destlen) == (size_t)-1) {
2917c478bd9Sstevel@tonic-gate 		/* If we've gotten this far, wcstombs shouldn't fail... */
2927c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: wcstombs failed unexpectedly: %s\n",
2937c478bd9Sstevel@tonic-gate 		    command, strerror(errno));
2947c478bd9Sstevel@tonic-gate 		exit(1);
2957c478bd9Sstevel@tonic-gate 	} else {
2967c478bd9Sstevel@tonic-gate 		char *tmp;
2977c478bd9Sstevel@tonic-gate 		/*
2987c478bd9Sstevel@tonic-gate 		 * Try to save memory; don't waste 3 * strlen in the
2997c478bd9Sstevel@tonic-gate 		 * common case.
3007c478bd9Sstevel@tonic-gate 		 */
3017c478bd9Sstevel@tonic-gate 		tmp = safe_strdup(uc);
3027c478bd9Sstevel@tonic-gate 		free(uc);
3037c478bd9Sstevel@tonic-gate 		uc = tmp;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	free(wide_dest);
3067c478bd9Sstevel@tonic-gate 	free(wide_src);
3077c478bd9Sstevel@tonic-gate 	return (uc);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate /*
3117c478bd9Sstevel@tonic-gate  * These functions determine which characters are safe to be left unquoted.
3127c478bd9Sstevel@tonic-gate  * Rather than starting with every printable character and subtracting out the
3137c478bd9Sstevel@tonic-gate  * shell metacharacters, we take the more conservative approach of starting with
3147c478bd9Sstevel@tonic-gate  * a set of safe characters and adding those few common punctuation characters
3157c478bd9Sstevel@tonic-gate  * which are known to be safe.  The rules are:
3167c478bd9Sstevel@tonic-gate  *
3177c478bd9Sstevel@tonic-gate  *	If this is a printable character (graph), and not punctuation, it is
3187c478bd9Sstevel@tonic-gate  *	safe to leave unquoted.
3197c478bd9Sstevel@tonic-gate  *
320d0158222SRobert Mustacchi  *	If it's one of the known hard-coded safe characters, it's also safe to
321d0158222SRobert Mustacchi  *	leave unquoted.
3227c478bd9Sstevel@tonic-gate  *
3237c478bd9Sstevel@tonic-gate  *	Otherwise, the entire argument must be quoted.
3247c478bd9Sstevel@tonic-gate  *
325d0158222SRobert Mustacchi  * This will cause some strings to be unnecessarily quoted, but it is safer than
3267c478bd9Sstevel@tonic-gate  * having a character unintentionally interpreted by the shell.
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate static int
issafe_ascii(char c)3297c478bd9Sstevel@tonic-gate issafe_ascii(char c)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	return (isalnum(c) || strchr("_.-/@:,", c) != NULL);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate static int
issafe(wchar_t wc)3357c478bd9Sstevel@tonic-gate issafe(wchar_t wc)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 	return ((iswgraph(wc) && !iswpunct(wc)) ||
3387c478bd9Sstevel@tonic-gate 	    wschr(L"_.-/@:,", wc) != NULL);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3427c478bd9Sstevel@tonic-gate static char *
quote_string_ascii(pargs_data_t * datap,char * src)3437c478bd9Sstevel@tonic-gate quote_string_ascii(pargs_data_t *datap, char *src)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	char *dst;
3467c478bd9Sstevel@tonic-gate 	int quote_count = 0;
3477c478bd9Sstevel@tonic-gate 	int need_quote = 0;
3487c478bd9Sstevel@tonic-gate 	char *srcp, *dstp;
3497c478bd9Sstevel@tonic-gate 	size_t dstlen;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	for (srcp = src; *srcp != '\0'; srcp++) {
3527c478bd9Sstevel@tonic-gate 		if (!issafe_ascii(*srcp)) {
3537c478bd9Sstevel@tonic-gate 			need_quote = 1;
3547c478bd9Sstevel@tonic-gate 			if (*srcp == '\'')
3557c478bd9Sstevel@tonic-gate 				quote_count++;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	if (!need_quote)
3607c478bd9Sstevel@tonic-gate 		return (src);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	/*
3637c478bd9Sstevel@tonic-gate 	 * The only character we care about here is a single quote.  All the
3647c478bd9Sstevel@tonic-gate 	 * other unprintable characters (and backslashes) will have been dealt
3657c478bd9Sstevel@tonic-gate 	 * with by unctrl_str().  We make the following subtitution when we
3667c478bd9Sstevel@tonic-gate 	 * encounter a single quote:
3677c478bd9Sstevel@tonic-gate 	 *
3687c478bd9Sstevel@tonic-gate 	 *	' = '"'"'
3697c478bd9Sstevel@tonic-gate 	 *
3707c478bd9Sstevel@tonic-gate 	 * In addition, we put single quotes around the entire argument.  For
3717c478bd9Sstevel@tonic-gate 	 * example:
3727c478bd9Sstevel@tonic-gate 	 *
3737c478bd9Sstevel@tonic-gate 	 *	foo'bar = 'foo'"'"'bar'
3747c478bd9Sstevel@tonic-gate 	 */
3757c478bd9Sstevel@tonic-gate 	dstlen = strlen(src) + 3 + 4 * quote_count;
3767c478bd9Sstevel@tonic-gate 	dst = safe_zalloc(dstlen);
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	dstp = dst;
3797c478bd9Sstevel@tonic-gate 	*dstp++ = '\'';
3807c478bd9Sstevel@tonic-gate 	for (srcp = src; *srcp != '\0'; srcp++, dstp++) {
3817c478bd9Sstevel@tonic-gate 		*dstp = *srcp;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 		if (*srcp == '\'') {
3847c478bd9Sstevel@tonic-gate 			dstp[1] = '"';
3857c478bd9Sstevel@tonic-gate 			dstp[2] = '\'';
3867c478bd9Sstevel@tonic-gate 			dstp[3] = '"';
3877c478bd9Sstevel@tonic-gate 			dstp[4] = '\'';
3887c478bd9Sstevel@tonic-gate 			dstp += 4;
3897c478bd9Sstevel@tonic-gate 		}
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 	*dstp++ = '\'';
3927c478bd9Sstevel@tonic-gate 	*dstp = '\0';
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	free(src);
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	return (dst);
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate static char *
quote_string(pargs_data_t * datap,char * src)4007c478bd9Sstevel@tonic-gate quote_string(pargs_data_t *datap, char *src)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 	wchar_t *wide_src, *wide_srcp;
4037c478bd9Sstevel@tonic-gate 	wchar_t *wide_dest, *wide_destp;
4047c478bd9Sstevel@tonic-gate 	char *uc;
4057c478bd9Sstevel@tonic-gate 	size_t srcbufsz = strlen(src) + 1;
4067c478bd9Sstevel@tonic-gate 	size_t srclen;
4077c478bd9Sstevel@tonic-gate 	size_t destbufsz;
4087c478bd9Sstevel@tonic-gate 	size_t destlen;
4097c478bd9Sstevel@tonic-gate 	int quote_count = 0;
4107c478bd9Sstevel@tonic-gate 	int need_quote = 0;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (datap->pd_conv_flags & CONV_STRICT_ASCII)
4137c478bd9Sstevel@tonic-gate 		return (quote_string_ascii(datap, src));
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	wide_srcp = wide_src = safe_zalloc(srcbufsz * sizeof (wchar_t));
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	if ((srclen = mbstowcs(wide_src, src, srcbufsz - 1)) == (size_t)-1) {
4187c478bd9Sstevel@tonic-gate 		free(wide_src);
4197c478bd9Sstevel@tonic-gate 		return (quote_string_ascii(datap, src));
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	if (srclen == srcbufsz - 1)
4237c478bd9Sstevel@tonic-gate 		wide_src[srclen] = L'\0';
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	for (wide_srcp = wide_src; *wide_srcp != '\0'; wide_srcp++) {
4267c478bd9Sstevel@tonic-gate 		if (!issafe(*wide_srcp)) {
4277c478bd9Sstevel@tonic-gate 			need_quote = 1;
4287c478bd9Sstevel@tonic-gate 			if (*wide_srcp == L'\'')
4297c478bd9Sstevel@tonic-gate 				quote_count++;
4307c478bd9Sstevel@tonic-gate 		}
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if (!need_quote) {
4347c478bd9Sstevel@tonic-gate 		free(wide_src);
4357c478bd9Sstevel@tonic-gate 		return (src);
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	/*
4397c478bd9Sstevel@tonic-gate 	 * See comment for quote_string_ascii(), above.
4407c478bd9Sstevel@tonic-gate 	 */
4417c478bd9Sstevel@tonic-gate 	destbufsz = srcbufsz + 3 + 4 * quote_count;
4427c478bd9Sstevel@tonic-gate 	wide_destp = wide_dest = safe_zalloc(destbufsz * sizeof (wchar_t));
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	*wide_destp++ = L'\'';
4457c478bd9Sstevel@tonic-gate 	for (wide_srcp = wide_src; *wide_srcp != L'\0';
4467c478bd9Sstevel@tonic-gate 	    wide_srcp++, wide_destp++) {
4477c478bd9Sstevel@tonic-gate 		*wide_destp = *wide_srcp;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 		if (*wide_srcp == L'\'') {
4507c478bd9Sstevel@tonic-gate 			wide_destp[1] = L'"';
4517c478bd9Sstevel@tonic-gate 			wide_destp[2] = L'\'';
4527c478bd9Sstevel@tonic-gate 			wide_destp[3] = L'"';
4537c478bd9Sstevel@tonic-gate 			wide_destp[4] = L'\'';
4547c478bd9Sstevel@tonic-gate 			wide_destp += 4;
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	*wide_destp++ = L'\'';
4587c478bd9Sstevel@tonic-gate 	*wide_destp = L'\0';
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	destlen = destbufsz * MB_CUR_MAX + 1;
4617c478bd9Sstevel@tonic-gate 	uc = safe_zalloc(destlen);
4627c478bd9Sstevel@tonic-gate 	if (wcstombs(uc, wide_dest, destlen) == (size_t)-1) {
4637c478bd9Sstevel@tonic-gate 		/* If we've gotten this far, wcstombs shouldn't fail... */
4647c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: wcstombs failed unexpectedly: %s\n",
4657c478bd9Sstevel@tonic-gate 		    command, strerror(errno));
4667c478bd9Sstevel@tonic-gate 		exit(1);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	free(wide_dest);
4707c478bd9Sstevel@tonic-gate 	free(wide_src);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	return (uc);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate  * Determine the locale of the target process by traversing its environment,
4787c478bd9Sstevel@tonic-gate  * making only one pass for efficiency's sake; stash the result in
4797c478bd9Sstevel@tonic-gate  * datap->pd_locale.
4807c478bd9Sstevel@tonic-gate  *
4817c478bd9Sstevel@tonic-gate  * It's possible that the process has called setlocale() to change its
4827c478bd9Sstevel@tonic-gate  * locale to something different, but we mostly care about making a good
4837c478bd9Sstevel@tonic-gate  * guess as to the locale at exec(2) time.
4847c478bd9Sstevel@tonic-gate  */
4857c478bd9Sstevel@tonic-gate static void
lookup_locale(pargs_data_t * datap)4867c478bd9Sstevel@tonic-gate lookup_locale(pargs_data_t *datap)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	int i, j, composite = 0;
4897c478bd9Sstevel@tonic-gate 	size_t	len = 0;
4907c478bd9Sstevel@tonic-gate 	char	*pd_locale;
4917c478bd9Sstevel@tonic-gate 	char	*lc_all = NULL, *lang = NULL;
4927c478bd9Sstevel@tonic-gate 	char	*lcs[] = { NULL, NULL, NULL, NULL, NULL, NULL };
4937c478bd9Sstevel@tonic-gate 	static const char *cat_names[] = {
4947c478bd9Sstevel@tonic-gate 		"LC_CTYPE=",	"LC_NUMERIC=",	"LC_TIME=",
4957c478bd9Sstevel@tonic-gate 		"LC_COLLATE=",	"LC_MONETARY=",	"LC_MESSAGES="
4967c478bd9Sstevel@tonic-gate 	};
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	for (i = 0; i < datap->pd_envc; i++) {
4997c478bd9Sstevel@tonic-gate 		char *s = datap->pd_envp_strs[i];
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		if (s == NULL)
5027c478bd9Sstevel@tonic-gate 			continue;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 		if (strncmp("LC_ALL=", s, strlen("LC_ALL=")) == 0) {
5057c478bd9Sstevel@tonic-gate 			/*
5067c478bd9Sstevel@tonic-gate 			 * Minor optimization-- if we find LC_ALL we're done.
5077c478bd9Sstevel@tonic-gate 			 */
5087c478bd9Sstevel@tonic-gate 			lc_all = s + strlen("LC_ALL=");
5097c478bd9Sstevel@tonic-gate 			break;
5107c478bd9Sstevel@tonic-gate 		}
5117c478bd9Sstevel@tonic-gate 		for (j = 0; j <= _LastCategory; j++) {
5127c478bd9Sstevel@tonic-gate 			if (strncmp(cat_names[j], s,
5137c478bd9Sstevel@tonic-gate 			    strlen(cat_names[j])) == 0) {
5147c478bd9Sstevel@tonic-gate 				lcs[j] = s + strlen(cat_names[j]);
5157c478bd9Sstevel@tonic-gate 			}
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 		if (strncmp("LANG=", s, strlen("LANG=")) == 0) {
5187c478bd9Sstevel@tonic-gate 			lang = s + strlen("LANG=");
5197c478bd9Sstevel@tonic-gate 		}
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (lc_all && (*lc_all == '\0'))
5237c478bd9Sstevel@tonic-gate 		lc_all = NULL;
5247c478bd9Sstevel@tonic-gate 	if (lang && (*lang == '\0'))
5257c478bd9Sstevel@tonic-gate 		lang = NULL;
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	for (i = 0; i <= _LastCategory; i++) {
5287c478bd9Sstevel@tonic-gate 		if (lc_all != NULL) {
5297c478bd9Sstevel@tonic-gate 			lcs[i] = lc_all;
5307c478bd9Sstevel@tonic-gate 		} else if (lcs[i] != NULL) {
5317c478bd9Sstevel@tonic-gate 			lcs[i] = lcs[i];
5327c478bd9Sstevel@tonic-gate 		} else if (lang != NULL) {
5337c478bd9Sstevel@tonic-gate 			lcs[i] = lang;
5347c478bd9Sstevel@tonic-gate 		} else {
5357c478bd9Sstevel@tonic-gate 			lcs[i] = "C";
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 		if ((i > 0) && (lcs[i] != lcs[i-1]))
5387c478bd9Sstevel@tonic-gate 			composite++;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 		len += 1 + strlen(lcs[i]);	/* 1 extra byte for '/' */
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	if (composite == 0) {
5447c478bd9Sstevel@tonic-gate 		/* simple locale */
5457c478bd9Sstevel@tonic-gate 		pd_locale = safe_strdup(lcs[0]);
5467c478bd9Sstevel@tonic-gate 	} else {
5477c478bd9Sstevel@tonic-gate 		/* composite locale */
5487c478bd9Sstevel@tonic-gate 		pd_locale = safe_zalloc(len + 1);
5497c478bd9Sstevel@tonic-gate 		(void) snprintf(pd_locale, len + 1, "/%s/%s/%s/%s/%s/%s",
5507c478bd9Sstevel@tonic-gate 		    lcs[0], lcs[1], lcs[2], lcs[3], lcs[4], lcs[5]);
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 	datap->pd_locale = pd_locale;
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate  * Pull a string from the victim, regardless of size; this routine allocates
5577c478bd9Sstevel@tonic-gate  * memory for the string which must be freed by the caller.
5587c478bd9Sstevel@tonic-gate  */
5597c478bd9Sstevel@tonic-gate static char *
extract_string(pargs_data_t * datap,uintptr_t addr)5607c478bd9Sstevel@tonic-gate extract_string(pargs_data_t *datap, uintptr_t addr)
5617c478bd9Sstevel@tonic-gate {
5627c478bd9Sstevel@tonic-gate 	int size = EXTRACT_BUFSZ;
5637c478bd9Sstevel@tonic-gate 	char *result;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	result = safe_zalloc(size);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	for (;;) {
5687c478bd9Sstevel@tonic-gate 		if (Pread_string(datap->pd_proc, result, size, addr) < 0) {
5697c478bd9Sstevel@tonic-gate 			free(result);
5707c478bd9Sstevel@tonic-gate 			return (NULL);
5717c478bd9Sstevel@tonic-gate 		} else if (strlen(result) == (size - 1)) {
5727c478bd9Sstevel@tonic-gate 			free(result);
5737c478bd9Sstevel@tonic-gate 			size *= 2;
5747c478bd9Sstevel@tonic-gate 			result = safe_zalloc(size);
5757c478bd9Sstevel@tonic-gate 		} else {
5767c478bd9Sstevel@tonic-gate 			break;
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	return (result);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate  * Utility function to read an array of pointers from the victim, adjusting
5847c478bd9Sstevel@tonic-gate  * for victim data model; returns the number of bytes successfully read.
5857c478bd9Sstevel@tonic-gate  */
5867c478bd9Sstevel@tonic-gate static ssize_t
read_ptr_array(pargs_data_t * datap,uintptr_t offset,uintptr_t * buf,size_t nelems)5877c478bd9Sstevel@tonic-gate read_ptr_array(pargs_data_t *datap, uintptr_t offset, uintptr_t *buf,
5887c478bd9Sstevel@tonic-gate     size_t nelems)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	ssize_t res;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	if (dmodel == PR_MODEL_NATIVE) {
5937c478bd9Sstevel@tonic-gate 		res = Pread(datap->pd_proc, buf, nelems * sizeof (uintptr_t),
5947c478bd9Sstevel@tonic-gate 		    offset);
5957c478bd9Sstevel@tonic-gate 	} else {
5967c478bd9Sstevel@tonic-gate 		int i;
5977c478bd9Sstevel@tonic-gate 		uint32_t *arr32 = safe_zalloc(nelems * sizeof (uint32_t));
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		res = Pread(datap->pd_proc, arr32, nelems * sizeof (uint32_t),
6007c478bd9Sstevel@tonic-gate 		    offset);
6017c478bd9Sstevel@tonic-gate 		if (res > 0) {
6027c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++)
6037c478bd9Sstevel@tonic-gate 				buf[i] = arr32[i];
6047c478bd9Sstevel@tonic-gate 		}
6057c478bd9Sstevel@tonic-gate 		free(arr32);
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 	return (res);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate /*
6117c478bd9Sstevel@tonic-gate  * Extract the argv array from the victim; store the pointer values in
6127c478bd9Sstevel@tonic-gate  * datap->pd_argv and the extracted strings in datap->pd_argv_strs.
6137c478bd9Sstevel@tonic-gate  */
6147c478bd9Sstevel@tonic-gate static void
get_args(pargs_data_t * datap)6157c478bd9Sstevel@tonic-gate get_args(pargs_data_t *datap)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	size_t argc = datap->pd_psinfo->pr_argc;
6187c478bd9Sstevel@tonic-gate 	uintptr_t argvoff = datap->pd_psinfo->pr_argv;
6197c478bd9Sstevel@tonic-gate 	int i;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	datap->pd_argc = argc;
6227c478bd9Sstevel@tonic-gate 	datap->pd_argv = safe_zalloc(argc * sizeof (uintptr_t));
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (read_ptr_array(datap, argvoff, datap->pd_argv, argc) <= 0) {
6257c478bd9Sstevel@tonic-gate 		free(datap->pd_argv);
6267c478bd9Sstevel@tonic-gate 		datap->pd_argv = NULL;
627fbfe962eSRobert Mustacchi 		datap->pd_argc = 0;
6287c478bd9Sstevel@tonic-gate 		return;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	datap->pd_argv_strs = safe_zalloc(argc * sizeof (char *));
6327c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
6337c478bd9Sstevel@tonic-gate 		if (datap->pd_argv[i] == 0)
6347c478bd9Sstevel@tonic-gate 			continue;
6357c478bd9Sstevel@tonic-gate 		datap->pd_argv_strs[i] = extract_string(datap,
6367c478bd9Sstevel@tonic-gate 		    datap->pd_argv[i]);
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6417c478bd9Sstevel@tonic-gate static int
build_env(void * data,struct ps_prochandle * pr,uintptr_t addr,const char * str)6427c478bd9Sstevel@tonic-gate build_env(void *data, struct ps_prochandle *pr, uintptr_t addr, const char *str)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	pargs_data_t *datap = data;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if (datap->pd_envp != NULL) {
647b0801aa3SMarcel Telka 		if (datap->pd_envc == datap->pd_env_space) {
648b0801aa3SMarcel Telka 			/*
649b0801aa3SMarcel Telka 			 * Not enough space for storing the env (it has more
650b0801aa3SMarcel Telka 			 * items than before).  Try to grow both arrays.
651b0801aa3SMarcel Telka 			 */
652b0801aa3SMarcel Telka 			void *new = realloc(datap->pd_envp,
653b0801aa3SMarcel Telka 			    sizeof (uintptr_t) * datap->pd_env_space * 2);
654b0801aa3SMarcel Telka 			if (new == NULL)
655b0801aa3SMarcel Telka 				return (1);
656b0801aa3SMarcel Telka 			datap->pd_envp = new;
657b0801aa3SMarcel Telka 
658b0801aa3SMarcel Telka 			new = realloc(datap->pd_envp_strs,
659b0801aa3SMarcel Telka 			    sizeof (char *) * datap->pd_env_space * 2);
660b0801aa3SMarcel Telka 			if (new == NULL)
661b0801aa3SMarcel Telka 				return (1);
662b0801aa3SMarcel Telka 			datap->pd_envp_strs = new;
663b0801aa3SMarcel Telka 
664b0801aa3SMarcel Telka 			datap->pd_env_space *= 2;
665b0801aa3SMarcel Telka 		}
66623a268cfSSimon Klinkert 
6677c478bd9Sstevel@tonic-gate 		datap->pd_envp[datap->pd_envc] = addr;
6687c478bd9Sstevel@tonic-gate 		if (str == NULL)
6697c478bd9Sstevel@tonic-gate 			datap->pd_envp_strs[datap->pd_envc] = NULL;
6707c478bd9Sstevel@tonic-gate 		else
6717c478bd9Sstevel@tonic-gate 			datap->pd_envp_strs[datap->pd_envc] = strdup(str);
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	datap->pd_envc++;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	return (0);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate static void
get_env(pargs_data_t * datap)6807c478bd9Sstevel@tonic-gate get_env(pargs_data_t *datap)
6817c478bd9Sstevel@tonic-gate {
6827c478bd9Sstevel@tonic-gate 	struct ps_prochandle *pr = datap->pd_proc;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	datap->pd_envc = 0;
6857c478bd9Sstevel@tonic-gate 	(void) Penv_iter(pr, build_env, datap);
6867c478bd9Sstevel@tonic-gate 
687b0801aa3SMarcel Telka 	/* We must allocate space for at least one entry */
688b0801aa3SMarcel Telka 	datap->pd_env_space = datap->pd_envc != 0 ? datap->pd_envc : 1;
689b0801aa3SMarcel Telka 	datap->pd_envp = safe_zalloc(sizeof (uintptr_t) * datap->pd_env_space);
690b0801aa3SMarcel Telka 	datap->pd_envp_strs =
691b0801aa3SMarcel Telka 	    safe_zalloc(sizeof (char *) * datap->pd_env_space);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	datap->pd_envc = 0;
6947c478bd9Sstevel@tonic-gate 	(void) Penv_iter(pr, build_env, datap);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate  * The following at_* routines are used to decode data from the aux vector.
6997c478bd9Sstevel@tonic-gate  */
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7027c478bd9Sstevel@tonic-gate static void
at_null(long val,char * instr,size_t n,char * str)7037c478bd9Sstevel@tonic-gate at_null(long val, char *instr, size_t n, char *str)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate 	str[0] = '\0';
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7097c478bd9Sstevel@tonic-gate static void
at_str(long val,char * instr,size_t n,char * str)7107c478bd9Sstevel@tonic-gate at_str(long val, char *instr, size_t n, char *str)
7117c478bd9Sstevel@tonic-gate {
7127c478bd9Sstevel@tonic-gate 	str[0] = '\0';
7137c478bd9Sstevel@tonic-gate 	if (instr != NULL) {
7147c478bd9Sstevel@tonic-gate 		(void) strlcpy(str, instr, n);
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate /*
7197c478bd9Sstevel@tonic-gate  * Note: Don't forget to add a corresponding case to isainfo(1).
7207c478bd9Sstevel@tonic-gate  */
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate #define	FMT_AV(s, n, hwcap, mask, name)				\
7237c478bd9Sstevel@tonic-gate 	if ((hwcap) & (mask))					\
7247c478bd9Sstevel@tonic-gate 		(void) snprintf(s, n, "%s" name " | ", s)
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7277c478bd9Sstevel@tonic-gate static void
at_hwcap(long val,char * instr,size_t n,char * str)7287c478bd9Sstevel@tonic-gate at_hwcap(long val, char *instr, size_t n, char *str)
7297c478bd9Sstevel@tonic-gate {
7307c478bd9Sstevel@tonic-gate #if defined(__sparc) || defined(__sparcv9)
73199f63845Sab196087 	(void) elfcap_hw1_to_str(ELFCAP_STYLE_UC, val, str, n,
73299f63845Sab196087 	    ELFCAP_FMT_PIPSPACE, EM_SPARC);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64)
73599f63845Sab196087 	(void) elfcap_hw1_to_str(ELFCAP_STYLE_UC, val, str, n,
73699f63845Sab196087 	    ELFCAP_FMT_PIPSPACE, EM_386);
7377c478bd9Sstevel@tonic-gate #else
7387c478bd9Sstevel@tonic-gate #error	"port me"
7397c478bd9Sstevel@tonic-gate #endif
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7437c478bd9Sstevel@tonic-gate static void
at_hwcap2(long val,char * instr,size_t n,char * str)744ebb8ac07SRobert Mustacchi at_hwcap2(long val, char *instr, size_t n, char *str)
745ebb8ac07SRobert Mustacchi {
746ebb8ac07SRobert Mustacchi #if defined(__sparc) || defined(__sparcv9)
747ebb8ac07SRobert Mustacchi 	(void) elfcap_hw2_to_str(ELFCAP_STYLE_UC, val, str, n,
748ebb8ac07SRobert Mustacchi 	    ELFCAP_FMT_PIPSPACE, EM_SPARC);
749ebb8ac07SRobert Mustacchi 
750ebb8ac07SRobert Mustacchi #elif defined(__i386) || defined(__amd64)
751ebb8ac07SRobert Mustacchi 	(void) elfcap_hw2_to_str(ELFCAP_STYLE_UC, val, str, n,
752ebb8ac07SRobert Mustacchi 	    ELFCAP_FMT_PIPSPACE, EM_386);
753ebb8ac07SRobert Mustacchi #else
754ebb8ac07SRobert Mustacchi #error	"port me"
755ebb8ac07SRobert Mustacchi #endif
756ebb8ac07SRobert Mustacchi }
757ebb8ac07SRobert Mustacchi 
758*56726c7eSRobert Mustacchi /*ARGSUSED*/
759*56726c7eSRobert Mustacchi static void
at_hwcap3(long val,char * instr,size_t n,char * str)760*56726c7eSRobert Mustacchi at_hwcap3(long val, char *instr, size_t n, char *str)
761*56726c7eSRobert Mustacchi {
762*56726c7eSRobert Mustacchi #if defined(__i386) || defined(__amd64)
763*56726c7eSRobert Mustacchi 	(void) elfcap_hw3_to_str(ELFCAP_STYLE_UC, val, str, n,
764*56726c7eSRobert Mustacchi 	    ELFCAP_FMT_PIPSPACE, EM_386);
765*56726c7eSRobert Mustacchi #else
766*56726c7eSRobert Mustacchi #error	"port me"
767*56726c7eSRobert Mustacchi #endif
768*56726c7eSRobert Mustacchi }
769ebb8ac07SRobert Mustacchi 
770ebb8ac07SRobert Mustacchi /*ARGSUSED*/
771ebb8ac07SRobert Mustacchi static void
at_uid(long val,char * instr,size_t n,char * str)7727c478bd9Sstevel@tonic-gate at_uid(long val, char *instr, size_t n, char *str)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate 	struct passwd *pw = getpwuid((uid_t)val);
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	if ((pw == NULL) || (pw->pw_name == NULL))
7777c478bd9Sstevel@tonic-gate 		str[0] = '\0';
7787c478bd9Sstevel@tonic-gate 	else
7797c478bd9Sstevel@tonic-gate 		(void) snprintf(str, n, "%lu(%s)", val, pw->pw_name);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7847c478bd9Sstevel@tonic-gate static void
at_gid(long val,char * instr,size_t n,char * str)7857c478bd9Sstevel@tonic-gate at_gid(long val, char *instr, size_t n, char *str)
7867c478bd9Sstevel@tonic-gate {
7877c478bd9Sstevel@tonic-gate 	struct group *gr = getgrgid((gid_t)val);
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	if ((gr == NULL) || (gr->gr_name == NULL))
7907c478bd9Sstevel@tonic-gate 		str[0] = '\0';
7917c478bd9Sstevel@tonic-gate 	else
7927c478bd9Sstevel@tonic-gate 		(void) snprintf(str, n, "%lu(%s)", val, gr->gr_name);
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate static struct auxfl {
7967c478bd9Sstevel@tonic-gate 	int af_flag;
7977c478bd9Sstevel@tonic-gate 	const char *af_name;
7987c478bd9Sstevel@tonic-gate } auxfl[] = {
7997c478bd9Sstevel@tonic-gate 	{ AF_SUN_SETUGID,	"setugid" },
8007c478bd9Sstevel@tonic-gate };
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8037c478bd9Sstevel@tonic-gate static void
at_flags(long val,char * instr,size_t n,char * str)8047c478bd9Sstevel@tonic-gate at_flags(long val, char *instr, size_t n, char *str)
8057c478bd9Sstevel@tonic-gate {
8067c478bd9Sstevel@tonic-gate 	int i;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	*str = '\0';
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (auxfl)/sizeof (struct auxfl); i++) {
8117c478bd9Sstevel@tonic-gate 		if ((val & auxfl[i].af_flag) != 0) {
8127c478bd9Sstevel@tonic-gate 			if (*str != '\0')
8137c478bd9Sstevel@tonic-gate 				(void) strlcat(str, ",", n);
8147c478bd9Sstevel@tonic-gate 			(void) strlcat(str, auxfl[i].af_name, n);
8157c478bd9Sstevel@tonic-gate 		}
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate #define	MAX_AT_NAME_LEN	15
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate struct aux_id {
8227c478bd9Sstevel@tonic-gate 	int aux_type;
8237c478bd9Sstevel@tonic-gate 	const char *aux_name;
8247c478bd9Sstevel@tonic-gate 	void (*aux_decode)(long, char *, size_t, char *);
8257c478bd9Sstevel@tonic-gate };
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate static struct aux_id aux_arr[] = {
8287c478bd9Sstevel@tonic-gate 	{ AT_NULL,		"AT_NULL",		at_null	},
8297c478bd9Sstevel@tonic-gate 	{ AT_IGNORE,		"AT_IGNORE",		at_null	},
8307c478bd9Sstevel@tonic-gate 	{ AT_EXECFD,		"AT_EXECFD",		at_null	},
8317c478bd9Sstevel@tonic-gate 	{ AT_PHDR,		"AT_PHDR",		at_null	},
8327c478bd9Sstevel@tonic-gate 	{ AT_PHENT,		"AT_PHENT",		at_null	},
8337c478bd9Sstevel@tonic-gate 	{ AT_PHNUM,		"AT_PHNUM",		at_null	},
8347c478bd9Sstevel@tonic-gate 	{ AT_PAGESZ,		"AT_PAGESZ",		at_null	},
8357c478bd9Sstevel@tonic-gate 	{ AT_BASE,		"AT_BASE",		at_null	},
8367c478bd9Sstevel@tonic-gate 	{ AT_FLAGS,		"AT_FLAGS",		at_null	},
8377c478bd9Sstevel@tonic-gate 	{ AT_ENTRY,		"AT_ENTRY",		at_null	},
8387c478bd9Sstevel@tonic-gate 	{ AT_SUN_UID,		"AT_SUN_UID",		at_uid	},
8397c478bd9Sstevel@tonic-gate 	{ AT_SUN_RUID,		"AT_SUN_RUID",		at_uid	},
8407c478bd9Sstevel@tonic-gate 	{ AT_SUN_GID,		"AT_SUN_GID",		at_gid	},
8417c478bd9Sstevel@tonic-gate 	{ AT_SUN_RGID,		"AT_SUN_RGID",		at_gid	},
8427c478bd9Sstevel@tonic-gate 	{ AT_SUN_LDELF,		"AT_SUN_LDELF",		at_null	},
8437c478bd9Sstevel@tonic-gate 	{ AT_SUN_LDSHDR,	"AT_SUN_LDSHDR",	at_null	},
8447c478bd9Sstevel@tonic-gate 	{ AT_SUN_LDNAME,	"AT_SUN_LDNAME",	at_null	},
8457c478bd9Sstevel@tonic-gate 	{ AT_SUN_LPAGESZ,	"AT_SUN_LPAGESZ",	at_null	},
8467c478bd9Sstevel@tonic-gate 	{ AT_SUN_PLATFORM,	"AT_SUN_PLATFORM",	at_str	},
8477c478bd9Sstevel@tonic-gate 	{ AT_SUN_EXECNAME,	"AT_SUN_EXECNAME",	at_str	},
8487c478bd9Sstevel@tonic-gate 	{ AT_SUN_HWCAP,		"AT_SUN_HWCAP",		at_hwcap },
849ebb8ac07SRobert Mustacchi 	{ AT_SUN_HWCAP2,	"AT_SUN_HWCAP2",	at_hwcap2 },
850*56726c7eSRobert Mustacchi 	{ AT_SUN_HWCAP3,	"AT_SUN_HWCAP3",	at_hwcap3 },
8517c478bd9Sstevel@tonic-gate 	{ AT_SUN_IFLUSH,	"AT_SUN_IFLUSH",	at_null	},
8527c478bd9Sstevel@tonic-gate 	{ AT_SUN_CPU,		"AT_SUN_CPU",		at_null	},
8537c478bd9Sstevel@tonic-gate 	{ AT_SUN_MMU,		"AT_SUN_MMU",		at_null	},
8547c478bd9Sstevel@tonic-gate 	{ AT_SUN_LDDATA,	"AT_SUN_LDDATA",	at_null	},
8557c478bd9Sstevel@tonic-gate 	{ AT_SUN_AUXFLAGS,	"AT_SUN_AUXFLAGS",	at_flags },
8569acbbeafSnn35248 	{ AT_SUN_EMULATOR,	"AT_SUN_EMULATOR",	at_str	},
8579acbbeafSnn35248 	{ AT_SUN_BRANDNAME,	"AT_SUN_BRANDNAME",	at_str	},
85807678296Ssl108498 	{ AT_SUN_BRAND_AUX1,	"AT_SUN_BRAND_AUX1",	at_null	},
85907678296Ssl108498 	{ AT_SUN_BRAND_AUX2,	"AT_SUN_BRAND_AUX2",	at_null	},
8602428aad8SPatrick Mooney 	{ AT_SUN_BRAND_AUX3,	"AT_SUN_BRAND_AUX3",	at_null	},
861d0158222SRobert Mustacchi 	{ AT_SUN_COMMPAGE,	"AT_SUN_COMMPAGE",	at_null	},
862d0158222SRobert Mustacchi 	{ AT_SUN_FPTYPE,	"AT_SUN_FPTYPE",	at_null },
863d0158222SRobert Mustacchi 	{ AT_SUN_FPSIZE,	"AT_SUN_FPSIZE",	at_null }
8647c478bd9Sstevel@tonic-gate };
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate #define	N_AT_ENTS (sizeof (aux_arr) / sizeof (struct aux_id))
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate /*
8697c478bd9Sstevel@tonic-gate  * Return the aux_id entry for the given aux type; returns NULL if not found.
8707c478bd9Sstevel@tonic-gate  */
8717c478bd9Sstevel@tonic-gate static struct aux_id *
aux_find(int type)8727c478bd9Sstevel@tonic-gate aux_find(int type)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate 	int i;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_AT_ENTS; i++) {
8777c478bd9Sstevel@tonic-gate 		if (type == aux_arr[i].aux_type)
8787c478bd9Sstevel@tonic-gate 			return (&aux_arr[i]);
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	return (NULL);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate static void
get_auxv(pargs_data_t * datap)8857c478bd9Sstevel@tonic-gate get_auxv(pargs_data_t *datap)
8867c478bd9Sstevel@tonic-gate {
8877c478bd9Sstevel@tonic-gate 	int i;
8887c478bd9Sstevel@tonic-gate 	const auxv_t *auxvp;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	/*
8917c478bd9Sstevel@tonic-gate 	 * Fetch the aux vector from the target process.
8927c478bd9Sstevel@tonic-gate 	 */
8937c478bd9Sstevel@tonic-gate 	if (ps_pauxv(datap->pd_proc, &auxvp) != PS_OK)
8947c478bd9Sstevel@tonic-gate 		return;
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	for (i = 0; auxvp[i].a_type != AT_NULL; i++)
8977c478bd9Sstevel@tonic-gate 		continue;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	datap->pd_auxc = i;
9007c478bd9Sstevel@tonic-gate 	datap->pd_auxv = safe_zalloc(i * sizeof (auxv_t));
9017c478bd9Sstevel@tonic-gate 	bcopy(auxvp, datap->pd_auxv, i * sizeof (auxv_t));
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	datap->pd_auxv_strs = safe_zalloc(datap->pd_auxc * sizeof (char *));
9047c478bd9Sstevel@tonic-gate 	for (i = 0; i < datap->pd_auxc; i++) {
9057c478bd9Sstevel@tonic-gate 		struct aux_id *aux = aux_find(datap->pd_auxv[i].a_type);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		/*
9087c478bd9Sstevel@tonic-gate 		 * Grab strings for those entries which have a string-decoder.
9097c478bd9Sstevel@tonic-gate 		 */
9107c478bd9Sstevel@tonic-gate 		if ((aux != NULL) && (aux->aux_decode == at_str)) {
9117c478bd9Sstevel@tonic-gate 			datap->pd_auxv_strs[i] =
9127c478bd9Sstevel@tonic-gate 			    extract_string(datap, datap->pd_auxv[i].a_un.a_val);
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate /*
9187c478bd9Sstevel@tonic-gate  * Prepare to convert characters in the victim's character set into user's
9197c478bd9Sstevel@tonic-gate  * character set.
9207c478bd9Sstevel@tonic-gate  */
9217c478bd9Sstevel@tonic-gate static void
setup_conversions(pargs_data_t * datap,int * diflocale)9227c478bd9Sstevel@tonic-gate setup_conversions(pargs_data_t *datap, int *diflocale)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	char *mylocale = NULL, *mycharset = NULL;
9257c478bd9Sstevel@tonic-gate 	char *targetlocale = NULL, *targetcharset = NULL;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	mycharset = safe_strdup(nl_langinfo(CODESET));
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	mylocale = setlocale(LC_CTYPE, NULL);
9307c478bd9Sstevel@tonic-gate 	if ((mylocale == NULL) || (strcmp(mylocale, "") == 0))
9317c478bd9Sstevel@tonic-gate 		mylocale = "C";
9327c478bd9Sstevel@tonic-gate 	mylocale = safe_strdup(mylocale);
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	if (datap->pd_conv_flags & CONV_STRICT_ASCII)
9357c478bd9Sstevel@tonic-gate 		goto done;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	/*
9387c478bd9Sstevel@tonic-gate 	 * If the target's locale is "C" or "POSIX", go fast.
9397c478bd9Sstevel@tonic-gate 	 */
9407c478bd9Sstevel@tonic-gate 	if ((strcmp(datap->pd_locale, "C") == 0) ||
9417c478bd9Sstevel@tonic-gate 	    (strcmp(datap->pd_locale, "POSIX") == 0)) {
9427c478bd9Sstevel@tonic-gate 		datap->pd_conv_flags |= CONV_STRICT_ASCII;
9437c478bd9Sstevel@tonic-gate 		goto done;
9447c478bd9Sstevel@tonic-gate 	}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	/*
9477c478bd9Sstevel@tonic-gate 	 * Switch to the victim's locale, and discover its character set.
9487c478bd9Sstevel@tonic-gate 	 */
9497c478bd9Sstevel@tonic-gate 	if (setlocale(LC_ALL, datap->pd_locale) == NULL) {
9507c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
9517c478bd9Sstevel@tonic-gate 		    "%s: Couldn't determine locale of target process.\n",
9527c478bd9Sstevel@tonic-gate 		    command);
9537c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
9547c478bd9Sstevel@tonic-gate 		    "%s: Some strings may not be displayed properly.\n",
9557c478bd9Sstevel@tonic-gate 		    command);
9567c478bd9Sstevel@tonic-gate 		goto done;
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	/*
9607c478bd9Sstevel@tonic-gate 	 * Get LC_CTYPE part of target's locale, and its codeset.
9617c478bd9Sstevel@tonic-gate 	 */
9627c478bd9Sstevel@tonic-gate 	targetlocale = safe_strdup(setlocale(LC_CTYPE, NULL));
9637c478bd9Sstevel@tonic-gate 	targetcharset = safe_strdup(nl_langinfo(CODESET));
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	/*
9667c478bd9Sstevel@tonic-gate 	 * Now go fully back to the pargs user's locale.
9677c478bd9Sstevel@tonic-gate 	 */
9687c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	/*
9717c478bd9Sstevel@tonic-gate 	 * It's safe to bail here if the lc_ctype of the locales are the
9727c478bd9Sstevel@tonic-gate 	 * same-- we know that their encodings and characters sets are the same.
9737c478bd9Sstevel@tonic-gate 	 */
9747c478bd9Sstevel@tonic-gate 	if (strcmp(targetlocale, mylocale) == 0)
9757c478bd9Sstevel@tonic-gate 		goto done;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	*diflocale = 1;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * If the codeset of the victim matches our codeset then iconv need
9817c478bd9Sstevel@tonic-gate 	 * not be involved.
9827c478bd9Sstevel@tonic-gate 	 */
9837c478bd9Sstevel@tonic-gate 	if (strcmp(mycharset, targetcharset) == 0)
9847c478bd9Sstevel@tonic-gate 		goto done;
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if ((datap->pd_iconv = iconv_open(mycharset, targetcharset))
9877c478bd9Sstevel@tonic-gate 	    == (iconv_t)-1) {
9887c478bd9Sstevel@tonic-gate 		/*
9897c478bd9Sstevel@tonic-gate 		 * EINVAL indicates there was no conversion available
9907c478bd9Sstevel@tonic-gate 		 * from victim charset to mycharset
9917c478bd9Sstevel@tonic-gate 		 */
9927c478bd9Sstevel@tonic-gate 		if (errno != EINVAL) {
9937c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
9947c478bd9Sstevel@tonic-gate 			    "%s: failed to initialize iconv: %s\n",
9957c478bd9Sstevel@tonic-gate 			    command, strerror(errno));
9967c478bd9Sstevel@tonic-gate 			exit(1);
9977c478bd9Sstevel@tonic-gate 		}
9987c478bd9Sstevel@tonic-gate 		datap->pd_conv_flags |= CONV_STRICT_ASCII;
9997c478bd9Sstevel@tonic-gate 	} else {
10007c478bd9Sstevel@tonic-gate 		datap->pd_conv_flags |= CONV_USE_ICONV;
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate done:
10037c478bd9Sstevel@tonic-gate 	free(mycharset);
10047c478bd9Sstevel@tonic-gate 	free(mylocale);
10057c478bd9Sstevel@tonic-gate 	free(targetcharset);
10067c478bd9Sstevel@tonic-gate 	free(targetlocale);
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate static void
cleanup_conversions(pargs_data_t * datap)10107c478bd9Sstevel@tonic-gate cleanup_conversions(pargs_data_t *datap)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	if (datap->pd_conv_flags & CONV_USE_ICONV) {
10137c478bd9Sstevel@tonic-gate 		(void) iconv_close(datap->pd_iconv);
10147c478bd9Sstevel@tonic-gate 	}
10157c478bd9Sstevel@tonic-gate }
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate static char *
convert_run_iconv(pargs_data_t * datap,const char * str)10187c478bd9Sstevel@tonic-gate convert_run_iconv(pargs_data_t *datap, const char *str)
10197c478bd9Sstevel@tonic-gate {
10207c478bd9Sstevel@tonic-gate 	size_t inleft, outleft, bufsz = 64;
10217c478bd9Sstevel@tonic-gate 	char *outstr, *outstrptr;
10227c478bd9Sstevel@tonic-gate 	const char *instrptr;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	for (;;) {
10257c478bd9Sstevel@tonic-gate 		outstrptr = outstr = safe_zalloc(bufsz + 1);
10267c478bd9Sstevel@tonic-gate 		outleft = bufsz;
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 		/*
10297c478bd9Sstevel@tonic-gate 		 * Generate the "initial shift state" sequence, placing that
10307c478bd9Sstevel@tonic-gate 		 * at the head of the string.
10317c478bd9Sstevel@tonic-gate 		 */
10327c478bd9Sstevel@tonic-gate 		inleft = 0;
10337c478bd9Sstevel@tonic-gate 		(void) iconv(datap->pd_iconv, NULL, &inleft,
10347c478bd9Sstevel@tonic-gate 		    &outstrptr, &outleft);
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 		inleft = strlen(str);
10377c478bd9Sstevel@tonic-gate 		instrptr = str;
10387c478bd9Sstevel@tonic-gate 		if (iconv(datap->pd_iconv, &instrptr, &inleft, &outstrptr,
10397c478bd9Sstevel@tonic-gate 		    &outleft) != (size_t)-1) {
10407c478bd9Sstevel@tonic-gate 			/*
10417c478bd9Sstevel@tonic-gate 			 * Outstr must be null terminated upon exit from
10427c478bd9Sstevel@tonic-gate 			 * iconv().
10437c478bd9Sstevel@tonic-gate 			 */
10447c478bd9Sstevel@tonic-gate 			*(outstr + (bufsz - outleft)) = '\0';
10457c478bd9Sstevel@tonic-gate 			break;
10467c478bd9Sstevel@tonic-gate 		} else if (errno == E2BIG) {
10477c478bd9Sstevel@tonic-gate 			bufsz *= 2;
10487c478bd9Sstevel@tonic-gate 			free(outstr);
10497c478bd9Sstevel@tonic-gate 		} else if ((errno == EILSEQ) || (errno == EINVAL)) {
10507c478bd9Sstevel@tonic-gate 			free(outstr);
10517c478bd9Sstevel@tonic-gate 			return (NULL);
10527c478bd9Sstevel@tonic-gate 		} else {
10537c478bd9Sstevel@tonic-gate 			/*
10547c478bd9Sstevel@tonic-gate 			 * iconv() could in theory return EBADF, but that
10557c478bd9Sstevel@tonic-gate 			 * shouldn't happen.
10567c478bd9Sstevel@tonic-gate 			 */
10577c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
10587c478bd9Sstevel@tonic-gate 			    "%s: iconv(3C) failed unexpectedly: %s\n",
10597c478bd9Sstevel@tonic-gate 			    command, strerror(errno));
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 			exit(1);
10627c478bd9Sstevel@tonic-gate 		}
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 	return (outstr);
10657c478bd9Sstevel@tonic-gate }
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate /*
10687c478bd9Sstevel@tonic-gate  * Returns a freshly allocated string converted to the local character set,
10697c478bd9Sstevel@tonic-gate  * removed of unprintable characters.
10707c478bd9Sstevel@tonic-gate  */
10717c478bd9Sstevel@tonic-gate static char *
convert_str(pargs_data_t * datap,const char * str,int * unprintable)10727c478bd9Sstevel@tonic-gate convert_str(pargs_data_t *datap, const char *str, int *unprintable)
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate 	char *retstr, *tmp;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	if (datap->pd_conv_flags & CONV_STRICT_ASCII) {
10777c478bd9Sstevel@tonic-gate 		retstr = unctrl_str_strict_ascii(str, 1, unprintable);
10787c478bd9Sstevel@tonic-gate 		return (retstr);
10797c478bd9Sstevel@tonic-gate 	}
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	if ((datap->pd_conv_flags & CONV_USE_ICONV) == 0) {
10827c478bd9Sstevel@tonic-gate 		/*
10837c478bd9Sstevel@tonic-gate 		 * If we aren't using iconv(), convert control chars in
10847c478bd9Sstevel@tonic-gate 		 * the string in pargs' locale, since that is the display
10857c478bd9Sstevel@tonic-gate 		 * locale.
10867c478bd9Sstevel@tonic-gate 		 */
10877c478bd9Sstevel@tonic-gate 		retstr = unctrl_str(str, 1, unprintable);
10887c478bd9Sstevel@tonic-gate 		return (retstr);
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	/*
10927c478bd9Sstevel@tonic-gate 	 * The logic here is a bit (ahem) tricky.  Start by converting
10937c478bd9Sstevel@tonic-gate 	 * unprintable characters *in the target's locale*.  This should
10947c478bd9Sstevel@tonic-gate 	 * eliminate a variety of unprintable or illegal characters-- in
10957c478bd9Sstevel@tonic-gate 	 * short, it should leave us with something which iconv() won't
10967c478bd9Sstevel@tonic-gate 	 * have trouble with.
10977c478bd9Sstevel@tonic-gate 	 *
10987c478bd9Sstevel@tonic-gate 	 * After allowing iconv to convert characters as needed, run unctrl
10997c478bd9Sstevel@tonic-gate 	 * again in pargs' locale-- This time to make sure that any
11007c478bd9Sstevel@tonic-gate 	 * characters which aren't printable according to the *current*
11017c478bd9Sstevel@tonic-gate 	 * locale (independent of the current codeset) get taken care of.
11027c478bd9Sstevel@tonic-gate 	 * Without this second stage, we might (for example) fail to
11037c478bd9Sstevel@tonic-gate 	 * properly handle characters converted into the 646 character set
11047c478bd9Sstevel@tonic-gate 	 * (which are 8-bits wide), but which must be displayed in the C
11057c478bd9Sstevel@tonic-gate 	 * locale (which uses 646, but whose printable characters are a
11067c478bd9Sstevel@tonic-gate 	 * subset of the 7-bit characters).
11077c478bd9Sstevel@tonic-gate 	 *
11087c478bd9Sstevel@tonic-gate 	 * Note that assuming the victim's locale using LC_ALL will be
11097c478bd9Sstevel@tonic-gate 	 * problematic when pargs' messages are internationalized in the
11107c478bd9Sstevel@tonic-gate 	 * future (and it calls textdomain(3C)).  In this case, any
11117c478bd9Sstevel@tonic-gate 	 * error message fprintf'd in unctrl_str() will be in the wrong
11127c478bd9Sstevel@tonic-gate 	 * LC_MESSAGES class.  We'll cross that bridge when we come to it.
11137c478bd9Sstevel@tonic-gate 	 */
11147c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, datap->pd_locale);
11157c478bd9Sstevel@tonic-gate 	retstr = unctrl_str(str, 1, unprintable);
11167c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	tmp = retstr;
11197c478bd9Sstevel@tonic-gate 	if ((retstr = convert_run_iconv(datap, retstr)) == NULL) {
11207c478bd9Sstevel@tonic-gate 		/*
11217c478bd9Sstevel@tonic-gate 		 * In this (rare but real) case, the iconv() failed even
11227c478bd9Sstevel@tonic-gate 		 * though we unctrl'd the string.  Treat the original string
11237c478bd9Sstevel@tonic-gate 		 * (str) as a C locale string and strip it that way.
11247c478bd9Sstevel@tonic-gate 		 */
11257c478bd9Sstevel@tonic-gate 		free(tmp);
11267c478bd9Sstevel@tonic-gate 		return (unctrl_str_strict_ascii(str, 0, unprintable));
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	free(tmp);
11307c478bd9Sstevel@tonic-gate 	tmp = retstr;
11317c478bd9Sstevel@tonic-gate 	/*
11327c478bd9Sstevel@tonic-gate 	 * Run unctrl_str, but make sure not to escape \ characters, which
11337c478bd9Sstevel@tonic-gate 	 * may have resulted from the first round of unctrl.
11347c478bd9Sstevel@tonic-gate 	 */
11357c478bd9Sstevel@tonic-gate 	retstr = unctrl_str(retstr, 0, unprintable);
11367c478bd9Sstevel@tonic-gate 	free(tmp);
11377c478bd9Sstevel@tonic-gate 	return (retstr);
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate static void
convert_array(pargs_data_t * datap,char ** arr,size_t count,int * unprintable)11427c478bd9Sstevel@tonic-gate convert_array(pargs_data_t *datap, char **arr, size_t count, int *unprintable)
11437c478bd9Sstevel@tonic-gate {
11447c478bd9Sstevel@tonic-gate 	int i;
11457c478bd9Sstevel@tonic-gate 	char *tmp;
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	if (arr == NULL)
11487c478bd9Sstevel@tonic-gate 		return;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
11517c478bd9Sstevel@tonic-gate 		if ((tmp = arr[i]) == NULL)
11527c478bd9Sstevel@tonic-gate 			continue;
11537c478bd9Sstevel@tonic-gate 		arr[i] = convert_str(datap, arr[i], unprintable);
11547c478bd9Sstevel@tonic-gate 		free(tmp);
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate /*
11597c478bd9Sstevel@tonic-gate  * Free data allocated during the gathering phase.
11607c478bd9Sstevel@tonic-gate  */
11617c478bd9Sstevel@tonic-gate static void
free_data(pargs_data_t * datap)11627c478bd9Sstevel@tonic-gate free_data(pargs_data_t *datap)
11637c478bd9Sstevel@tonic-gate {
11647c478bd9Sstevel@tonic-gate 	int i;
11657c478bd9Sstevel@tonic-gate 
1166b0801aa3SMarcel Telka 	for (i = 0; i < datap->pd_argc; i++)
11677c478bd9Sstevel@tonic-gate 		free(datap->pd_argv_strs[i]);
11687c478bd9Sstevel@tonic-gate 	free(datap->pd_argv);
11697c478bd9Sstevel@tonic-gate 	free(datap->pd_argv_strs);
11707c478bd9Sstevel@tonic-gate 
1171b0801aa3SMarcel Telka 	for (i = 0; i < datap->pd_envc; i++)
11727c478bd9Sstevel@tonic-gate 		free(datap->pd_envp_strs[i]);
11737c478bd9Sstevel@tonic-gate 	free(datap->pd_envp);
11747c478bd9Sstevel@tonic-gate 	free(datap->pd_envp_strs);
11757c478bd9Sstevel@tonic-gate 
1176b0801aa3SMarcel Telka 	for (i = 0; i < datap->pd_auxc; i++)
11777c478bd9Sstevel@tonic-gate 		free(datap->pd_auxv_strs[i]);
11787c478bd9Sstevel@tonic-gate 	free(datap->pd_auxv);
11797c478bd9Sstevel@tonic-gate 	free(datap->pd_auxv_strs);
11807c478bd9Sstevel@tonic-gate }
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate static void
print_args(pargs_data_t * datap)11837c478bd9Sstevel@tonic-gate print_args(pargs_data_t *datap)
11847c478bd9Sstevel@tonic-gate {
11857c478bd9Sstevel@tonic-gate 	int i;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	if (datap->pd_argv == NULL) {
11887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: failed to read argv[]\n", command);
11897c478bd9Sstevel@tonic-gate 		return;
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	for (i = 0; i < datap->pd_argc; i++) {
11937c478bd9Sstevel@tonic-gate 		(void) printf("argv[%d]: ", i);
119421b85b87SToomas Soome 		if (datap->pd_argv[i] == (uintptr_t)NULL) {
11957c478bd9Sstevel@tonic-gate 			(void) printf("<NULL>\n");
11967c478bd9Sstevel@tonic-gate 		} else if (datap->pd_argv_strs[i] == NULL) {
11977c478bd9Sstevel@tonic-gate 			(void) printf("<0x%0*lx>\n",
11987c478bd9Sstevel@tonic-gate 			    (dmodel == PR_MODEL_LP64)? 16 : 8,
11997c478bd9Sstevel@tonic-gate 			    (long)datap->pd_argv[i]);
12007c478bd9Sstevel@tonic-gate 		} else {
12017c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", datap->pd_argv_strs[i]);
12027c478bd9Sstevel@tonic-gate 		}
12037c478bd9Sstevel@tonic-gate 	}
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate static void
print_env(pargs_data_t * datap)12077c478bd9Sstevel@tonic-gate print_env(pargs_data_t *datap)
12087c478bd9Sstevel@tonic-gate {
12097c478bd9Sstevel@tonic-gate 	int i;
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	if (datap->pd_envp == NULL) {
12127c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: failed to read envp[]\n", command);
12137c478bd9Sstevel@tonic-gate 		return;
12147c478bd9Sstevel@tonic-gate 	}
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	for (i = 0; i < datap->pd_envc; i++) {
12177c478bd9Sstevel@tonic-gate 		(void) printf("envp[%d]: ", i);
12187c478bd9Sstevel@tonic-gate 		if (datap->pd_envp[i] == 0) {
12197c478bd9Sstevel@tonic-gate 			break;
12207c478bd9Sstevel@tonic-gate 		} else if (datap->pd_envp_strs[i] == NULL) {
12217c478bd9Sstevel@tonic-gate 			(void) printf("<0x%0*lx>\n",
12227c478bd9Sstevel@tonic-gate 			    (dmodel == PR_MODEL_LP64)? 16 : 8,
12237c478bd9Sstevel@tonic-gate 			    (long)datap->pd_envp[i]);
12247c478bd9Sstevel@tonic-gate 		} else {
12257c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", datap->pd_envp_strs[i]);
12267c478bd9Sstevel@tonic-gate 		}
12277c478bd9Sstevel@tonic-gate 	}
12287c478bd9Sstevel@tonic-gate }
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate static int
print_cmdline(pargs_data_t * datap)12317c478bd9Sstevel@tonic-gate print_cmdline(pargs_data_t *datap)
12327c478bd9Sstevel@tonic-gate {
12337c478bd9Sstevel@tonic-gate 	int i;
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	/*
12367c478bd9Sstevel@tonic-gate 	 * Go through and check to see if we have valid data.  If not, print
12377c478bd9Sstevel@tonic-gate 	 * an error message and bail.
12387c478bd9Sstevel@tonic-gate 	 */
12397c478bd9Sstevel@tonic-gate 	for (i = 0; i < datap->pd_argc; i++) {
124021b85b87SToomas Soome 		if (datap->pd_argv == NULL ||
124121b85b87SToomas Soome 		    datap->pd_argv[i] == (uintptr_t)NULL ||
12427c478bd9Sstevel@tonic-gate 		    datap->pd_argv_strs[i] == NULL) {
12437c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: target has corrupted "
12447c478bd9Sstevel@tonic-gate 			    "argument list\n", command);
12457c478bd9Sstevel@tonic-gate 			return (1);
12467c478bd9Sstevel@tonic-gate 		}
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 		datap->pd_argv_strs[i] =
12497c478bd9Sstevel@tonic-gate 		    quote_string(datap, datap->pd_argv_strs[i]);
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	if (datap->pd_execname == NULL) {
12537c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot determine name of "
12547c478bd9Sstevel@tonic-gate 		    "executable\n", command);
12557c478bd9Sstevel@tonic-gate 		return (1);
12567c478bd9Sstevel@tonic-gate 	}
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 	(void) printf("%s ", datap->pd_execname);
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	for (i = 1; i < datap->pd_argc; i++)
12617c478bd9Sstevel@tonic-gate 		(void) printf("%s ", datap->pd_argv_strs[i]);
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 	(void) printf("\n");
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	return (0);
12667c478bd9Sstevel@tonic-gate }
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate static void
print_auxv(pargs_data_t * datap)12697c478bd9Sstevel@tonic-gate print_auxv(pargs_data_t *datap)
12707c478bd9Sstevel@tonic-gate {
12717c478bd9Sstevel@tonic-gate 	int i;
12727c478bd9Sstevel@tonic-gate 	const auxv_t *pa;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	/*
12757c478bd9Sstevel@tonic-gate 	 * Print the names and values of all the aux vector entries.
12767c478bd9Sstevel@tonic-gate 	 */
12777c478bd9Sstevel@tonic-gate 	for (i = 0; i < datap->pd_auxc; i++) {
12787c478bd9Sstevel@tonic-gate 		char type[32];
12797c478bd9Sstevel@tonic-gate 		char decode[PATH_MAX];
12807c478bd9Sstevel@tonic-gate 		struct aux_id *aux;
12817c478bd9Sstevel@tonic-gate 		long v;
12827c478bd9Sstevel@tonic-gate 		pa = &datap->pd_auxv[i];
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 		aux = aux_find(pa->a_type);
12857c478bd9Sstevel@tonic-gate 		v = (long)pa->a_un.a_val;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 		if (aux != NULL) {
12887c478bd9Sstevel@tonic-gate 			/*
12897c478bd9Sstevel@tonic-gate 			 * Fetch aux vector type string and decoded
12907c478bd9Sstevel@tonic-gate 			 * representation of the value.
12917c478bd9Sstevel@tonic-gate 			 */
12927c478bd9Sstevel@tonic-gate 			(void) strlcpy(type, aux->aux_name, sizeof (type));
12937c478bd9Sstevel@tonic-gate 			aux->aux_decode(v, datap->pd_auxv_strs[i],
12947c478bd9Sstevel@tonic-gate 			    sizeof (decode), decode);
12957c478bd9Sstevel@tonic-gate 		} else {
12967c478bd9Sstevel@tonic-gate 			(void) snprintf(type, sizeof (type), "%d", pa->a_type);
12977c478bd9Sstevel@tonic-gate 			decode[0] = '\0';
12987c478bd9Sstevel@tonic-gate 		}
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 		(void) printf("%-*s 0x%0*lx %s\n", MAX_AT_NAME_LEN, type,
13017c478bd9Sstevel@tonic-gate 		    (dmodel == PR_MODEL_LP64)? 16 : 8, v, decode);
13027c478bd9Sstevel@tonic-gate 	}
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])13067c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
13077c478bd9Sstevel@tonic-gate {
13087c478bd9Sstevel@tonic-gate 	int aflag = 0, cflag = 0, eflag = 0, xflag = 0, lflag = 0;
13097c478bd9Sstevel@tonic-gate 	int errflg = 0, retc = 0;
13107c478bd9Sstevel@tonic-gate 	int opt;
13117c478bd9Sstevel@tonic-gate 	int error = 1;
13127c478bd9Sstevel@tonic-gate 	core_content_t content = 0;
1313ffec1fd1SRobert Mustacchi 	pargs_cmd_t cmd = PARGS_ARGV;
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
13167c478bd9Sstevel@tonic-gate 
1317ffec1fd1SRobert Mustacchi 	command = basename(argv[0]);
1318ffec1fd1SRobert Mustacchi 
1319ffec1fd1SRobert Mustacchi 	if (strcmp(command, "penv") == 0)
1320ffec1fd1SRobert Mustacchi 		cmd = PARGS_ENV;
1321ffec1fd1SRobert Mustacchi 	else if (strcmp(command, "pauxv") == 0)
1322ffec1fd1SRobert Mustacchi 		cmd = PARGS_AUXV;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "acelxF")) != EOF) {
13257c478bd9Sstevel@tonic-gate 		switch (opt) {
13267c478bd9Sstevel@tonic-gate 		case 'a':		/* show process arguments */
13277c478bd9Sstevel@tonic-gate 			content |= CC_CONTENT_STACK;
13287c478bd9Sstevel@tonic-gate 			aflag++;
1329ffec1fd1SRobert Mustacchi 			if (cmd != PARGS_ARGV)
1330ffec1fd1SRobert Mustacchi 				errflg++;
13317c478bd9Sstevel@tonic-gate 			break;
13327c478bd9Sstevel@tonic-gate 		case 'c':		/* force 7-bit ascii */
13337c478bd9Sstevel@tonic-gate 			cflag++;
13347c478bd9Sstevel@tonic-gate 			break;
13357c478bd9Sstevel@tonic-gate 		case 'e':		/* show environment variables */
13367c478bd9Sstevel@tonic-gate 			content |= CC_CONTENT_STACK;
13377c478bd9Sstevel@tonic-gate 			eflag++;
1338ffec1fd1SRobert Mustacchi 			if (cmd != PARGS_ARGV)
1339ffec1fd1SRobert Mustacchi 				errflg++;
13407c478bd9Sstevel@tonic-gate 			break;
13417c478bd9Sstevel@tonic-gate 		case 'l':
13427c478bd9Sstevel@tonic-gate 			lflag++;
13437c478bd9Sstevel@tonic-gate 			aflag++;	/* -l implies -a */
1344ffec1fd1SRobert Mustacchi 			if (cmd != PARGS_ARGV)
1345ffec1fd1SRobert Mustacchi 				errflg++;
13467c478bd9Sstevel@tonic-gate 			break;
13477c478bd9Sstevel@tonic-gate 		case 'x':		/* show aux vector entries */
13487c478bd9Sstevel@tonic-gate 			xflag++;
1349ffec1fd1SRobert Mustacchi 			if (cmd != PARGS_ARGV)
1350ffec1fd1SRobert Mustacchi 				errflg++;
13517c478bd9Sstevel@tonic-gate 			break;
13527c478bd9Sstevel@tonic-gate 		case 'F':
13537c478bd9Sstevel@tonic-gate 			/*
13547c478bd9Sstevel@tonic-gate 			 * Since we open the process read-only, there is no need
13557c478bd9Sstevel@tonic-gate 			 * for the -F flag.  It's a documented flag, so we
13567c478bd9Sstevel@tonic-gate 			 * consume it silently.
13577c478bd9Sstevel@tonic-gate 			 */
13587c478bd9Sstevel@tonic-gate 			break;
13597c478bd9Sstevel@tonic-gate 		default:
13607c478bd9Sstevel@tonic-gate 			errflg++;
13617c478bd9Sstevel@tonic-gate 			break;
13627c478bd9Sstevel@tonic-gate 		}
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	/* -a is the default if no options are specified */
13667c478bd9Sstevel@tonic-gate 	if ((aflag + eflag + xflag + lflag) == 0) {
1367ffec1fd1SRobert Mustacchi 		switch (cmd) {
1368ffec1fd1SRobert Mustacchi 		case PARGS_ARGV:
13697c478bd9Sstevel@tonic-gate 			aflag++;
13707c478bd9Sstevel@tonic-gate 			content |= CC_CONTENT_STACK;
1371ffec1fd1SRobert Mustacchi 			break;
1372ffec1fd1SRobert Mustacchi 		case PARGS_ENV:
1373ffec1fd1SRobert Mustacchi 			content |= CC_CONTENT_STACK;
1374ffec1fd1SRobert Mustacchi 			eflag++;
1375ffec1fd1SRobert Mustacchi 			break;
1376ffec1fd1SRobert Mustacchi 		case PARGS_AUXV:
1377ffec1fd1SRobert Mustacchi 			xflag++;
1378ffec1fd1SRobert Mustacchi 			break;
1379ffec1fd1SRobert Mustacchi 		}
13807c478bd9Sstevel@tonic-gate 	}
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	/* -l cannot be used with the -x or -e flags */
13837c478bd9Sstevel@tonic-gate 	if (lflag && (xflag || eflag)) {
13847c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "-l is incompatible with -x and -e\n");
13857c478bd9Sstevel@tonic-gate 		errflg++;
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	argc -= optind;
13897c478bd9Sstevel@tonic-gate 	argv += optind;
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	if (errflg || argc <= 0) {
13927c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1393ba5fdd2dSDavid Höppner 		    "usage:  %s [-aceFlx] { pid | core } ...\n"
13947c478bd9Sstevel@tonic-gate 		    "  (show process arguments and environment)\n"
13957c478bd9Sstevel@tonic-gate 		    "  -a: show process arguments (default)\n"
13967c478bd9Sstevel@tonic-gate 		    "  -c: interpret characters as 7-bit ascii regardless of "
13977c478bd9Sstevel@tonic-gate 		    "locale\n"
13987c478bd9Sstevel@tonic-gate 		    "  -e: show environment variables\n"
1399ba5fdd2dSDavid Höppner 		    "  -F: force grabbing of the target process\n"
14007c478bd9Sstevel@tonic-gate 		    "  -l: display arguments as command line\n"
1401ba5fdd2dSDavid Höppner 		    "  -x: show aux vector entries\n", command);
14027c478bd9Sstevel@tonic-gate 		return (2);
14037c478bd9Sstevel@tonic-gate 	}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 	while (argc-- > 0) {
14067c478bd9Sstevel@tonic-gate 		char *arg;
14077c478bd9Sstevel@tonic-gate 		int gret, r;
14087c478bd9Sstevel@tonic-gate 		psinfo_t psinfo;
14097c478bd9Sstevel@tonic-gate 		char *psargs_conv;
14107c478bd9Sstevel@tonic-gate 		struct ps_prochandle *Pr;
14117c478bd9Sstevel@tonic-gate 		pargs_data_t datap;
14127c478bd9Sstevel@tonic-gate 		char *info;
14137c478bd9Sstevel@tonic-gate 		size_t info_sz;
14147c478bd9Sstevel@tonic-gate 		int pstate;
14157c478bd9Sstevel@tonic-gate 		char execname[PATH_MAX];
14167c478bd9Sstevel@tonic-gate 		int unprintable;
14177c478bd9Sstevel@tonic-gate 		int diflocale;
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
14207c478bd9Sstevel@tonic-gate 		arg = *argv++;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 		/*
14237c478bd9Sstevel@tonic-gate 		 * Suppress extra blanks lines if we've encountered processes
14247c478bd9Sstevel@tonic-gate 		 * which can't be opened.
14257c478bd9Sstevel@tonic-gate 		 */
14267c478bd9Sstevel@tonic-gate 		if (error == 0) {
14277c478bd9Sstevel@tonic-gate 			(void) printf("\n");
14287c478bd9Sstevel@tonic-gate 		}
14297c478bd9Sstevel@tonic-gate 		error = 0;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 		/*
14327c478bd9Sstevel@tonic-gate 		 * First grab just the psinfo information, in case this
14337c478bd9Sstevel@tonic-gate 		 * process is a zombie (in which case proc_arg_grab() will
14347c478bd9Sstevel@tonic-gate 		 * fail).  If so, print a nice message and continue.
14357c478bd9Sstevel@tonic-gate 		 */
14367c478bd9Sstevel@tonic-gate 		if (proc_arg_psinfo(arg, PR_ARG_ANY, &psinfo,
14377c478bd9Sstevel@tonic-gate 		    &gret) == -1) {
14387c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
14397c478bd9Sstevel@tonic-gate 			    command, arg, Pgrab_error(gret));
14407c478bd9Sstevel@tonic-gate 			retc++;
14417c478bd9Sstevel@tonic-gate 			error = 1;
14427c478bd9Sstevel@tonic-gate 			continue;
14437c478bd9Sstevel@tonic-gate 		}
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 		if (psinfo.pr_nlwp == 0) {
14467c478bd9Sstevel@tonic-gate 			(void) printf("%d: <defunct>\n", (int)psinfo.pr_pid);
14477c478bd9Sstevel@tonic-gate 			continue;
14487c478bd9Sstevel@tonic-gate 		}
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 		/*
14517c478bd9Sstevel@tonic-gate 		 * If process is a "system" process (like pageout), just
14527c478bd9Sstevel@tonic-gate 		 * print its psargs and continue on.
14537c478bd9Sstevel@tonic-gate 		 */
14547c478bd9Sstevel@tonic-gate 		if (psinfo.pr_size == 0 && psinfo.pr_rssize == 0) {
14557c478bd9Sstevel@tonic-gate 			proc_unctrl_psinfo(&psinfo);
14567c478bd9Sstevel@tonic-gate 			if (!lflag)
14577c478bd9Sstevel@tonic-gate 				(void) printf("%d: ", (int)psinfo.pr_pid);
14587c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", psinfo.pr_psargs);
14597c478bd9Sstevel@tonic-gate 			continue;
14607c478bd9Sstevel@tonic-gate 		}
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 		/*
14637c478bd9Sstevel@tonic-gate 		 * Open the process readonly, since we do not need to write to
14647c478bd9Sstevel@tonic-gate 		 * the control file.
14657c478bd9Sstevel@tonic-gate 		 */
14667c478bd9Sstevel@tonic-gate 		if ((Pr = proc_arg_grab(arg, PR_ARG_ANY, PGRAB_RDONLY,
14677c478bd9Sstevel@tonic-gate 		    &gret)) == NULL) {
14687c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
14697c478bd9Sstevel@tonic-gate 			    command, arg, Pgrab_error(gret));
14707c478bd9Sstevel@tonic-gate 			retc++;
14717c478bd9Sstevel@tonic-gate 			error = 1;
14727c478bd9Sstevel@tonic-gate 			continue;
14737c478bd9Sstevel@tonic-gate 		}
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 		pstate = Pstate(Pr);
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 		if (pstate == PS_DEAD &&
14787c478bd9Sstevel@tonic-gate 		    (Pcontent(Pr) & content) != content) {
14797c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: core '%s' has "
14807c478bd9Sstevel@tonic-gate 			    "insufficient content\n", command, arg);
14817c478bd9Sstevel@tonic-gate 			retc++;
14827c478bd9Sstevel@tonic-gate 			continue;
14837c478bd9Sstevel@tonic-gate 		}
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 		/*
14867c478bd9Sstevel@tonic-gate 		 * If malloc() fails, we return here so that we can let go
14877c478bd9Sstevel@tonic-gate 		 * of the victim, restore our locale, print a message,
14887c478bd9Sstevel@tonic-gate 		 * then exit.
14897c478bd9Sstevel@tonic-gate 		 */
14907c478bd9Sstevel@tonic-gate 		if ((r = setjmp(env)) != 0) {
14917c478bd9Sstevel@tonic-gate 			Prelease(Pr, 0);
14927c478bd9Sstevel@tonic-gate 			(void) setlocale(LC_ALL, "");
14937c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: out of memory: %s\n",
14947c478bd9Sstevel@tonic-gate 			    command, strerror(r));
14957c478bd9Sstevel@tonic-gate 			return (1);
14967c478bd9Sstevel@tonic-gate 		}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		dmodel = Pstatus(Pr)->pr_dmodel;
14997c478bd9Sstevel@tonic-gate 		bzero(&datap, sizeof (datap));
15007c478bd9Sstevel@tonic-gate 		bcopy(Ppsinfo(Pr), &psinfo, sizeof (psinfo_t));
15017c478bd9Sstevel@tonic-gate 		datap.pd_proc = Pr;
15027c478bd9Sstevel@tonic-gate 		datap.pd_psinfo = &psinfo;
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 		if (cflag)
15057c478bd9Sstevel@tonic-gate 			datap.pd_conv_flags |= CONV_STRICT_ASCII;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 		/*
15087c478bd9Sstevel@tonic-gate 		 * Strip control characters, then record process summary in
15097c478bd9Sstevel@tonic-gate 		 * a buffer, since we don't want to print anything out until
15107c478bd9Sstevel@tonic-gate 		 * after we release the process.
15117c478bd9Sstevel@tonic-gate 		 */
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 		/*
15147c478bd9Sstevel@tonic-gate 		 * The process is neither a system process nor defunct.
15157c478bd9Sstevel@tonic-gate 		 *
15167c478bd9Sstevel@tonic-gate 		 * Do printing and post-processing (like name lookups) after
15177c478bd9Sstevel@tonic-gate 		 * gathering the raw data from the process and releasing it.
15187c478bd9Sstevel@tonic-gate 		 * This way, we don't deadlock on (for example) name lookup
15197c478bd9Sstevel@tonic-gate 		 * if we grabbed the nscd and do 'pargs -x'.
15207c478bd9Sstevel@tonic-gate 		 *
15217c478bd9Sstevel@tonic-gate 		 * We always fetch the environment of the target, so that we
15227c478bd9Sstevel@tonic-gate 		 * can make an educated guess about its locale.
15237c478bd9Sstevel@tonic-gate 		 */
15247c478bd9Sstevel@tonic-gate 		get_env(&datap);
15257c478bd9Sstevel@tonic-gate 		if (aflag != 0)
15267c478bd9Sstevel@tonic-gate 			get_args(&datap);
15277c478bd9Sstevel@tonic-gate 		if (xflag != 0)
15287c478bd9Sstevel@tonic-gate 			get_auxv(&datap);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		/*
15317c478bd9Sstevel@tonic-gate 		 * If malloc() fails after this poiint, we return here to
15327c478bd9Sstevel@tonic-gate 		 * restore our locale and print a message.  If we don't
15337c478bd9Sstevel@tonic-gate 		 * reset this, we might erroneously try to Prelease a process
15347c478bd9Sstevel@tonic-gate 		 * twice.
15357c478bd9Sstevel@tonic-gate 		 */
15367c478bd9Sstevel@tonic-gate 		if ((r = setjmp(env)) != 0) {
15377c478bd9Sstevel@tonic-gate 			(void) setlocale(LC_ALL, "");
15387c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: out of memory: %s\n",
15397c478bd9Sstevel@tonic-gate 			    command, strerror(r));
15407c478bd9Sstevel@tonic-gate 			return (1);
15417c478bd9Sstevel@tonic-gate 		}
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 		/*
15447c478bd9Sstevel@tonic-gate 		 * For the -l option, we need a proper name for this executable
15457c478bd9Sstevel@tonic-gate 		 * before we release it.
15467c478bd9Sstevel@tonic-gate 		 */
15477c478bd9Sstevel@tonic-gate 		if (lflag)
15487c478bd9Sstevel@tonic-gate 			datap.pd_execname = Pexecname(Pr, execname,
15497c478bd9Sstevel@tonic-gate 			    sizeof (execname));
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 		Prelease(Pr, 0);
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 		/*
15547c478bd9Sstevel@tonic-gate 		 * Crawl through the environment to determine the locale of
15557c478bd9Sstevel@tonic-gate 		 * the target.
15567c478bd9Sstevel@tonic-gate 		 */
15577c478bd9Sstevel@tonic-gate 		lookup_locale(&datap);
15587c478bd9Sstevel@tonic-gate 		diflocale = 0;
15597c478bd9Sstevel@tonic-gate 		setup_conversions(&datap, &diflocale);
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 		if (lflag != 0) {
15627c478bd9Sstevel@tonic-gate 			unprintable = 0;
15637c478bd9Sstevel@tonic-gate 			convert_array(&datap, datap.pd_argv_strs,
15647c478bd9Sstevel@tonic-gate 			    datap.pd_argc, &unprintable);
15657c478bd9Sstevel@tonic-gate 			if (diflocale)
15667c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: Warning, target "
15677c478bd9Sstevel@tonic-gate 				    "locale differs from current locale\n",
15687c478bd9Sstevel@tonic-gate 				    command);
15697c478bd9Sstevel@tonic-gate 			else if (unprintable)
15707c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: Warning, command "
15717c478bd9Sstevel@tonic-gate 				    "line contains unprintable characters\n",
15727c478bd9Sstevel@tonic-gate 				    command);
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 			retc += print_cmdline(&datap);
15757c478bd9Sstevel@tonic-gate 		} else {
15767c478bd9Sstevel@tonic-gate 			psargs_conv = convert_str(&datap, psinfo.pr_psargs,
15777c478bd9Sstevel@tonic-gate 			    &unprintable);
15787c478bd9Sstevel@tonic-gate 			info_sz = strlen(psargs_conv) + MAXPATHLEN + 32 + 1;
15797c478bd9Sstevel@tonic-gate 			info = malloc(info_sz);
15807c478bd9Sstevel@tonic-gate 			if (pstate == PS_DEAD) {
15817c478bd9Sstevel@tonic-gate 				(void) snprintf(info, info_sz,
15827c478bd9Sstevel@tonic-gate 				    "core '%s' of %d:\t%s\n",
15837c478bd9Sstevel@tonic-gate 				    arg, (int)psinfo.pr_pid, psargs_conv);
15847c478bd9Sstevel@tonic-gate 			} else {
15857c478bd9Sstevel@tonic-gate 				(void) snprintf(info, info_sz, "%d:\t%s\n",
15867c478bd9Sstevel@tonic-gate 				    (int)psinfo.pr_pid, psargs_conv);
15877c478bd9Sstevel@tonic-gate 			}
15887c478bd9Sstevel@tonic-gate 			(void) printf("%s", info);
15897c478bd9Sstevel@tonic-gate 			free(info);
15907c478bd9Sstevel@tonic-gate 			free(psargs_conv);
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 			if (aflag != 0) {
15937c478bd9Sstevel@tonic-gate 				convert_array(&datap, datap.pd_argv_strs,
15947c478bd9Sstevel@tonic-gate 				    datap.pd_argc, &unprintable);
15957c478bd9Sstevel@tonic-gate 				print_args(&datap);
15967c478bd9Sstevel@tonic-gate 				if (eflag || xflag)
15977c478bd9Sstevel@tonic-gate 					(void) printf("\n");
15987c478bd9Sstevel@tonic-gate 			}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 			if (eflag != 0) {
16017c478bd9Sstevel@tonic-gate 				convert_array(&datap, datap.pd_envp_strs,
16027c478bd9Sstevel@tonic-gate 				    datap.pd_envc, &unprintable);
16037c478bd9Sstevel@tonic-gate 				print_env(&datap);
16047c478bd9Sstevel@tonic-gate 				if (xflag)
16057c478bd9Sstevel@tonic-gate 					(void) printf("\n");
16067c478bd9Sstevel@tonic-gate 			}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 			if (xflag != 0) {
16097c478bd9Sstevel@tonic-gate 				convert_array(&datap, datap.pd_auxv_strs,
16107c478bd9Sstevel@tonic-gate 				    datap.pd_auxc, &unprintable);
16117c478bd9Sstevel@tonic-gate 				print_auxv(&datap);
16127c478bd9Sstevel@tonic-gate 			}
16137c478bd9Sstevel@tonic-gate 		}
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 		cleanup_conversions(&datap);
16167c478bd9Sstevel@tonic-gate 		free_data(&datap);
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	return (retc != 0 ? 1 : 0);
16207c478bd9Sstevel@tonic-gate }
1621