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