1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * pargs examines and prints the arguments (argv), environment (environ), 31*7c478bd9Sstevel@tonic-gate * and auxiliary vector of another process. 32*7c478bd9Sstevel@tonic-gate * 33*7c478bd9Sstevel@tonic-gate * This utility is made more complex because it must run in internationalized 34*7c478bd9Sstevel@tonic-gate * environments. The two key cases for pargs to manage are: 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * 1. pargs and target run in the same locale: pargs must respect the 37*7c478bd9Sstevel@tonic-gate * locale, but this case is straightforward. Care is taken to correctly 38*7c478bd9Sstevel@tonic-gate * use wide characters in order to print results properly. 39*7c478bd9Sstevel@tonic-gate * 40*7c478bd9Sstevel@tonic-gate * 2. pargs and target run in different locales: in this case, pargs examines 41*7c478bd9Sstevel@tonic-gate * the string having assumed the victim's locale. Unprintable (but valid) 42*7c478bd9Sstevel@tonic-gate * characters are escaped. Next, iconv(3c) is used to convert between the 43*7c478bd9Sstevel@tonic-gate * target and pargs codeset. Finally, a second pass to escape unprintable 44*7c478bd9Sstevel@tonic-gate * (but valid) characters is made. 45*7c478bd9Sstevel@tonic-gate * 46*7c478bd9Sstevel@tonic-gate * In any case in which characters are encountered which are not valid in 47*7c478bd9Sstevel@tonic-gate * their purported locale, the string "fails" and is treated as a traditional 48*7c478bd9Sstevel@tonic-gate * 7-bit ASCII encoded string, and escaped accordingly. 49*7c478bd9Sstevel@tonic-gate */ 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate #include <stdio.h> 52*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 53*7c478bd9Sstevel@tonic-gate #include <locale.h> 54*7c478bd9Sstevel@tonic-gate #include <wchar.h> 55*7c478bd9Sstevel@tonic-gate #include <iconv.h> 56*7c478bd9Sstevel@tonic-gate #include <langinfo.h> 57*7c478bd9Sstevel@tonic-gate #include <unistd.h> 58*7c478bd9Sstevel@tonic-gate #include <ctype.h> 59*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 60*7c478bd9Sstevel@tonic-gate #include <string.h> 61*7c478bd9Sstevel@tonic-gate #include <strings.h> 62*7c478bd9Sstevel@tonic-gate #include <limits.h> 63*7c478bd9Sstevel@tonic-gate #include <pwd.h> 64*7c478bd9Sstevel@tonic-gate #include <grp.h> 65*7c478bd9Sstevel@tonic-gate #include <errno.h> 66*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 67*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 68*7c478bd9Sstevel@tonic-gate #include <sys/auxv.h> 69*7c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 70*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 71*7c478bd9Sstevel@tonic-gate #include <sys/elf.h> 72*7c478bd9Sstevel@tonic-gate #include <libproc.h> 73*7c478bd9Sstevel@tonic-gate #include <wctype.h> 74*7c478bd9Sstevel@tonic-gate #include <widec.h> 75*7c478bd9Sstevel@tonic-gate #include <elfcap.h> 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate typedef struct pargs_data { 78*7c478bd9Sstevel@tonic-gate struct ps_prochandle *pd_proc; /* target proc handle */ 79*7c478bd9Sstevel@tonic-gate psinfo_t *pd_psinfo; /* target psinfo */ 80*7c478bd9Sstevel@tonic-gate char *pd_locale; /* target process locale */ 81*7c478bd9Sstevel@tonic-gate int pd_conv_flags; /* flags governing string conversion */ 82*7c478bd9Sstevel@tonic-gate iconv_t pd_iconv; /* iconv conversion descriptor */ 83*7c478bd9Sstevel@tonic-gate size_t pd_argc; 84*7c478bd9Sstevel@tonic-gate uintptr_t *pd_argv; 85*7c478bd9Sstevel@tonic-gate char **pd_argv_strs; 86*7c478bd9Sstevel@tonic-gate size_t pd_envc; 87*7c478bd9Sstevel@tonic-gate uintptr_t *pd_envp; 88*7c478bd9Sstevel@tonic-gate char **pd_envp_strs; 89*7c478bd9Sstevel@tonic-gate size_t pd_auxc; 90*7c478bd9Sstevel@tonic-gate auxv_t *pd_auxv; 91*7c478bd9Sstevel@tonic-gate char **pd_auxv_strs; 92*7c478bd9Sstevel@tonic-gate char *pd_execname; 93*7c478bd9Sstevel@tonic-gate } pargs_data_t; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate #define CONV_USE_ICONV 0x01 96*7c478bd9Sstevel@tonic-gate #define CONV_STRICT_ASCII 0x02 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate static char *command; 99*7c478bd9Sstevel@tonic-gate static int dmodel; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate #define EXTRACT_BUFSZ 128 /* extract_string() initial size */ 102*7c478bd9Sstevel@tonic-gate #define ENV_CHUNK 16 /* #env ptrs to read at a time */ 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate static jmp_buf env; /* malloc failure handling */ 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate static void * 107*7c478bd9Sstevel@tonic-gate safe_zalloc(size_t size) 108*7c478bd9Sstevel@tonic-gate { 109*7c478bd9Sstevel@tonic-gate void *p; 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate /* 112*7c478bd9Sstevel@tonic-gate * If the malloc fails we longjmp out to allow the code to Prelease() 113*7c478bd9Sstevel@tonic-gate * a stopped victim if needed. 114*7c478bd9Sstevel@tonic-gate */ 115*7c478bd9Sstevel@tonic-gate if ((p = malloc(size)) == NULL) { 116*7c478bd9Sstevel@tonic-gate longjmp(env, errno); 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate bzero(p, size); 120*7c478bd9Sstevel@tonic-gate return (p); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate static char * 124*7c478bd9Sstevel@tonic-gate safe_strdup(const char *s1) 125*7c478bd9Sstevel@tonic-gate { 126*7c478bd9Sstevel@tonic-gate char *s2; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate s2 = safe_zalloc(strlen(s1) + 1); 129*7c478bd9Sstevel@tonic-gate (void) strcpy(s2, s1); 130*7c478bd9Sstevel@tonic-gate return (s2); 131*7c478bd9Sstevel@tonic-gate } 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate /* 134*7c478bd9Sstevel@tonic-gate * Given a wchar_t which might represent an 'escapable' sequence (see 135*7c478bd9Sstevel@tonic-gate * formats(5)), return the base ascii character needed to print that 136*7c478bd9Sstevel@tonic-gate * sequence. 137*7c478bd9Sstevel@tonic-gate * 138*7c478bd9Sstevel@tonic-gate * The comparisons performed may look suspect at first, but all are valid; 139*7c478bd9Sstevel@tonic-gate * the characters below all appear in the "Portable Character Set." The 140*7c478bd9Sstevel@tonic-gate * Single Unix Spec says: "The wide-character value for each member of the 141*7c478bd9Sstevel@tonic-gate * Portable Character Set will equal its value when used as the lone 142*7c478bd9Sstevel@tonic-gate * character in an integer character constant." 143*7c478bd9Sstevel@tonic-gate */ 144*7c478bd9Sstevel@tonic-gate static uchar_t 145*7c478bd9Sstevel@tonic-gate get_interp_char(wchar_t wc) 146*7c478bd9Sstevel@tonic-gate { 147*7c478bd9Sstevel@tonic-gate switch (wc) { 148*7c478bd9Sstevel@tonic-gate case L'\a': 149*7c478bd9Sstevel@tonic-gate return ('a'); 150*7c478bd9Sstevel@tonic-gate case L'\b': 151*7c478bd9Sstevel@tonic-gate return ('b'); 152*7c478bd9Sstevel@tonic-gate case L'\f': 153*7c478bd9Sstevel@tonic-gate return ('f'); 154*7c478bd9Sstevel@tonic-gate case L'\n': 155*7c478bd9Sstevel@tonic-gate return ('n'); 156*7c478bd9Sstevel@tonic-gate case L'\r': 157*7c478bd9Sstevel@tonic-gate return ('r'); 158*7c478bd9Sstevel@tonic-gate case L'\t': 159*7c478bd9Sstevel@tonic-gate return ('t'); 160*7c478bd9Sstevel@tonic-gate case L'\v': 161*7c478bd9Sstevel@tonic-gate return ('v'); 162*7c478bd9Sstevel@tonic-gate case L'\\': 163*7c478bd9Sstevel@tonic-gate return ('\\'); 164*7c478bd9Sstevel@tonic-gate } 165*7c478bd9Sstevel@tonic-gate return ('\0'); 166*7c478bd9Sstevel@tonic-gate } 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate static char * 169*7c478bd9Sstevel@tonic-gate unctrl_str_strict_ascii(const char *src, int escape_slash, int *unprintable) 170*7c478bd9Sstevel@tonic-gate { 171*7c478bd9Sstevel@tonic-gate uchar_t *uc, *ucp, c, ic; 172*7c478bd9Sstevel@tonic-gate uc = ucp = safe_zalloc((strlen(src) * 4) + 1); 173*7c478bd9Sstevel@tonic-gate while ((c = *src++) != '\0') { 174*7c478bd9Sstevel@tonic-gate /* 175*7c478bd9Sstevel@tonic-gate * Call get_interp_char *first*, since \ will otherwise not 176*7c478bd9Sstevel@tonic-gate * be escaped as \\. 177*7c478bd9Sstevel@tonic-gate */ 178*7c478bd9Sstevel@tonic-gate if ((ic = get_interp_char((wchar_t)c)) != '\0') { 179*7c478bd9Sstevel@tonic-gate if (escape_slash || ic != '\\') 180*7c478bd9Sstevel@tonic-gate *ucp++ = '\\'; 181*7c478bd9Sstevel@tonic-gate *ucp++ = ic; 182*7c478bd9Sstevel@tonic-gate } else if (isascii(c) && isprint(c)) { 183*7c478bd9Sstevel@tonic-gate *ucp++ = c; 184*7c478bd9Sstevel@tonic-gate } else { 185*7c478bd9Sstevel@tonic-gate *ucp++ = '\\'; 186*7c478bd9Sstevel@tonic-gate *ucp++ = ((c >> 6) & 7) + '0'; 187*7c478bd9Sstevel@tonic-gate *ucp++ = ((c >> 3) & 7) + '0'; 188*7c478bd9Sstevel@tonic-gate *ucp++ = (c & 7) + '0'; 189*7c478bd9Sstevel@tonic-gate *unprintable = 1; 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate *ucp = '\0'; 193*7c478bd9Sstevel@tonic-gate return ((char *)uc); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * Convert control characters as described in format(5) to their readable 198*7c478bd9Sstevel@tonic-gate * representation; special care is taken to handle multibyte character sets. 199*7c478bd9Sstevel@tonic-gate * 200*7c478bd9Sstevel@tonic-gate * If escape_slash is true, escaping of '\' occurs. The first time a string 201*7c478bd9Sstevel@tonic-gate * is unctrl'd, this should be '1'. Subsequent iterations over the same 202*7c478bd9Sstevel@tonic-gate * string should set escape_slash to 0. Otherwise you'll wind up with 203*7c478bd9Sstevel@tonic-gate * \ --> \\ --> \\\\. 204*7c478bd9Sstevel@tonic-gate */ 205*7c478bd9Sstevel@tonic-gate static char * 206*7c478bd9Sstevel@tonic-gate unctrl_str(const char *src, int escape_slash, int *unprintable) 207*7c478bd9Sstevel@tonic-gate { 208*7c478bd9Sstevel@tonic-gate wchar_t wc; 209*7c478bd9Sstevel@tonic-gate wchar_t *wide_src, *wide_srcp; 210*7c478bd9Sstevel@tonic-gate wchar_t *wide_dest, *wide_destp; 211*7c478bd9Sstevel@tonic-gate char *uc; 212*7c478bd9Sstevel@tonic-gate size_t srcbufsz = strlen(src) + 1; 213*7c478bd9Sstevel@tonic-gate size_t destbufsz = srcbufsz * 4; 214*7c478bd9Sstevel@tonic-gate size_t srclen, destlen; 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate wide_srcp = wide_src = safe_zalloc(srcbufsz * sizeof (wchar_t)); 217*7c478bd9Sstevel@tonic-gate wide_destp = wide_dest = safe_zalloc(destbufsz * sizeof (wchar_t)); 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if ((srclen = mbstowcs(wide_src, src, srcbufsz - 1)) == (size_t)-1) { 220*7c478bd9Sstevel@tonic-gate /* 221*7c478bd9Sstevel@tonic-gate * We can't trust the string, since in the locale in which 222*7c478bd9Sstevel@tonic-gate * this call is operating, the string contains an invalid 223*7c478bd9Sstevel@tonic-gate * multibyte sequence. There isn't much to do here, so 224*7c478bd9Sstevel@tonic-gate * convert the string byte by byte to wide characters, as 225*7c478bd9Sstevel@tonic-gate * if it came from a C locale (char) string. This isn't 226*7c478bd9Sstevel@tonic-gate * perfect, but at least the characters will make it to 227*7c478bd9Sstevel@tonic-gate * the screen. 228*7c478bd9Sstevel@tonic-gate */ 229*7c478bd9Sstevel@tonic-gate free(wide_src); 230*7c478bd9Sstevel@tonic-gate free(wide_dest); 231*7c478bd9Sstevel@tonic-gate return (unctrl_str_strict_ascii(src, escape_slash, 232*7c478bd9Sstevel@tonic-gate unprintable)); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate if (srclen == (srcbufsz - 1)) { 235*7c478bd9Sstevel@tonic-gate wide_src[srclen] = L'\0'; 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate while ((wc = *wide_srcp++) != L'\0') { 239*7c478bd9Sstevel@tonic-gate char cvt_buf[MB_LEN_MAX]; 240*7c478bd9Sstevel@tonic-gate int len, i; 241*7c478bd9Sstevel@tonic-gate char c = get_interp_char(wc); 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate if ((c != '\0') && (escape_slash || c != '\\')) { 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * Print "interpreted version" (\n, \a, etc). 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate *wide_destp++ = L'\\'; 248*7c478bd9Sstevel@tonic-gate *wide_destp++ = (wchar_t)c; 249*7c478bd9Sstevel@tonic-gate continue; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate if (iswprint(wc)) { 253*7c478bd9Sstevel@tonic-gate *wide_destp++ = wc; 254*7c478bd9Sstevel@tonic-gate continue; 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate /* 258*7c478bd9Sstevel@tonic-gate * Convert the wide char back into (potentially several) 259*7c478bd9Sstevel@tonic-gate * multibyte characters, then escape out each of those bytes. 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate bzero(cvt_buf, sizeof (cvt_buf)); 262*7c478bd9Sstevel@tonic-gate if ((len = wctomb(cvt_buf, wc)) == -1) { 263*7c478bd9Sstevel@tonic-gate /* 264*7c478bd9Sstevel@tonic-gate * This is a totally invalid wide char; discard it. 265*7c478bd9Sstevel@tonic-gate */ 266*7c478bd9Sstevel@tonic-gate continue; 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 269*7c478bd9Sstevel@tonic-gate uchar_t c = cvt_buf[i]; 270*7c478bd9Sstevel@tonic-gate *wide_destp++ = L'\\'; 271*7c478bd9Sstevel@tonic-gate *wide_destp++ = (wchar_t)('0' + ((c >> 6) & 7)); 272*7c478bd9Sstevel@tonic-gate *wide_destp++ = (wchar_t)('0' + ((c >> 3) & 7)); 273*7c478bd9Sstevel@tonic-gate *wide_destp++ = (wchar_t)('0' + (c & 7)); 274*7c478bd9Sstevel@tonic-gate *unprintable = 1; 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate *wide_destp = '\0'; 279*7c478bd9Sstevel@tonic-gate destlen = (wide_destp - wide_dest) * MB_CUR_MAX + 1; 280*7c478bd9Sstevel@tonic-gate uc = safe_zalloc(destlen); 281*7c478bd9Sstevel@tonic-gate if (wcstombs(uc, wide_dest, destlen) == (size_t)-1) { 282*7c478bd9Sstevel@tonic-gate /* If we've gotten this far, wcstombs shouldn't fail... */ 283*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: wcstombs failed unexpectedly: %s\n", 284*7c478bd9Sstevel@tonic-gate command, strerror(errno)); 285*7c478bd9Sstevel@tonic-gate exit(1); 286*7c478bd9Sstevel@tonic-gate } else { 287*7c478bd9Sstevel@tonic-gate char *tmp; 288*7c478bd9Sstevel@tonic-gate /* 289*7c478bd9Sstevel@tonic-gate * Try to save memory; don't waste 3 * strlen in the 290*7c478bd9Sstevel@tonic-gate * common case. 291*7c478bd9Sstevel@tonic-gate */ 292*7c478bd9Sstevel@tonic-gate tmp = safe_strdup(uc); 293*7c478bd9Sstevel@tonic-gate free(uc); 294*7c478bd9Sstevel@tonic-gate uc = tmp; 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate free(wide_dest); 297*7c478bd9Sstevel@tonic-gate free(wide_src); 298*7c478bd9Sstevel@tonic-gate return (uc); 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* 302*7c478bd9Sstevel@tonic-gate * These functions determine which characters are safe to be left unquoted. 303*7c478bd9Sstevel@tonic-gate * Rather than starting with every printable character and subtracting out the 304*7c478bd9Sstevel@tonic-gate * shell metacharacters, we take the more conservative approach of starting with 305*7c478bd9Sstevel@tonic-gate * a set of safe characters and adding those few common punctuation characters 306*7c478bd9Sstevel@tonic-gate * which are known to be safe. The rules are: 307*7c478bd9Sstevel@tonic-gate * 308*7c478bd9Sstevel@tonic-gate * If this is a printable character (graph), and not punctuation, it is 309*7c478bd9Sstevel@tonic-gate * safe to leave unquoted. 310*7c478bd9Sstevel@tonic-gate * 311*7c478bd9Sstevel@tonic-gate * If it's one of known hard-coded safe characters, it's also safe to leave 312*7c478bd9Sstevel@tonic-gate * unquoted. 313*7c478bd9Sstevel@tonic-gate * 314*7c478bd9Sstevel@tonic-gate * Otherwise, the entire argument must be quoted. 315*7c478bd9Sstevel@tonic-gate * 316*7c478bd9Sstevel@tonic-gate * This will cause some strings to be unecessarily quoted, but it is safer than 317*7c478bd9Sstevel@tonic-gate * having a character unintentionally interpreted by the shell. 318*7c478bd9Sstevel@tonic-gate */ 319*7c478bd9Sstevel@tonic-gate static int 320*7c478bd9Sstevel@tonic-gate issafe_ascii(char c) 321*7c478bd9Sstevel@tonic-gate { 322*7c478bd9Sstevel@tonic-gate return (isalnum(c) || strchr("_.-/@:,", c) != NULL); 323*7c478bd9Sstevel@tonic-gate } 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate static int 326*7c478bd9Sstevel@tonic-gate issafe(wchar_t wc) 327*7c478bd9Sstevel@tonic-gate { 328*7c478bd9Sstevel@tonic-gate return ((iswgraph(wc) && !iswpunct(wc)) || 329*7c478bd9Sstevel@tonic-gate wschr(L"_.-/@:,", wc) != NULL); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 333*7c478bd9Sstevel@tonic-gate static char * 334*7c478bd9Sstevel@tonic-gate quote_string_ascii(pargs_data_t *datap, char *src) 335*7c478bd9Sstevel@tonic-gate { 336*7c478bd9Sstevel@tonic-gate char *dst; 337*7c478bd9Sstevel@tonic-gate int quote_count = 0; 338*7c478bd9Sstevel@tonic-gate int need_quote = 0; 339*7c478bd9Sstevel@tonic-gate char *srcp, *dstp; 340*7c478bd9Sstevel@tonic-gate size_t dstlen; 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate for (srcp = src; *srcp != '\0'; srcp++) { 343*7c478bd9Sstevel@tonic-gate if (!issafe_ascii(*srcp)) { 344*7c478bd9Sstevel@tonic-gate need_quote = 1; 345*7c478bd9Sstevel@tonic-gate if (*srcp == '\'') 346*7c478bd9Sstevel@tonic-gate quote_count++; 347*7c478bd9Sstevel@tonic-gate } 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate if (!need_quote) 351*7c478bd9Sstevel@tonic-gate return (src); 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate /* 354*7c478bd9Sstevel@tonic-gate * The only character we care about here is a single quote. All the 355*7c478bd9Sstevel@tonic-gate * other unprintable characters (and backslashes) will have been dealt 356*7c478bd9Sstevel@tonic-gate * with by unctrl_str(). We make the following subtitution when we 357*7c478bd9Sstevel@tonic-gate * encounter a single quote: 358*7c478bd9Sstevel@tonic-gate * 359*7c478bd9Sstevel@tonic-gate * ' = '"'"' 360*7c478bd9Sstevel@tonic-gate * 361*7c478bd9Sstevel@tonic-gate * In addition, we put single quotes around the entire argument. For 362*7c478bd9Sstevel@tonic-gate * example: 363*7c478bd9Sstevel@tonic-gate * 364*7c478bd9Sstevel@tonic-gate * foo'bar = 'foo'"'"'bar' 365*7c478bd9Sstevel@tonic-gate */ 366*7c478bd9Sstevel@tonic-gate dstlen = strlen(src) + 3 + 4 * quote_count; 367*7c478bd9Sstevel@tonic-gate dst = safe_zalloc(dstlen); 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate dstp = dst; 370*7c478bd9Sstevel@tonic-gate *dstp++ = '\''; 371*7c478bd9Sstevel@tonic-gate for (srcp = src; *srcp != '\0'; srcp++, dstp++) { 372*7c478bd9Sstevel@tonic-gate *dstp = *srcp; 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate if (*srcp == '\'') { 375*7c478bd9Sstevel@tonic-gate dstp[1] = '"'; 376*7c478bd9Sstevel@tonic-gate dstp[2] = '\''; 377*7c478bd9Sstevel@tonic-gate dstp[3] = '"'; 378*7c478bd9Sstevel@tonic-gate dstp[4] = '\''; 379*7c478bd9Sstevel@tonic-gate dstp += 4; 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate *dstp++ = '\''; 383*7c478bd9Sstevel@tonic-gate *dstp = '\0'; 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate free(src); 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate return (dst); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate static char * 391*7c478bd9Sstevel@tonic-gate quote_string(pargs_data_t *datap, char *src) 392*7c478bd9Sstevel@tonic-gate { 393*7c478bd9Sstevel@tonic-gate wchar_t *wide_src, *wide_srcp; 394*7c478bd9Sstevel@tonic-gate wchar_t *wide_dest, *wide_destp; 395*7c478bd9Sstevel@tonic-gate char *uc; 396*7c478bd9Sstevel@tonic-gate size_t srcbufsz = strlen(src) + 1; 397*7c478bd9Sstevel@tonic-gate size_t srclen; 398*7c478bd9Sstevel@tonic-gate size_t destbufsz; 399*7c478bd9Sstevel@tonic-gate size_t destlen; 400*7c478bd9Sstevel@tonic-gate int quote_count = 0; 401*7c478bd9Sstevel@tonic-gate int need_quote = 0; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate if (datap->pd_conv_flags & CONV_STRICT_ASCII) 404*7c478bd9Sstevel@tonic-gate return (quote_string_ascii(datap, src)); 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate wide_srcp = wide_src = safe_zalloc(srcbufsz * sizeof (wchar_t)); 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate if ((srclen = mbstowcs(wide_src, src, srcbufsz - 1)) == (size_t)-1) { 409*7c478bd9Sstevel@tonic-gate free(wide_src); 410*7c478bd9Sstevel@tonic-gate return (quote_string_ascii(datap, src)); 411*7c478bd9Sstevel@tonic-gate } 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate if (srclen == srcbufsz - 1) 414*7c478bd9Sstevel@tonic-gate wide_src[srclen] = L'\0'; 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate for (wide_srcp = wide_src; *wide_srcp != '\0'; wide_srcp++) { 417*7c478bd9Sstevel@tonic-gate if (!issafe(*wide_srcp)) { 418*7c478bd9Sstevel@tonic-gate need_quote = 1; 419*7c478bd9Sstevel@tonic-gate if (*wide_srcp == L'\'') 420*7c478bd9Sstevel@tonic-gate quote_count++; 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate if (!need_quote) { 425*7c478bd9Sstevel@tonic-gate free(wide_src); 426*7c478bd9Sstevel@tonic-gate return (src); 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate /* 430*7c478bd9Sstevel@tonic-gate * See comment for quote_string_ascii(), above. 431*7c478bd9Sstevel@tonic-gate */ 432*7c478bd9Sstevel@tonic-gate destbufsz = srcbufsz + 3 + 4 * quote_count; 433*7c478bd9Sstevel@tonic-gate wide_destp = wide_dest = safe_zalloc(destbufsz * sizeof (wchar_t)); 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate *wide_destp++ = L'\''; 436*7c478bd9Sstevel@tonic-gate for (wide_srcp = wide_src; *wide_srcp != L'\0'; 437*7c478bd9Sstevel@tonic-gate wide_srcp++, wide_destp++) { 438*7c478bd9Sstevel@tonic-gate *wide_destp = *wide_srcp; 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate if (*wide_srcp == L'\'') { 441*7c478bd9Sstevel@tonic-gate wide_destp[1] = L'"'; 442*7c478bd9Sstevel@tonic-gate wide_destp[2] = L'\''; 443*7c478bd9Sstevel@tonic-gate wide_destp[3] = L'"'; 444*7c478bd9Sstevel@tonic-gate wide_destp[4] = L'\''; 445*7c478bd9Sstevel@tonic-gate wide_destp += 4; 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate *wide_destp++ = L'\''; 449*7c478bd9Sstevel@tonic-gate *wide_destp = L'\0'; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate destlen = destbufsz * MB_CUR_MAX + 1; 452*7c478bd9Sstevel@tonic-gate uc = safe_zalloc(destlen); 453*7c478bd9Sstevel@tonic-gate if (wcstombs(uc, wide_dest, destlen) == (size_t)-1) { 454*7c478bd9Sstevel@tonic-gate /* If we've gotten this far, wcstombs shouldn't fail... */ 455*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: wcstombs failed unexpectedly: %s\n", 456*7c478bd9Sstevel@tonic-gate command, strerror(errno)); 457*7c478bd9Sstevel@tonic-gate exit(1); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate free(wide_dest); 461*7c478bd9Sstevel@tonic-gate free(wide_src); 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate return (uc); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate /* 468*7c478bd9Sstevel@tonic-gate * Determine the locale of the target process by traversing its environment, 469*7c478bd9Sstevel@tonic-gate * making only one pass for efficiency's sake; stash the result in 470*7c478bd9Sstevel@tonic-gate * datap->pd_locale. 471*7c478bd9Sstevel@tonic-gate * 472*7c478bd9Sstevel@tonic-gate * It's possible that the process has called setlocale() to change its 473*7c478bd9Sstevel@tonic-gate * locale to something different, but we mostly care about making a good 474*7c478bd9Sstevel@tonic-gate * guess as to the locale at exec(2) time. 475*7c478bd9Sstevel@tonic-gate */ 476*7c478bd9Sstevel@tonic-gate static void 477*7c478bd9Sstevel@tonic-gate lookup_locale(pargs_data_t *datap) 478*7c478bd9Sstevel@tonic-gate { 479*7c478bd9Sstevel@tonic-gate int i, j, composite = 0; 480*7c478bd9Sstevel@tonic-gate size_t len = 0; 481*7c478bd9Sstevel@tonic-gate char *pd_locale; 482*7c478bd9Sstevel@tonic-gate char *lc_all = NULL, *lang = NULL; 483*7c478bd9Sstevel@tonic-gate char *lcs[] = { NULL, NULL, NULL, NULL, NULL, NULL }; 484*7c478bd9Sstevel@tonic-gate static const char *cat_names[] = { 485*7c478bd9Sstevel@tonic-gate "LC_CTYPE=", "LC_NUMERIC=", "LC_TIME=", 486*7c478bd9Sstevel@tonic-gate "LC_COLLATE=", "LC_MONETARY=", "LC_MESSAGES=" 487*7c478bd9Sstevel@tonic-gate }; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_envc; i++) { 490*7c478bd9Sstevel@tonic-gate char *s = datap->pd_envp_strs[i]; 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate if (s == NULL) 493*7c478bd9Sstevel@tonic-gate continue; 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate if (strncmp("LC_ALL=", s, strlen("LC_ALL=")) == 0) { 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * Minor optimization-- if we find LC_ALL we're done. 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate lc_all = s + strlen("LC_ALL="); 500*7c478bd9Sstevel@tonic-gate break; 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate for (j = 0; j <= _LastCategory; j++) { 503*7c478bd9Sstevel@tonic-gate if (strncmp(cat_names[j], s, 504*7c478bd9Sstevel@tonic-gate strlen(cat_names[j])) == 0) { 505*7c478bd9Sstevel@tonic-gate lcs[j] = s + strlen(cat_names[j]); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate if (strncmp("LANG=", s, strlen("LANG=")) == 0) { 509*7c478bd9Sstevel@tonic-gate lang = s + strlen("LANG="); 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate if (lc_all && (*lc_all == '\0')) 514*7c478bd9Sstevel@tonic-gate lc_all = NULL; 515*7c478bd9Sstevel@tonic-gate if (lang && (*lang == '\0')) 516*7c478bd9Sstevel@tonic-gate lang = NULL; 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate for (i = 0; i <= _LastCategory; i++) { 519*7c478bd9Sstevel@tonic-gate if (lc_all != NULL) { 520*7c478bd9Sstevel@tonic-gate lcs[i] = lc_all; 521*7c478bd9Sstevel@tonic-gate } else if (lcs[i] != NULL) { 522*7c478bd9Sstevel@tonic-gate lcs[i] = lcs[i]; 523*7c478bd9Sstevel@tonic-gate } else if (lang != NULL) { 524*7c478bd9Sstevel@tonic-gate lcs[i] = lang; 525*7c478bd9Sstevel@tonic-gate } else { 526*7c478bd9Sstevel@tonic-gate lcs[i] = "C"; 527*7c478bd9Sstevel@tonic-gate } 528*7c478bd9Sstevel@tonic-gate if ((i > 0) && (lcs[i] != lcs[i-1])) 529*7c478bd9Sstevel@tonic-gate composite++; 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate len += 1 + strlen(lcs[i]); /* 1 extra byte for '/' */ 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate if (composite == 0) { 535*7c478bd9Sstevel@tonic-gate /* simple locale */ 536*7c478bd9Sstevel@tonic-gate pd_locale = safe_strdup(lcs[0]); 537*7c478bd9Sstevel@tonic-gate } else { 538*7c478bd9Sstevel@tonic-gate /* composite locale */ 539*7c478bd9Sstevel@tonic-gate pd_locale = safe_zalloc(len + 1); 540*7c478bd9Sstevel@tonic-gate (void) snprintf(pd_locale, len + 1, "/%s/%s/%s/%s/%s/%s", 541*7c478bd9Sstevel@tonic-gate lcs[0], lcs[1], lcs[2], lcs[3], lcs[4], lcs[5]); 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate datap->pd_locale = pd_locale; 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate /* 547*7c478bd9Sstevel@tonic-gate * Pull a string from the victim, regardless of size; this routine allocates 548*7c478bd9Sstevel@tonic-gate * memory for the string which must be freed by the caller. 549*7c478bd9Sstevel@tonic-gate */ 550*7c478bd9Sstevel@tonic-gate static char * 551*7c478bd9Sstevel@tonic-gate extract_string(pargs_data_t *datap, uintptr_t addr) 552*7c478bd9Sstevel@tonic-gate { 553*7c478bd9Sstevel@tonic-gate int size = EXTRACT_BUFSZ; 554*7c478bd9Sstevel@tonic-gate char *result; 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate result = safe_zalloc(size); 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate for (;;) { 559*7c478bd9Sstevel@tonic-gate if (Pread_string(datap->pd_proc, result, size, addr) < 0) { 560*7c478bd9Sstevel@tonic-gate free(result); 561*7c478bd9Sstevel@tonic-gate return (NULL); 562*7c478bd9Sstevel@tonic-gate } else if (strlen(result) == (size - 1)) { 563*7c478bd9Sstevel@tonic-gate free(result); 564*7c478bd9Sstevel@tonic-gate size *= 2; 565*7c478bd9Sstevel@tonic-gate result = safe_zalloc(size); 566*7c478bd9Sstevel@tonic-gate } else { 567*7c478bd9Sstevel@tonic-gate break; 568*7c478bd9Sstevel@tonic-gate } 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate return (result); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate /* 574*7c478bd9Sstevel@tonic-gate * Utility function to read an array of pointers from the victim, adjusting 575*7c478bd9Sstevel@tonic-gate * for victim data model; returns the number of bytes successfully read. 576*7c478bd9Sstevel@tonic-gate */ 577*7c478bd9Sstevel@tonic-gate static ssize_t 578*7c478bd9Sstevel@tonic-gate read_ptr_array(pargs_data_t *datap, uintptr_t offset, uintptr_t *buf, 579*7c478bd9Sstevel@tonic-gate size_t nelems) 580*7c478bd9Sstevel@tonic-gate { 581*7c478bd9Sstevel@tonic-gate ssize_t res; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate if (dmodel == PR_MODEL_NATIVE) { 584*7c478bd9Sstevel@tonic-gate res = Pread(datap->pd_proc, buf, nelems * sizeof (uintptr_t), 585*7c478bd9Sstevel@tonic-gate offset); 586*7c478bd9Sstevel@tonic-gate } else { 587*7c478bd9Sstevel@tonic-gate int i; 588*7c478bd9Sstevel@tonic-gate uint32_t *arr32 = safe_zalloc(nelems * sizeof (uint32_t)); 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate res = Pread(datap->pd_proc, arr32, nelems * sizeof (uint32_t), 591*7c478bd9Sstevel@tonic-gate offset); 592*7c478bd9Sstevel@tonic-gate if (res > 0) { 593*7c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) 594*7c478bd9Sstevel@tonic-gate buf[i] = arr32[i]; 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate free(arr32); 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate return (res); 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate /* 602*7c478bd9Sstevel@tonic-gate * Extract the argv array from the victim; store the pointer values in 603*7c478bd9Sstevel@tonic-gate * datap->pd_argv and the extracted strings in datap->pd_argv_strs. 604*7c478bd9Sstevel@tonic-gate */ 605*7c478bd9Sstevel@tonic-gate static void 606*7c478bd9Sstevel@tonic-gate get_args(pargs_data_t *datap) 607*7c478bd9Sstevel@tonic-gate { 608*7c478bd9Sstevel@tonic-gate size_t argc = datap->pd_psinfo->pr_argc; 609*7c478bd9Sstevel@tonic-gate uintptr_t argvoff = datap->pd_psinfo->pr_argv; 610*7c478bd9Sstevel@tonic-gate int i; 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate datap->pd_argc = argc; 613*7c478bd9Sstevel@tonic-gate datap->pd_argv = safe_zalloc(argc * sizeof (uintptr_t)); 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate if (read_ptr_array(datap, argvoff, datap->pd_argv, argc) <= 0) { 616*7c478bd9Sstevel@tonic-gate free(datap->pd_argv); 617*7c478bd9Sstevel@tonic-gate datap->pd_argv = NULL; 618*7c478bd9Sstevel@tonic-gate return; 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate datap->pd_argv_strs = safe_zalloc(argc * sizeof (char *)); 622*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 623*7c478bd9Sstevel@tonic-gate if (datap->pd_argv[i] == 0) 624*7c478bd9Sstevel@tonic-gate continue; 625*7c478bd9Sstevel@tonic-gate datap->pd_argv_strs[i] = extract_string(datap, 626*7c478bd9Sstevel@tonic-gate datap->pd_argv[i]); 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate } 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 631*7c478bd9Sstevel@tonic-gate static int 632*7c478bd9Sstevel@tonic-gate build_env(void *data, struct ps_prochandle *pr, uintptr_t addr, const char *str) 633*7c478bd9Sstevel@tonic-gate { 634*7c478bd9Sstevel@tonic-gate pargs_data_t *datap = data; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate if (datap->pd_envp != NULL) { 637*7c478bd9Sstevel@tonic-gate datap->pd_envp[datap->pd_envc] = addr; 638*7c478bd9Sstevel@tonic-gate if (str == NULL) 639*7c478bd9Sstevel@tonic-gate datap->pd_envp_strs[datap->pd_envc] = NULL; 640*7c478bd9Sstevel@tonic-gate else 641*7c478bd9Sstevel@tonic-gate datap->pd_envp_strs[datap->pd_envc] = strdup(str); 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate datap->pd_envc++; 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate return (0); 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate static void 650*7c478bd9Sstevel@tonic-gate get_env(pargs_data_t *datap) 651*7c478bd9Sstevel@tonic-gate { 652*7c478bd9Sstevel@tonic-gate struct ps_prochandle *pr = datap->pd_proc; 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate datap->pd_envc = 0; 655*7c478bd9Sstevel@tonic-gate (void) Penv_iter(pr, build_env, datap); 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate datap->pd_envp = safe_zalloc(sizeof (uintptr_t) * datap->pd_envc); 658*7c478bd9Sstevel@tonic-gate datap->pd_envp_strs = safe_zalloc(sizeof (char *) * datap->pd_envc); 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate datap->pd_envc = 0; 661*7c478bd9Sstevel@tonic-gate (void) Penv_iter(pr, build_env, datap); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate /* 665*7c478bd9Sstevel@tonic-gate * The following at_* routines are used to decode data from the aux vector. 666*7c478bd9Sstevel@tonic-gate */ 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 669*7c478bd9Sstevel@tonic-gate static void 670*7c478bd9Sstevel@tonic-gate at_null(long val, char *instr, size_t n, char *str) 671*7c478bd9Sstevel@tonic-gate { 672*7c478bd9Sstevel@tonic-gate str[0] = '\0'; 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 676*7c478bd9Sstevel@tonic-gate static void 677*7c478bd9Sstevel@tonic-gate at_str(long val, char *instr, size_t n, char *str) 678*7c478bd9Sstevel@tonic-gate { 679*7c478bd9Sstevel@tonic-gate str[0] = '\0'; 680*7c478bd9Sstevel@tonic-gate if (instr != NULL) { 681*7c478bd9Sstevel@tonic-gate (void) strlcpy(str, instr, n); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* 686*7c478bd9Sstevel@tonic-gate * Note: Don't forget to add a corresponding case to isainfo(1). 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate #define FMT_AV(s, n, hwcap, mask, name) \ 690*7c478bd9Sstevel@tonic-gate if ((hwcap) & (mask)) \ 691*7c478bd9Sstevel@tonic-gate (void) snprintf(s, n, "%s" name " | ", s) 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 694*7c478bd9Sstevel@tonic-gate static void 695*7c478bd9Sstevel@tonic-gate at_hwcap(long val, char *instr, size_t n, char *str) 696*7c478bd9Sstevel@tonic-gate { 697*7c478bd9Sstevel@tonic-gate #if defined(__sparc) || defined(__sparcv9) 698*7c478bd9Sstevel@tonic-gate (void) hwcap_1_val2str(val, str, n, CAP_FMT_PIPSPACE, EM_SPARC); 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 701*7c478bd9Sstevel@tonic-gate (void) hwcap_1_val2str(val, str, n, CAP_FMT_PIPSPACE, EM_386); 702*7c478bd9Sstevel@tonic-gate #else 703*7c478bd9Sstevel@tonic-gate #error "port me" 704*7c478bd9Sstevel@tonic-gate #endif 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 708*7c478bd9Sstevel@tonic-gate static void 709*7c478bd9Sstevel@tonic-gate at_uid(long val, char *instr, size_t n, char *str) 710*7c478bd9Sstevel@tonic-gate { 711*7c478bd9Sstevel@tonic-gate struct passwd *pw = getpwuid((uid_t)val); 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate if ((pw == NULL) || (pw->pw_name == NULL)) 714*7c478bd9Sstevel@tonic-gate str[0] = '\0'; 715*7c478bd9Sstevel@tonic-gate else 716*7c478bd9Sstevel@tonic-gate (void) snprintf(str, n, "%lu(%s)", val, pw->pw_name); 717*7c478bd9Sstevel@tonic-gate } 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 721*7c478bd9Sstevel@tonic-gate static void 722*7c478bd9Sstevel@tonic-gate at_gid(long val, char *instr, size_t n, char *str) 723*7c478bd9Sstevel@tonic-gate { 724*7c478bd9Sstevel@tonic-gate struct group *gr = getgrgid((gid_t)val); 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate if ((gr == NULL) || (gr->gr_name == NULL)) 727*7c478bd9Sstevel@tonic-gate str[0] = '\0'; 728*7c478bd9Sstevel@tonic-gate else 729*7c478bd9Sstevel@tonic-gate (void) snprintf(str, n, "%lu(%s)", val, gr->gr_name); 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate static struct auxfl { 733*7c478bd9Sstevel@tonic-gate int af_flag; 734*7c478bd9Sstevel@tonic-gate const char *af_name; 735*7c478bd9Sstevel@tonic-gate } auxfl[] = { 736*7c478bd9Sstevel@tonic-gate { AF_SUN_SETUGID, "setugid" }, 737*7c478bd9Sstevel@tonic-gate }; 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 740*7c478bd9Sstevel@tonic-gate static void 741*7c478bd9Sstevel@tonic-gate at_flags(long val, char *instr, size_t n, char *str) 742*7c478bd9Sstevel@tonic-gate { 743*7c478bd9Sstevel@tonic-gate int i; 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate *str = '\0'; 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (auxfl)/sizeof (struct auxfl); i++) { 748*7c478bd9Sstevel@tonic-gate if ((val & auxfl[i].af_flag) != 0) { 749*7c478bd9Sstevel@tonic-gate if (*str != '\0') 750*7c478bd9Sstevel@tonic-gate (void) strlcat(str, ",", n); 751*7c478bd9Sstevel@tonic-gate (void) strlcat(str, auxfl[i].af_name, n); 752*7c478bd9Sstevel@tonic-gate } 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate #define MAX_AT_NAME_LEN 15 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate struct aux_id { 759*7c478bd9Sstevel@tonic-gate int aux_type; 760*7c478bd9Sstevel@tonic-gate const char *aux_name; 761*7c478bd9Sstevel@tonic-gate void (*aux_decode)(long, char *, size_t, char *); 762*7c478bd9Sstevel@tonic-gate }; 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate static struct aux_id aux_arr[] = { 765*7c478bd9Sstevel@tonic-gate { AT_NULL, "AT_NULL", at_null }, 766*7c478bd9Sstevel@tonic-gate { AT_IGNORE, "AT_IGNORE", at_null }, 767*7c478bd9Sstevel@tonic-gate { AT_EXECFD, "AT_EXECFD", at_null }, 768*7c478bd9Sstevel@tonic-gate { AT_PHDR, "AT_PHDR", at_null }, 769*7c478bd9Sstevel@tonic-gate { AT_PHENT, "AT_PHENT", at_null }, 770*7c478bd9Sstevel@tonic-gate { AT_PHNUM, "AT_PHNUM", at_null }, 771*7c478bd9Sstevel@tonic-gate { AT_PAGESZ, "AT_PAGESZ", at_null }, 772*7c478bd9Sstevel@tonic-gate { AT_BASE, "AT_BASE", at_null }, 773*7c478bd9Sstevel@tonic-gate { AT_FLAGS, "AT_FLAGS", at_null }, 774*7c478bd9Sstevel@tonic-gate { AT_ENTRY, "AT_ENTRY", at_null }, 775*7c478bd9Sstevel@tonic-gate { AT_SUN_UID, "AT_SUN_UID", at_uid }, 776*7c478bd9Sstevel@tonic-gate { AT_SUN_RUID, "AT_SUN_RUID", at_uid }, 777*7c478bd9Sstevel@tonic-gate { AT_SUN_GID, "AT_SUN_GID", at_gid }, 778*7c478bd9Sstevel@tonic-gate { AT_SUN_RGID, "AT_SUN_RGID", at_gid }, 779*7c478bd9Sstevel@tonic-gate { AT_SUN_LDELF, "AT_SUN_LDELF", at_null }, 780*7c478bd9Sstevel@tonic-gate { AT_SUN_LDSHDR, "AT_SUN_LDSHDR", at_null }, 781*7c478bd9Sstevel@tonic-gate { AT_SUN_LDNAME, "AT_SUN_LDNAME", at_null }, 782*7c478bd9Sstevel@tonic-gate { AT_SUN_LPAGESZ, "AT_SUN_LPAGESZ", at_null }, 783*7c478bd9Sstevel@tonic-gate { AT_SUN_PLATFORM, "AT_SUN_PLATFORM", at_str }, 784*7c478bd9Sstevel@tonic-gate { AT_SUN_EXECNAME, "AT_SUN_EXECNAME", at_str }, 785*7c478bd9Sstevel@tonic-gate { AT_SUN_HWCAP, "AT_SUN_HWCAP", at_hwcap }, 786*7c478bd9Sstevel@tonic-gate { AT_SUN_IFLUSH, "AT_SUN_IFLUSH", at_null }, 787*7c478bd9Sstevel@tonic-gate { AT_SUN_CPU, "AT_SUN_CPU", at_null }, 788*7c478bd9Sstevel@tonic-gate { AT_SUN_MMU, "AT_SUN_MMU", at_null }, 789*7c478bd9Sstevel@tonic-gate { AT_SUN_LDDATA, "AT_SUN_LDDATA", at_null }, 790*7c478bd9Sstevel@tonic-gate { AT_SUN_AUXFLAGS, "AT_SUN_AUXFLAGS", at_flags }, 791*7c478bd9Sstevel@tonic-gate }; 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate #define N_AT_ENTS (sizeof (aux_arr) / sizeof (struct aux_id)) 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate /* 796*7c478bd9Sstevel@tonic-gate * Return the aux_id entry for the given aux type; returns NULL if not found. 797*7c478bd9Sstevel@tonic-gate */ 798*7c478bd9Sstevel@tonic-gate static struct aux_id * 799*7c478bd9Sstevel@tonic-gate aux_find(int type) 800*7c478bd9Sstevel@tonic-gate { 801*7c478bd9Sstevel@tonic-gate int i; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate for (i = 0; i < N_AT_ENTS; i++) { 804*7c478bd9Sstevel@tonic-gate if (type == aux_arr[i].aux_type) 805*7c478bd9Sstevel@tonic-gate return (&aux_arr[i]); 806*7c478bd9Sstevel@tonic-gate } 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate return (NULL); 809*7c478bd9Sstevel@tonic-gate } 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate static void 812*7c478bd9Sstevel@tonic-gate get_auxv(pargs_data_t *datap) 813*7c478bd9Sstevel@tonic-gate { 814*7c478bd9Sstevel@tonic-gate int i; 815*7c478bd9Sstevel@tonic-gate const auxv_t *auxvp; 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* 818*7c478bd9Sstevel@tonic-gate * Fetch the aux vector from the target process. 819*7c478bd9Sstevel@tonic-gate */ 820*7c478bd9Sstevel@tonic-gate if (ps_pauxv(datap->pd_proc, &auxvp) != PS_OK) 821*7c478bd9Sstevel@tonic-gate return; 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate for (i = 0; auxvp[i].a_type != AT_NULL; i++) 824*7c478bd9Sstevel@tonic-gate continue; 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate datap->pd_auxc = i; 827*7c478bd9Sstevel@tonic-gate datap->pd_auxv = safe_zalloc(i * sizeof (auxv_t)); 828*7c478bd9Sstevel@tonic-gate bcopy(auxvp, datap->pd_auxv, i * sizeof (auxv_t)); 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate datap->pd_auxv_strs = safe_zalloc(datap->pd_auxc * sizeof (char *)); 831*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_auxc; i++) { 832*7c478bd9Sstevel@tonic-gate struct aux_id *aux = aux_find(datap->pd_auxv[i].a_type); 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate /* 835*7c478bd9Sstevel@tonic-gate * Grab strings for those entries which have a string-decoder. 836*7c478bd9Sstevel@tonic-gate */ 837*7c478bd9Sstevel@tonic-gate if ((aux != NULL) && (aux->aux_decode == at_str)) { 838*7c478bd9Sstevel@tonic-gate datap->pd_auxv_strs[i] = 839*7c478bd9Sstevel@tonic-gate extract_string(datap, datap->pd_auxv[i].a_un.a_val); 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate } 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate /* 845*7c478bd9Sstevel@tonic-gate * Prepare to convert characters in the victim's character set into user's 846*7c478bd9Sstevel@tonic-gate * character set. 847*7c478bd9Sstevel@tonic-gate */ 848*7c478bd9Sstevel@tonic-gate static void 849*7c478bd9Sstevel@tonic-gate setup_conversions(pargs_data_t *datap, int *diflocale) 850*7c478bd9Sstevel@tonic-gate { 851*7c478bd9Sstevel@tonic-gate char *mylocale = NULL, *mycharset = NULL; 852*7c478bd9Sstevel@tonic-gate char *targetlocale = NULL, *targetcharset = NULL; 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate mycharset = safe_strdup(nl_langinfo(CODESET)); 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate mylocale = setlocale(LC_CTYPE, NULL); 857*7c478bd9Sstevel@tonic-gate if ((mylocale == NULL) || (strcmp(mylocale, "") == 0)) 858*7c478bd9Sstevel@tonic-gate mylocale = "C"; 859*7c478bd9Sstevel@tonic-gate mylocale = safe_strdup(mylocale); 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate if (datap->pd_conv_flags & CONV_STRICT_ASCII) 862*7c478bd9Sstevel@tonic-gate goto done; 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate /* 865*7c478bd9Sstevel@tonic-gate * If the target's locale is "C" or "POSIX", go fast. 866*7c478bd9Sstevel@tonic-gate */ 867*7c478bd9Sstevel@tonic-gate if ((strcmp(datap->pd_locale, "C") == 0) || 868*7c478bd9Sstevel@tonic-gate (strcmp(datap->pd_locale, "POSIX") == 0)) { 869*7c478bd9Sstevel@tonic-gate datap->pd_conv_flags |= CONV_STRICT_ASCII; 870*7c478bd9Sstevel@tonic-gate goto done; 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate /* 874*7c478bd9Sstevel@tonic-gate * Switch to the victim's locale, and discover its character set. 875*7c478bd9Sstevel@tonic-gate */ 876*7c478bd9Sstevel@tonic-gate if (setlocale(LC_ALL, datap->pd_locale) == NULL) { 877*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 878*7c478bd9Sstevel@tonic-gate "%s: Couldn't determine locale of target process.\n", 879*7c478bd9Sstevel@tonic-gate command); 880*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 881*7c478bd9Sstevel@tonic-gate "%s: Some strings may not be displayed properly.\n", 882*7c478bd9Sstevel@tonic-gate command); 883*7c478bd9Sstevel@tonic-gate goto done; 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate /* 887*7c478bd9Sstevel@tonic-gate * Get LC_CTYPE part of target's locale, and its codeset. 888*7c478bd9Sstevel@tonic-gate */ 889*7c478bd9Sstevel@tonic-gate targetlocale = safe_strdup(setlocale(LC_CTYPE, NULL)); 890*7c478bd9Sstevel@tonic-gate targetcharset = safe_strdup(nl_langinfo(CODESET)); 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate /* 893*7c478bd9Sstevel@tonic-gate * Now go fully back to the pargs user's locale. 894*7c478bd9Sstevel@tonic-gate */ 895*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate /* 898*7c478bd9Sstevel@tonic-gate * It's safe to bail here if the lc_ctype of the locales are the 899*7c478bd9Sstevel@tonic-gate * same-- we know that their encodings and characters sets are the same. 900*7c478bd9Sstevel@tonic-gate */ 901*7c478bd9Sstevel@tonic-gate if (strcmp(targetlocale, mylocale) == 0) 902*7c478bd9Sstevel@tonic-gate goto done; 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate *diflocale = 1; 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate /* 907*7c478bd9Sstevel@tonic-gate * If the codeset of the victim matches our codeset then iconv need 908*7c478bd9Sstevel@tonic-gate * not be involved. 909*7c478bd9Sstevel@tonic-gate */ 910*7c478bd9Sstevel@tonic-gate if (strcmp(mycharset, targetcharset) == 0) 911*7c478bd9Sstevel@tonic-gate goto done; 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate if ((datap->pd_iconv = iconv_open(mycharset, targetcharset)) 914*7c478bd9Sstevel@tonic-gate == (iconv_t)-1) { 915*7c478bd9Sstevel@tonic-gate /* 916*7c478bd9Sstevel@tonic-gate * EINVAL indicates there was no conversion available 917*7c478bd9Sstevel@tonic-gate * from victim charset to mycharset 918*7c478bd9Sstevel@tonic-gate */ 919*7c478bd9Sstevel@tonic-gate if (errno != EINVAL) { 920*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 921*7c478bd9Sstevel@tonic-gate "%s: failed to initialize iconv: %s\n", 922*7c478bd9Sstevel@tonic-gate command, strerror(errno)); 923*7c478bd9Sstevel@tonic-gate exit(1); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate datap->pd_conv_flags |= CONV_STRICT_ASCII; 926*7c478bd9Sstevel@tonic-gate } else { 927*7c478bd9Sstevel@tonic-gate datap->pd_conv_flags |= CONV_USE_ICONV; 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate done: 930*7c478bd9Sstevel@tonic-gate free(mycharset); 931*7c478bd9Sstevel@tonic-gate free(mylocale); 932*7c478bd9Sstevel@tonic-gate free(targetcharset); 933*7c478bd9Sstevel@tonic-gate free(targetlocale); 934*7c478bd9Sstevel@tonic-gate } 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate static void 937*7c478bd9Sstevel@tonic-gate cleanup_conversions(pargs_data_t *datap) 938*7c478bd9Sstevel@tonic-gate { 939*7c478bd9Sstevel@tonic-gate if (datap->pd_conv_flags & CONV_USE_ICONV) { 940*7c478bd9Sstevel@tonic-gate (void) iconv_close(datap->pd_iconv); 941*7c478bd9Sstevel@tonic-gate } 942*7c478bd9Sstevel@tonic-gate } 943*7c478bd9Sstevel@tonic-gate 944*7c478bd9Sstevel@tonic-gate static char * 945*7c478bd9Sstevel@tonic-gate convert_run_iconv(pargs_data_t *datap, const char *str) 946*7c478bd9Sstevel@tonic-gate { 947*7c478bd9Sstevel@tonic-gate size_t inleft, outleft, bufsz = 64; 948*7c478bd9Sstevel@tonic-gate char *outstr, *outstrptr; 949*7c478bd9Sstevel@tonic-gate const char *instrptr; 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate for (;;) { 952*7c478bd9Sstevel@tonic-gate outstrptr = outstr = safe_zalloc(bufsz + 1); 953*7c478bd9Sstevel@tonic-gate outleft = bufsz; 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate /* 956*7c478bd9Sstevel@tonic-gate * Generate the "initial shift state" sequence, placing that 957*7c478bd9Sstevel@tonic-gate * at the head of the string. 958*7c478bd9Sstevel@tonic-gate */ 959*7c478bd9Sstevel@tonic-gate inleft = 0; 960*7c478bd9Sstevel@tonic-gate (void) iconv(datap->pd_iconv, NULL, &inleft, 961*7c478bd9Sstevel@tonic-gate &outstrptr, &outleft); 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate inleft = strlen(str); 964*7c478bd9Sstevel@tonic-gate instrptr = str; 965*7c478bd9Sstevel@tonic-gate if (iconv(datap->pd_iconv, &instrptr, &inleft, &outstrptr, 966*7c478bd9Sstevel@tonic-gate &outleft) != (size_t)-1) { 967*7c478bd9Sstevel@tonic-gate /* 968*7c478bd9Sstevel@tonic-gate * Outstr must be null terminated upon exit from 969*7c478bd9Sstevel@tonic-gate * iconv(). 970*7c478bd9Sstevel@tonic-gate */ 971*7c478bd9Sstevel@tonic-gate *(outstr + (bufsz - outleft)) = '\0'; 972*7c478bd9Sstevel@tonic-gate break; 973*7c478bd9Sstevel@tonic-gate } else if (errno == E2BIG) { 974*7c478bd9Sstevel@tonic-gate bufsz *= 2; 975*7c478bd9Sstevel@tonic-gate free(outstr); 976*7c478bd9Sstevel@tonic-gate } else if ((errno == EILSEQ) || (errno == EINVAL)) { 977*7c478bd9Sstevel@tonic-gate free(outstr); 978*7c478bd9Sstevel@tonic-gate return (NULL); 979*7c478bd9Sstevel@tonic-gate } else { 980*7c478bd9Sstevel@tonic-gate /* 981*7c478bd9Sstevel@tonic-gate * iconv() could in theory return EBADF, but that 982*7c478bd9Sstevel@tonic-gate * shouldn't happen. 983*7c478bd9Sstevel@tonic-gate */ 984*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 985*7c478bd9Sstevel@tonic-gate "%s: iconv(3C) failed unexpectedly: %s\n", 986*7c478bd9Sstevel@tonic-gate command, strerror(errno)); 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate exit(1); 989*7c478bd9Sstevel@tonic-gate } 990*7c478bd9Sstevel@tonic-gate } 991*7c478bd9Sstevel@tonic-gate return (outstr); 992*7c478bd9Sstevel@tonic-gate } 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate /* 995*7c478bd9Sstevel@tonic-gate * Returns a freshly allocated string converted to the local character set, 996*7c478bd9Sstevel@tonic-gate * removed of unprintable characters. 997*7c478bd9Sstevel@tonic-gate */ 998*7c478bd9Sstevel@tonic-gate static char * 999*7c478bd9Sstevel@tonic-gate convert_str(pargs_data_t *datap, const char *str, int *unprintable) 1000*7c478bd9Sstevel@tonic-gate { 1001*7c478bd9Sstevel@tonic-gate char *retstr, *tmp; 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate if (datap->pd_conv_flags & CONV_STRICT_ASCII) { 1004*7c478bd9Sstevel@tonic-gate retstr = unctrl_str_strict_ascii(str, 1, unprintable); 1005*7c478bd9Sstevel@tonic-gate return (retstr); 1006*7c478bd9Sstevel@tonic-gate } 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate if ((datap->pd_conv_flags & CONV_USE_ICONV) == 0) { 1009*7c478bd9Sstevel@tonic-gate /* 1010*7c478bd9Sstevel@tonic-gate * If we aren't using iconv(), convert control chars in 1011*7c478bd9Sstevel@tonic-gate * the string in pargs' locale, since that is the display 1012*7c478bd9Sstevel@tonic-gate * locale. 1013*7c478bd9Sstevel@tonic-gate */ 1014*7c478bd9Sstevel@tonic-gate retstr = unctrl_str(str, 1, unprintable); 1015*7c478bd9Sstevel@tonic-gate return (retstr); 1016*7c478bd9Sstevel@tonic-gate } 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate /* 1019*7c478bd9Sstevel@tonic-gate * The logic here is a bit (ahem) tricky. Start by converting 1020*7c478bd9Sstevel@tonic-gate * unprintable characters *in the target's locale*. This should 1021*7c478bd9Sstevel@tonic-gate * eliminate a variety of unprintable or illegal characters-- in 1022*7c478bd9Sstevel@tonic-gate * short, it should leave us with something which iconv() won't 1023*7c478bd9Sstevel@tonic-gate * have trouble with. 1024*7c478bd9Sstevel@tonic-gate * 1025*7c478bd9Sstevel@tonic-gate * After allowing iconv to convert characters as needed, run unctrl 1026*7c478bd9Sstevel@tonic-gate * again in pargs' locale-- This time to make sure that any 1027*7c478bd9Sstevel@tonic-gate * characters which aren't printable according to the *current* 1028*7c478bd9Sstevel@tonic-gate * locale (independent of the current codeset) get taken care of. 1029*7c478bd9Sstevel@tonic-gate * Without this second stage, we might (for example) fail to 1030*7c478bd9Sstevel@tonic-gate * properly handle characters converted into the 646 character set 1031*7c478bd9Sstevel@tonic-gate * (which are 8-bits wide), but which must be displayed in the C 1032*7c478bd9Sstevel@tonic-gate * locale (which uses 646, but whose printable characters are a 1033*7c478bd9Sstevel@tonic-gate * subset of the 7-bit characters). 1034*7c478bd9Sstevel@tonic-gate * 1035*7c478bd9Sstevel@tonic-gate * Note that assuming the victim's locale using LC_ALL will be 1036*7c478bd9Sstevel@tonic-gate * problematic when pargs' messages are internationalized in the 1037*7c478bd9Sstevel@tonic-gate * future (and it calls textdomain(3C)). In this case, any 1038*7c478bd9Sstevel@tonic-gate * error message fprintf'd in unctrl_str() will be in the wrong 1039*7c478bd9Sstevel@tonic-gate * LC_MESSAGES class. We'll cross that bridge when we come to it. 1040*7c478bd9Sstevel@tonic-gate */ 1041*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, datap->pd_locale); 1042*7c478bd9Sstevel@tonic-gate retstr = unctrl_str(str, 1, unprintable); 1043*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate tmp = retstr; 1046*7c478bd9Sstevel@tonic-gate if ((retstr = convert_run_iconv(datap, retstr)) == NULL) { 1047*7c478bd9Sstevel@tonic-gate /* 1048*7c478bd9Sstevel@tonic-gate * In this (rare but real) case, the iconv() failed even 1049*7c478bd9Sstevel@tonic-gate * though we unctrl'd the string. Treat the original string 1050*7c478bd9Sstevel@tonic-gate * (str) as a C locale string and strip it that way. 1051*7c478bd9Sstevel@tonic-gate */ 1052*7c478bd9Sstevel@tonic-gate free(tmp); 1053*7c478bd9Sstevel@tonic-gate return (unctrl_str_strict_ascii(str, 0, unprintable)); 1054*7c478bd9Sstevel@tonic-gate } 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate free(tmp); 1057*7c478bd9Sstevel@tonic-gate tmp = retstr; 1058*7c478bd9Sstevel@tonic-gate /* 1059*7c478bd9Sstevel@tonic-gate * Run unctrl_str, but make sure not to escape \ characters, which 1060*7c478bd9Sstevel@tonic-gate * may have resulted from the first round of unctrl. 1061*7c478bd9Sstevel@tonic-gate */ 1062*7c478bd9Sstevel@tonic-gate retstr = unctrl_str(retstr, 0, unprintable); 1063*7c478bd9Sstevel@tonic-gate free(tmp); 1064*7c478bd9Sstevel@tonic-gate return (retstr); 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate static void 1069*7c478bd9Sstevel@tonic-gate convert_array(pargs_data_t *datap, char **arr, size_t count, int *unprintable) 1070*7c478bd9Sstevel@tonic-gate { 1071*7c478bd9Sstevel@tonic-gate int i; 1072*7c478bd9Sstevel@tonic-gate char *tmp; 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate if (arr == NULL) 1075*7c478bd9Sstevel@tonic-gate return; 1076*7c478bd9Sstevel@tonic-gate 1077*7c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) { 1078*7c478bd9Sstevel@tonic-gate if ((tmp = arr[i]) == NULL) 1079*7c478bd9Sstevel@tonic-gate continue; 1080*7c478bd9Sstevel@tonic-gate arr[i] = convert_str(datap, arr[i], unprintable); 1081*7c478bd9Sstevel@tonic-gate free(tmp); 1082*7c478bd9Sstevel@tonic-gate } 1083*7c478bd9Sstevel@tonic-gate } 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate /* 1086*7c478bd9Sstevel@tonic-gate * Free data allocated during the gathering phase. 1087*7c478bd9Sstevel@tonic-gate */ 1088*7c478bd9Sstevel@tonic-gate static void 1089*7c478bd9Sstevel@tonic-gate free_data(pargs_data_t *datap) 1090*7c478bd9Sstevel@tonic-gate { 1091*7c478bd9Sstevel@tonic-gate int i; 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate if (datap->pd_argv) { 1094*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_argc; i++) { 1095*7c478bd9Sstevel@tonic-gate if (datap->pd_argv_strs[i] != NULL) 1096*7c478bd9Sstevel@tonic-gate free(datap->pd_argv_strs[i]); 1097*7c478bd9Sstevel@tonic-gate } 1098*7c478bd9Sstevel@tonic-gate free(datap->pd_argv); 1099*7c478bd9Sstevel@tonic-gate free(datap->pd_argv_strs); 1100*7c478bd9Sstevel@tonic-gate } 1101*7c478bd9Sstevel@tonic-gate 1102*7c478bd9Sstevel@tonic-gate if (datap->pd_envp) { 1103*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_envc; i++) { 1104*7c478bd9Sstevel@tonic-gate if (datap->pd_envp_strs[i] != NULL) 1105*7c478bd9Sstevel@tonic-gate free(datap->pd_envp_strs[i]); 1106*7c478bd9Sstevel@tonic-gate } 1107*7c478bd9Sstevel@tonic-gate free(datap->pd_envp); 1108*7c478bd9Sstevel@tonic-gate free(datap->pd_envp_strs); 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate if (datap->pd_auxv) { 1112*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_auxc; i++) { 1113*7c478bd9Sstevel@tonic-gate if (datap->pd_auxv_strs[i] != NULL) 1114*7c478bd9Sstevel@tonic-gate free(datap->pd_auxv_strs[i]); 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate free(datap->pd_auxv); 1117*7c478bd9Sstevel@tonic-gate free(datap->pd_auxv_strs); 1118*7c478bd9Sstevel@tonic-gate } 1119*7c478bd9Sstevel@tonic-gate } 1120*7c478bd9Sstevel@tonic-gate 1121*7c478bd9Sstevel@tonic-gate static void 1122*7c478bd9Sstevel@tonic-gate print_args(pargs_data_t *datap) 1123*7c478bd9Sstevel@tonic-gate { 1124*7c478bd9Sstevel@tonic-gate int i; 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate if (datap->pd_argv == NULL) { 1127*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: failed to read argv[]\n", command); 1128*7c478bd9Sstevel@tonic-gate return; 1129*7c478bd9Sstevel@tonic-gate } 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_argc; i++) { 1132*7c478bd9Sstevel@tonic-gate (void) printf("argv[%d]: ", i); 1133*7c478bd9Sstevel@tonic-gate if (datap->pd_argv[i] == NULL) { 1134*7c478bd9Sstevel@tonic-gate (void) printf("<NULL>\n"); 1135*7c478bd9Sstevel@tonic-gate } else if (datap->pd_argv_strs[i] == NULL) { 1136*7c478bd9Sstevel@tonic-gate (void) printf("<0x%0*lx>\n", 1137*7c478bd9Sstevel@tonic-gate (dmodel == PR_MODEL_LP64)? 16 : 8, 1138*7c478bd9Sstevel@tonic-gate (long)datap->pd_argv[i]); 1139*7c478bd9Sstevel@tonic-gate } else { 1140*7c478bd9Sstevel@tonic-gate (void) printf("%s\n", datap->pd_argv_strs[i]); 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate static void 1146*7c478bd9Sstevel@tonic-gate print_env(pargs_data_t *datap) 1147*7c478bd9Sstevel@tonic-gate { 1148*7c478bd9Sstevel@tonic-gate int i; 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate if (datap->pd_envp == NULL) { 1151*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: failed to read envp[]\n", command); 1152*7c478bd9Sstevel@tonic-gate return; 1153*7c478bd9Sstevel@tonic-gate } 1154*7c478bd9Sstevel@tonic-gate 1155*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_envc; i++) { 1156*7c478bd9Sstevel@tonic-gate (void) printf("envp[%d]: ", i); 1157*7c478bd9Sstevel@tonic-gate if (datap->pd_envp[i] == 0) { 1158*7c478bd9Sstevel@tonic-gate break; 1159*7c478bd9Sstevel@tonic-gate } else if (datap->pd_envp_strs[i] == NULL) { 1160*7c478bd9Sstevel@tonic-gate (void) printf("<0x%0*lx>\n", 1161*7c478bd9Sstevel@tonic-gate (dmodel == PR_MODEL_LP64)? 16 : 8, 1162*7c478bd9Sstevel@tonic-gate (long)datap->pd_envp[i]); 1163*7c478bd9Sstevel@tonic-gate } else { 1164*7c478bd9Sstevel@tonic-gate (void) printf("%s\n", datap->pd_envp_strs[i]); 1165*7c478bd9Sstevel@tonic-gate } 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate 1169*7c478bd9Sstevel@tonic-gate static int 1170*7c478bd9Sstevel@tonic-gate print_cmdline(pargs_data_t *datap) 1171*7c478bd9Sstevel@tonic-gate { 1172*7c478bd9Sstevel@tonic-gate int i; 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate /* 1175*7c478bd9Sstevel@tonic-gate * Go through and check to see if we have valid data. If not, print 1176*7c478bd9Sstevel@tonic-gate * an error message and bail. 1177*7c478bd9Sstevel@tonic-gate */ 1178*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_argc; i++) { 1179*7c478bd9Sstevel@tonic-gate if (datap->pd_argv[i] == NULL || 1180*7c478bd9Sstevel@tonic-gate datap->pd_argv_strs[i] == NULL) { 1181*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: target has corrupted " 1182*7c478bd9Sstevel@tonic-gate "argument list\n", command); 1183*7c478bd9Sstevel@tonic-gate return (1); 1184*7c478bd9Sstevel@tonic-gate } 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate datap->pd_argv_strs[i] = 1187*7c478bd9Sstevel@tonic-gate quote_string(datap, datap->pd_argv_strs[i]); 1188*7c478bd9Sstevel@tonic-gate } 1189*7c478bd9Sstevel@tonic-gate 1190*7c478bd9Sstevel@tonic-gate if (datap->pd_execname == NULL) { 1191*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot determine name of " 1192*7c478bd9Sstevel@tonic-gate "executable\n", command); 1193*7c478bd9Sstevel@tonic-gate return (1); 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate (void) printf("%s ", datap->pd_execname); 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate for (i = 1; i < datap->pd_argc; i++) 1199*7c478bd9Sstevel@tonic-gate (void) printf("%s ", datap->pd_argv_strs[i]); 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 1202*7c478bd9Sstevel@tonic-gate 1203*7c478bd9Sstevel@tonic-gate return (0); 1204*7c478bd9Sstevel@tonic-gate } 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate static void 1207*7c478bd9Sstevel@tonic-gate print_auxv(pargs_data_t *datap) 1208*7c478bd9Sstevel@tonic-gate { 1209*7c478bd9Sstevel@tonic-gate int i; 1210*7c478bd9Sstevel@tonic-gate const auxv_t *pa; 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate /* 1213*7c478bd9Sstevel@tonic-gate * Print the names and values of all the aux vector entries. 1214*7c478bd9Sstevel@tonic-gate */ 1215*7c478bd9Sstevel@tonic-gate for (i = 0; i < datap->pd_auxc; i++) { 1216*7c478bd9Sstevel@tonic-gate char type[32]; 1217*7c478bd9Sstevel@tonic-gate char decode[PATH_MAX]; 1218*7c478bd9Sstevel@tonic-gate struct aux_id *aux; 1219*7c478bd9Sstevel@tonic-gate long v; 1220*7c478bd9Sstevel@tonic-gate pa = &datap->pd_auxv[i]; 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate aux = aux_find(pa->a_type); 1223*7c478bd9Sstevel@tonic-gate v = (long)pa->a_un.a_val; 1224*7c478bd9Sstevel@tonic-gate 1225*7c478bd9Sstevel@tonic-gate if (aux != NULL) { 1226*7c478bd9Sstevel@tonic-gate /* 1227*7c478bd9Sstevel@tonic-gate * Fetch aux vector type string and decoded 1228*7c478bd9Sstevel@tonic-gate * representation of the value. 1229*7c478bd9Sstevel@tonic-gate */ 1230*7c478bd9Sstevel@tonic-gate (void) strlcpy(type, aux->aux_name, sizeof (type)); 1231*7c478bd9Sstevel@tonic-gate aux->aux_decode(v, datap->pd_auxv_strs[i], 1232*7c478bd9Sstevel@tonic-gate sizeof (decode), decode); 1233*7c478bd9Sstevel@tonic-gate } else { 1234*7c478bd9Sstevel@tonic-gate (void) snprintf(type, sizeof (type), "%d", pa->a_type); 1235*7c478bd9Sstevel@tonic-gate decode[0] = '\0'; 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate (void) printf("%-*s 0x%0*lx %s\n", MAX_AT_NAME_LEN, type, 1239*7c478bd9Sstevel@tonic-gate (dmodel == PR_MODEL_LP64)? 16 : 8, v, decode); 1240*7c478bd9Sstevel@tonic-gate } 1241*7c478bd9Sstevel@tonic-gate } 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate int 1244*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 1245*7c478bd9Sstevel@tonic-gate { 1246*7c478bd9Sstevel@tonic-gate int aflag = 0, cflag = 0, eflag = 0, xflag = 0, lflag = 0; 1247*7c478bd9Sstevel@tonic-gate int errflg = 0, retc = 0; 1248*7c478bd9Sstevel@tonic-gate int opt; 1249*7c478bd9Sstevel@tonic-gate int error = 1; 1250*7c478bd9Sstevel@tonic-gate core_content_t content = 0; 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1253*7c478bd9Sstevel@tonic-gate 1254*7c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 1255*7c478bd9Sstevel@tonic-gate command++; 1256*7c478bd9Sstevel@tonic-gate else 1257*7c478bd9Sstevel@tonic-gate command = argv[0]; 1258*7c478bd9Sstevel@tonic-gate 1259*7c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "acelxF")) != EOF) { 1260*7c478bd9Sstevel@tonic-gate switch (opt) { 1261*7c478bd9Sstevel@tonic-gate case 'a': /* show process arguments */ 1262*7c478bd9Sstevel@tonic-gate content |= CC_CONTENT_STACK; 1263*7c478bd9Sstevel@tonic-gate aflag++; 1264*7c478bd9Sstevel@tonic-gate break; 1265*7c478bd9Sstevel@tonic-gate case 'c': /* force 7-bit ascii */ 1266*7c478bd9Sstevel@tonic-gate cflag++; 1267*7c478bd9Sstevel@tonic-gate break; 1268*7c478bd9Sstevel@tonic-gate case 'e': /* show environment variables */ 1269*7c478bd9Sstevel@tonic-gate content |= CC_CONTENT_STACK; 1270*7c478bd9Sstevel@tonic-gate eflag++; 1271*7c478bd9Sstevel@tonic-gate break; 1272*7c478bd9Sstevel@tonic-gate case 'l': 1273*7c478bd9Sstevel@tonic-gate lflag++; 1274*7c478bd9Sstevel@tonic-gate aflag++; /* -l implies -a */ 1275*7c478bd9Sstevel@tonic-gate break; 1276*7c478bd9Sstevel@tonic-gate case 'x': /* show aux vector entries */ 1277*7c478bd9Sstevel@tonic-gate xflag++; 1278*7c478bd9Sstevel@tonic-gate break; 1279*7c478bd9Sstevel@tonic-gate case 'F': 1280*7c478bd9Sstevel@tonic-gate /* 1281*7c478bd9Sstevel@tonic-gate * Since we open the process read-only, there is no need 1282*7c478bd9Sstevel@tonic-gate * for the -F flag. It's a documented flag, so we 1283*7c478bd9Sstevel@tonic-gate * consume it silently. 1284*7c478bd9Sstevel@tonic-gate */ 1285*7c478bd9Sstevel@tonic-gate break; 1286*7c478bd9Sstevel@tonic-gate default: 1287*7c478bd9Sstevel@tonic-gate errflg++; 1288*7c478bd9Sstevel@tonic-gate break; 1289*7c478bd9Sstevel@tonic-gate } 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate /* -a is the default if no options are specified */ 1293*7c478bd9Sstevel@tonic-gate if ((aflag + eflag + xflag + lflag) == 0) { 1294*7c478bd9Sstevel@tonic-gate aflag++; 1295*7c478bd9Sstevel@tonic-gate content |= CC_CONTENT_STACK; 1296*7c478bd9Sstevel@tonic-gate } 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate /* -l cannot be used with the -x or -e flags */ 1299*7c478bd9Sstevel@tonic-gate if (lflag && (xflag || eflag)) { 1300*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "-l is incompatible with -x and -e\n"); 1301*7c478bd9Sstevel@tonic-gate errflg++; 1302*7c478bd9Sstevel@tonic-gate } 1303*7c478bd9Sstevel@tonic-gate 1304*7c478bd9Sstevel@tonic-gate argc -= optind; 1305*7c478bd9Sstevel@tonic-gate argv += optind; 1306*7c478bd9Sstevel@tonic-gate 1307*7c478bd9Sstevel@tonic-gate if (errflg || argc <= 0) { 1308*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1309*7c478bd9Sstevel@tonic-gate "usage: %s [-acexF] { pid | core } ...\n" 1310*7c478bd9Sstevel@tonic-gate " (show process arguments and environment)\n" 1311*7c478bd9Sstevel@tonic-gate " -a: show process arguments (default)\n" 1312*7c478bd9Sstevel@tonic-gate " -c: interpret characters as 7-bit ascii regardless of " 1313*7c478bd9Sstevel@tonic-gate "locale\n" 1314*7c478bd9Sstevel@tonic-gate " -e: show environment variables\n" 1315*7c478bd9Sstevel@tonic-gate " -l: display arguments as command line\n" 1316*7c478bd9Sstevel@tonic-gate " -x: show aux vector entries\n" 1317*7c478bd9Sstevel@tonic-gate " -F: force grabbing of the target process\n", command); 1318*7c478bd9Sstevel@tonic-gate return (2); 1319*7c478bd9Sstevel@tonic-gate } 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate while (argc-- > 0) { 1322*7c478bd9Sstevel@tonic-gate char *arg; 1323*7c478bd9Sstevel@tonic-gate int gret, r; 1324*7c478bd9Sstevel@tonic-gate psinfo_t psinfo; 1325*7c478bd9Sstevel@tonic-gate char *psargs_conv; 1326*7c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr; 1327*7c478bd9Sstevel@tonic-gate pargs_data_t datap; 1328*7c478bd9Sstevel@tonic-gate char *info; 1329*7c478bd9Sstevel@tonic-gate size_t info_sz; 1330*7c478bd9Sstevel@tonic-gate int pstate; 1331*7c478bd9Sstevel@tonic-gate char execname[PATH_MAX]; 1332*7c478bd9Sstevel@tonic-gate int unprintable; 1333*7c478bd9Sstevel@tonic-gate int diflocale; 1334*7c478bd9Sstevel@tonic-gate 1335*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 1336*7c478bd9Sstevel@tonic-gate arg = *argv++; 1337*7c478bd9Sstevel@tonic-gate 1338*7c478bd9Sstevel@tonic-gate /* 1339*7c478bd9Sstevel@tonic-gate * Suppress extra blanks lines if we've encountered processes 1340*7c478bd9Sstevel@tonic-gate * which can't be opened. 1341*7c478bd9Sstevel@tonic-gate */ 1342*7c478bd9Sstevel@tonic-gate if (error == 0) { 1343*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 1344*7c478bd9Sstevel@tonic-gate } 1345*7c478bd9Sstevel@tonic-gate error = 0; 1346*7c478bd9Sstevel@tonic-gate 1347*7c478bd9Sstevel@tonic-gate /* 1348*7c478bd9Sstevel@tonic-gate * First grab just the psinfo information, in case this 1349*7c478bd9Sstevel@tonic-gate * process is a zombie (in which case proc_arg_grab() will 1350*7c478bd9Sstevel@tonic-gate * fail). If so, print a nice message and continue. 1351*7c478bd9Sstevel@tonic-gate */ 1352*7c478bd9Sstevel@tonic-gate if (proc_arg_psinfo(arg, PR_ARG_ANY, &psinfo, 1353*7c478bd9Sstevel@tonic-gate &gret) == -1) { 1354*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 1355*7c478bd9Sstevel@tonic-gate command, arg, Pgrab_error(gret)); 1356*7c478bd9Sstevel@tonic-gate retc++; 1357*7c478bd9Sstevel@tonic-gate error = 1; 1358*7c478bd9Sstevel@tonic-gate continue; 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate if (psinfo.pr_nlwp == 0) { 1362*7c478bd9Sstevel@tonic-gate (void) printf("%d: <defunct>\n", (int)psinfo.pr_pid); 1363*7c478bd9Sstevel@tonic-gate continue; 1364*7c478bd9Sstevel@tonic-gate } 1365*7c478bd9Sstevel@tonic-gate 1366*7c478bd9Sstevel@tonic-gate /* 1367*7c478bd9Sstevel@tonic-gate * If process is a "system" process (like pageout), just 1368*7c478bd9Sstevel@tonic-gate * print its psargs and continue on. 1369*7c478bd9Sstevel@tonic-gate */ 1370*7c478bd9Sstevel@tonic-gate if (psinfo.pr_size == 0 && psinfo.pr_rssize == 0) { 1371*7c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 1372*7c478bd9Sstevel@tonic-gate if (!lflag) 1373*7c478bd9Sstevel@tonic-gate (void) printf("%d: ", (int)psinfo.pr_pid); 1374*7c478bd9Sstevel@tonic-gate (void) printf("%s\n", psinfo.pr_psargs); 1375*7c478bd9Sstevel@tonic-gate continue; 1376*7c478bd9Sstevel@tonic-gate } 1377*7c478bd9Sstevel@tonic-gate 1378*7c478bd9Sstevel@tonic-gate /* 1379*7c478bd9Sstevel@tonic-gate * Open the process readonly, since we do not need to write to 1380*7c478bd9Sstevel@tonic-gate * the control file. 1381*7c478bd9Sstevel@tonic-gate */ 1382*7c478bd9Sstevel@tonic-gate if ((Pr = proc_arg_grab(arg, PR_ARG_ANY, PGRAB_RDONLY, 1383*7c478bd9Sstevel@tonic-gate &gret)) == NULL) { 1384*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 1385*7c478bd9Sstevel@tonic-gate command, arg, Pgrab_error(gret)); 1386*7c478bd9Sstevel@tonic-gate retc++; 1387*7c478bd9Sstevel@tonic-gate error = 1; 1388*7c478bd9Sstevel@tonic-gate continue; 1389*7c478bd9Sstevel@tonic-gate } 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate pstate = Pstate(Pr); 1392*7c478bd9Sstevel@tonic-gate 1393*7c478bd9Sstevel@tonic-gate if (pstate == PS_DEAD && 1394*7c478bd9Sstevel@tonic-gate (Pcontent(Pr) & content) != content) { 1395*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: core '%s' has " 1396*7c478bd9Sstevel@tonic-gate "insufficient content\n", command, arg); 1397*7c478bd9Sstevel@tonic-gate retc++; 1398*7c478bd9Sstevel@tonic-gate continue; 1399*7c478bd9Sstevel@tonic-gate } 1400*7c478bd9Sstevel@tonic-gate 1401*7c478bd9Sstevel@tonic-gate /* 1402*7c478bd9Sstevel@tonic-gate * If malloc() fails, we return here so that we can let go 1403*7c478bd9Sstevel@tonic-gate * of the victim, restore our locale, print a message, 1404*7c478bd9Sstevel@tonic-gate * then exit. 1405*7c478bd9Sstevel@tonic-gate */ 1406*7c478bd9Sstevel@tonic-gate if ((r = setjmp(env)) != 0) { 1407*7c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 1408*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1409*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: out of memory: %s\n", 1410*7c478bd9Sstevel@tonic-gate command, strerror(r)); 1411*7c478bd9Sstevel@tonic-gate return (1); 1412*7c478bd9Sstevel@tonic-gate } 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate dmodel = Pstatus(Pr)->pr_dmodel; 1415*7c478bd9Sstevel@tonic-gate bzero(&datap, sizeof (datap)); 1416*7c478bd9Sstevel@tonic-gate bcopy(Ppsinfo(Pr), &psinfo, sizeof (psinfo_t)); 1417*7c478bd9Sstevel@tonic-gate datap.pd_proc = Pr; 1418*7c478bd9Sstevel@tonic-gate datap.pd_psinfo = &psinfo; 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate if (cflag) 1421*7c478bd9Sstevel@tonic-gate datap.pd_conv_flags |= CONV_STRICT_ASCII; 1422*7c478bd9Sstevel@tonic-gate 1423*7c478bd9Sstevel@tonic-gate /* 1424*7c478bd9Sstevel@tonic-gate * Strip control characters, then record process summary in 1425*7c478bd9Sstevel@tonic-gate * a buffer, since we don't want to print anything out until 1426*7c478bd9Sstevel@tonic-gate * after we release the process. 1427*7c478bd9Sstevel@tonic-gate */ 1428*7c478bd9Sstevel@tonic-gate 1429*7c478bd9Sstevel@tonic-gate /* 1430*7c478bd9Sstevel@tonic-gate * The process is neither a system process nor defunct. 1431*7c478bd9Sstevel@tonic-gate * 1432*7c478bd9Sstevel@tonic-gate * Do printing and post-processing (like name lookups) after 1433*7c478bd9Sstevel@tonic-gate * gathering the raw data from the process and releasing it. 1434*7c478bd9Sstevel@tonic-gate * This way, we don't deadlock on (for example) name lookup 1435*7c478bd9Sstevel@tonic-gate * if we grabbed the nscd and do 'pargs -x'. 1436*7c478bd9Sstevel@tonic-gate * 1437*7c478bd9Sstevel@tonic-gate * We always fetch the environment of the target, so that we 1438*7c478bd9Sstevel@tonic-gate * can make an educated guess about its locale. 1439*7c478bd9Sstevel@tonic-gate */ 1440*7c478bd9Sstevel@tonic-gate get_env(&datap); 1441*7c478bd9Sstevel@tonic-gate if (aflag != 0) 1442*7c478bd9Sstevel@tonic-gate get_args(&datap); 1443*7c478bd9Sstevel@tonic-gate if (xflag != 0) 1444*7c478bd9Sstevel@tonic-gate get_auxv(&datap); 1445*7c478bd9Sstevel@tonic-gate 1446*7c478bd9Sstevel@tonic-gate /* 1447*7c478bd9Sstevel@tonic-gate * If malloc() fails after this poiint, we return here to 1448*7c478bd9Sstevel@tonic-gate * restore our locale and print a message. If we don't 1449*7c478bd9Sstevel@tonic-gate * reset this, we might erroneously try to Prelease a process 1450*7c478bd9Sstevel@tonic-gate * twice. 1451*7c478bd9Sstevel@tonic-gate */ 1452*7c478bd9Sstevel@tonic-gate if ((r = setjmp(env)) != 0) { 1453*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1454*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: out of memory: %s\n", 1455*7c478bd9Sstevel@tonic-gate command, strerror(r)); 1456*7c478bd9Sstevel@tonic-gate return (1); 1457*7c478bd9Sstevel@tonic-gate } 1458*7c478bd9Sstevel@tonic-gate 1459*7c478bd9Sstevel@tonic-gate /* 1460*7c478bd9Sstevel@tonic-gate * For the -l option, we need a proper name for this executable 1461*7c478bd9Sstevel@tonic-gate * before we release it. 1462*7c478bd9Sstevel@tonic-gate */ 1463*7c478bd9Sstevel@tonic-gate if (lflag) 1464*7c478bd9Sstevel@tonic-gate datap.pd_execname = Pexecname(Pr, execname, 1465*7c478bd9Sstevel@tonic-gate sizeof (execname)); 1466*7c478bd9Sstevel@tonic-gate 1467*7c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 1468*7c478bd9Sstevel@tonic-gate 1469*7c478bd9Sstevel@tonic-gate /* 1470*7c478bd9Sstevel@tonic-gate * Crawl through the environment to determine the locale of 1471*7c478bd9Sstevel@tonic-gate * the target. 1472*7c478bd9Sstevel@tonic-gate */ 1473*7c478bd9Sstevel@tonic-gate lookup_locale(&datap); 1474*7c478bd9Sstevel@tonic-gate diflocale = 0; 1475*7c478bd9Sstevel@tonic-gate setup_conversions(&datap, &diflocale); 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate if (lflag != 0) { 1478*7c478bd9Sstevel@tonic-gate unprintable = 0; 1479*7c478bd9Sstevel@tonic-gate convert_array(&datap, datap.pd_argv_strs, 1480*7c478bd9Sstevel@tonic-gate datap.pd_argc, &unprintable); 1481*7c478bd9Sstevel@tonic-gate if (diflocale) 1482*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: Warning, target " 1483*7c478bd9Sstevel@tonic-gate "locale differs from current locale\n", 1484*7c478bd9Sstevel@tonic-gate command); 1485*7c478bd9Sstevel@tonic-gate else if (unprintable) 1486*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: Warning, command " 1487*7c478bd9Sstevel@tonic-gate "line contains unprintable characters\n", 1488*7c478bd9Sstevel@tonic-gate command); 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate retc += print_cmdline(&datap); 1491*7c478bd9Sstevel@tonic-gate } else { 1492*7c478bd9Sstevel@tonic-gate psargs_conv = convert_str(&datap, psinfo.pr_psargs, 1493*7c478bd9Sstevel@tonic-gate &unprintable); 1494*7c478bd9Sstevel@tonic-gate info_sz = strlen(psargs_conv) + MAXPATHLEN + 32 + 1; 1495*7c478bd9Sstevel@tonic-gate info = malloc(info_sz); 1496*7c478bd9Sstevel@tonic-gate if (pstate == PS_DEAD) { 1497*7c478bd9Sstevel@tonic-gate (void) snprintf(info, info_sz, 1498*7c478bd9Sstevel@tonic-gate "core '%s' of %d:\t%s\n", 1499*7c478bd9Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psargs_conv); 1500*7c478bd9Sstevel@tonic-gate } else { 1501*7c478bd9Sstevel@tonic-gate (void) snprintf(info, info_sz, "%d:\t%s\n", 1502*7c478bd9Sstevel@tonic-gate (int)psinfo.pr_pid, psargs_conv); 1503*7c478bd9Sstevel@tonic-gate } 1504*7c478bd9Sstevel@tonic-gate (void) printf("%s", info); 1505*7c478bd9Sstevel@tonic-gate free(info); 1506*7c478bd9Sstevel@tonic-gate free(psargs_conv); 1507*7c478bd9Sstevel@tonic-gate 1508*7c478bd9Sstevel@tonic-gate if (aflag != 0) { 1509*7c478bd9Sstevel@tonic-gate convert_array(&datap, datap.pd_argv_strs, 1510*7c478bd9Sstevel@tonic-gate datap.pd_argc, &unprintable); 1511*7c478bd9Sstevel@tonic-gate print_args(&datap); 1512*7c478bd9Sstevel@tonic-gate if (eflag || xflag) 1513*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 1514*7c478bd9Sstevel@tonic-gate } 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate if (eflag != 0) { 1517*7c478bd9Sstevel@tonic-gate convert_array(&datap, datap.pd_envp_strs, 1518*7c478bd9Sstevel@tonic-gate datap.pd_envc, &unprintable); 1519*7c478bd9Sstevel@tonic-gate print_env(&datap); 1520*7c478bd9Sstevel@tonic-gate if (xflag) 1521*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 1522*7c478bd9Sstevel@tonic-gate } 1523*7c478bd9Sstevel@tonic-gate 1524*7c478bd9Sstevel@tonic-gate if (xflag != 0) { 1525*7c478bd9Sstevel@tonic-gate convert_array(&datap, datap.pd_auxv_strs, 1526*7c478bd9Sstevel@tonic-gate datap.pd_auxc, &unprintable); 1527*7c478bd9Sstevel@tonic-gate print_auxv(&datap); 1528*7c478bd9Sstevel@tonic-gate } 1529*7c478bd9Sstevel@tonic-gate } 1530*7c478bd9Sstevel@tonic-gate 1531*7c478bd9Sstevel@tonic-gate cleanup_conversions(&datap); 1532*7c478bd9Sstevel@tonic-gate free_data(&datap); 1533*7c478bd9Sstevel@tonic-gate } 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate return (retc != 0 ? 1 : 0); 1536*7c478bd9Sstevel@tonic-gate } 1537