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