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