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