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