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